# Table of Contents - [Activation | Vantage API Reference | Terra Docs](#activation-vantage-api-reference-terra-docs) - [Orders | Vantage API Reference | Terra Docs](#orders-vantage-api-reference-terra-docs) - [Products | Vantage API Reference | Terra Docs](#products-vantage-api-reference-terra-docs) - [Clients | Vantage API Reference | Terra Docs](#clients-vantage-api-reference-terra-docs) - [Results | Vantage API Reference | Terra Docs](#results-vantage-api-reference-terra-docs) - [What is Vantage API? | Vantage API Docs | Terra Docs](#what-is-vantage-api-vantage-api-docs-terra-docs) - [Account setup and API keys | Vantage API Docs | Terra Docs](#account-setup-and-api-keys-vantage-api-docs-terra-docs) - [What is Terra API? | Terra Docs](#what-is-terra-api-terra-docs) - [Webhooks | Vantage API Docs | Terra Docs](#webhooks-vantage-api-docs-terra-docs) - [Test Collection Methods | Vantage API Docs | Terra Docs](#test-collection-methods-vantage-api-docs-terra-docs) - [Acknowledging Results | Vantage API Docs | Terra Docs](#acknowledging-results-vantage-api-docs-terra-docs) - [Terra AI | AI | Terra Docs](#terra-ai-ai-terra-docs) - [Results | Vantage API Docs | Terra Docs](#results-vantage-api-docs-terra-docs) - [January Update 2026 | Changelog | Terra Docs](#january-update-2026-changelog-terra-docs) - [Ordering your first test | Vantage API Docs | Terra Docs](#ordering-your-first-test-vantage-api-docs-terra-docs) - [Working with Sandbox | Vantage API Docs | Terra Docs](#working-with-sandbox-vantage-api-docs-terra-docs) - [User authentication | Terra Docs](#user-authentication-terra-docs) - [Managing user health data | Terra Docs](#managing-user-health-data-terra-docs) - [Mobile-only sources | Terra Docs](#mobile-only-sources-terra-docs) - [Troubleshooting | Terra Docs](#troubleshooting-terra-docs) - [Event Types | API Reference | Terra Docs](#event-types-api-reference-terra-docs) - [Supported integrations | API Reference | Terra Docs](#supported-integrations-api-reference-terra-docs) - [Core Concepts | API Reference | Terra Docs](#core-concepts-api-reference-terra-docs) - [Mobile SDK | API Reference | Terra Docs](#mobile-sdk-api-reference-terra-docs) - [Mobile SDK | API Reference | Terra Docs](#mobile-sdk-api-reference-terra-docs) - [REST API Endpoints | API Reference | Terra Docs](#rest-api-endpoints-api-reference-terra-docs) - [Core concepts | API Reference | Terra Docs](#core-concepts-api-reference-terra-docs) - [Supported Integrations | API Reference | Terra Docs](#supported-integrations-api-reference-terra-docs) - [OpenAPI Spec | API Reference | Terra Docs](#openapi-spec-api-reference-terra-docs) - [Websocket Reference | API Reference | Terra Docs](#websocket-reference-api-reference-terra-docs) - [Supported Integrations | API Reference | Terra Docs](#supported-integrations-api-reference-terra-docs) - [Android (Kotlin) | API Reference | Terra Docs](#android-kotlin-api-reference-terra-docs) - [Samples | API Reference | Terra Docs](#samples-api-reference-terra-docs) - [Pricing | Terra Docs](#pricing-terra-docs) - [Core Concepts | API Reference | Terra Docs](#core-concepts-api-reference-terra-docs) - [Event types | API Reference | Terra Docs](#event-types-api-reference-terra-docs) - [Destinations | API Reference | Terra Docs](#destinations-api-reference-terra-docs) - [React Native | API Reference | Terra Docs](#react-native-api-reference-terra-docs) - [Flutter | API Reference | Terra Docs](#flutter-api-reference-terra-docs) - [Account setup and API keys | Terra Docs](#account-setup-and-api-keys-terra-docs) - [iOS (Swift) | API Reference | Terra Docs](#ios-swift-api-reference-terra-docs) - [Terra -> Your backend | Terra Docs](#terra-your-backend-terra-docs) - [Wearable -> Your app | Terra Docs](#wearable-your-app-terra-docs) - [Android (Kotlin) | API Reference | Terra Docs](#android-kotlin-api-reference-terra-docs) - [Flutter | API Reference | Terra Docs](#flutter-api-reference-terra-docs) - [iOS (Swift) | API Reference | Terra Docs](#ios-swift-api-reference-terra-docs) - [Core concepts | Terra Docs](#core-concepts-terra-docs) - [React Native | API Reference | Terra Docs](#react-native-api-reference-terra-docs) - [Overview | Terra Docs](#overview-terra-docs) - [Integration setup | Terra Docs](#integration-setup-terra-docs) - [Data models | API Reference | Terra Docs](#data-models-api-reference-terra-docs) - [Understanding sources and destinations | Terra Docs](#understanding-sources-and-destinations-terra-docs) - [Overview | Terra Docs](#overview-terra-docs) - [Health Rewards | Terra Docs](#health-rewards-terra-docs) - [Your app -> Terra | Terra Docs](#your-app-terra-terra-docs) - [Health Scores | Terra Docs](#health-scores-terra-docs) - [Understanding Terra environments | Terra Docs](#understanding-terra-environments-terra-docs) - [Authentication flow | Terra Docs](#authentication-flow-terra-docs) - [Customising authentication redirects | Terra Docs](#customising-authentication-redirects-terra-docs) - [Customising data types | Terra Docs](#customising-data-types-terra-docs) - [Handling authentication events | Terra Docs](#handling-authentication-events-terra-docs) - [iOS (Swift) | Terra Docs](#ios-swift-terra-docs) - [Setting up data destinations | Terra Docs](#setting-up-data-destinations-terra-docs) - [Implementation (Terra widget) | Terra Docs](#implementation-terra-widget-terra-docs) - [Quickstart | Terra Docs](#quickstart-terra-docs) - [Supabase | Terra Docs](#supabase-terra-docs) - [SQL database (Postgres, MySQL) | Terra Docs](#sql-database-postgres-mysql-terra-docs) - [Implementation (Custom UI) | Terra Docs](#implementation-custom-ui-terra-docs) - [Android | Terra Docs](#android-terra-docs) - [Getting Started | Terra Docs](#getting-started-terra-docs) - [Queuing services (SQS, Kafka) | Terra Docs](#queuing-services-sqs-kafka-terra-docs) - [Cloud storage (S3, GCP) | Terra Docs](#cloud-storage-s3-gcp-terra-docs) - [Dedicated data source API keys | Terra Docs](#dedicated-data-source-api-keys-terra-docs) - [Requesting historical health data (REST API requests) | Terra Docs](#requesting-historical-health-data-rest-api-requests-terra-docs) - [Receiving health data updates (events) | Terra Docs](#receiving-health-data-updates-events-terra-docs) - [Android | Terra Docs](#android-terra-docs) - [API Endpoints | API Reference | Terra Docs](#api-endpoints-api-reference-terra-docs) --- # Activation | Vantage API Reference | Terra Docs ### [hashtag](https://docs.tryterra.co/vantage-api-reference#get-activate) Serve kit activation page get https://vantage.tryterra.co/activate Returns an HTML page for end users to activate their test kit and provide test-taker information Query parameters kit\_idstringRequired Supplier Kit ID from test kit packaging Responses chevron-right 200 HTML activation form text/html Responsestring chevron-right 400 Invalid kit ID text/html chevron-right 500 Internal server error text/html get /activate HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 HTML activation form chevron-down ### [hashtag](https://docs.tryterra.co/vantage-api-reference#post-activate-kit) Activate a test kit post https://vantage.tryterra.co/activate/kit Registers test-taker details with the supplier and updates order item status. This endpoint is called after the test-taker receives their kit and provides their information. Body application/jsonchevron-down application/json Information provided by test-taker when activating their kit addressobjectRequired Current address of the test-taker (may differ from shipping address) Show propertiesplus collection\_datestringOptionalExample: `2025-11-15T09:00:00Z` recipientobjectOptional Test-taker personal information (may differ from original recipient) Show propertiesplus supplier\_kit\_idstringOptionalExample: `KIT123456789` Responses chevron-right 200 Kit activated successfully application/json Responseobject Confirmation that kit was activated successfully Show propertiesplus chevron-right 400 Invalid request body or kit already activated application/json chevron-right 404 Kit not found application/json chevron-right 409 Kit already activated application/json chevron-right 500 Internal server error application/json chevron-right 503 Supplier service unavailable application/json post /activate/kit HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Kit activated successfully chevron-down [NextClientschevron-right](https://docs.tryterra.co/vantage-api-reference/core-resources/clients) Last updated 1 month ago Was this helpful? * [GETServe kit activation page](https://docs.tryterra.co/vantage-api-reference#get-activate) * [POSTActivate a test kit](https://docs.tryterra.co/vantage-api-reference#post-activate-kit) Was this helpful? sun-brightdesktopmoon Copy GET /activate?kit_id=text HTTP/1.1 Host: vantage.tryterra.co Accept: */* Copy text Copy POST /activate/kit HTTP/1.1 Host: vantage.tryterra.co Content-Type: application/json Accept: */* Content-Length: 440 { "address": { "address_line_1": "456 Oxford Street", "address_line_2": "Apt 7C", "administrative_area": "Greater Manchester", "city": "Manchester", "country_code": "GB", "postal_code": "M1 5GD" }, "collection_date": "2025-11-15T09:00:00Z", "recipient": { "country_code": 44, "date_of_birth": "1985-03-20", "email": "[email protected]", "first_name": "John", "gender_at_birth": "m", "last_name": "Smith", "phone_number": 447700900456 }, "supplier_kit_id": "KIT123456789" } Copy { "kit_id": "KIT123456789", "message": "Kit activated successfully", "success": true } sun-brightdesktopmoon --- # Orders | Vantage API Reference | Terra Docs ### [hashtag](https://docs.tryterra.co/vantage-api-reference/core-resources/orders#post-orders) Create a new order post https://vantage.tryterra.co/orders Create a new blood, DNA, or device test order Body application/jsonchevron-down application/json Request body for creating a new diagnostic test order client\_order\_reference\_idstring · min: 1 · max: 100Required Your unique order identifier that you generate (for idempotency and tracking) Example: `ORDER-2024-001` collection\_typestringRequired itemsobject\[\] · min: 1Required Only need product\_variant\_id and quantity completely define what was ordered Show propertiesplus recipientall ofRequired Details of the person who ordered. Depending on the supplier recipient is not necessarily the test-taker. Although some suppliers enforce this constraint on us. Show propertiesplus requested\_lab\_addressobjectOptional Physical address for shipping test kits Show propertiesplus shipping\_addressobjectOptional Physical address for shipping test kits Show propertiesplus Responses chevron-right 201 Order created successfully application/json chevron-right 400 Bad request - invalid JSON or validation errors application/json chevron-right 500 Internal server error application/json post /orders HTTPchevron-down HTTPcURLJavaScriptPython Test it 201 Order created successfully chevron-down ### [hashtag](https://docs.tryterra.co/vantage-api-reference/core-resources/orders#get-orders-orderid) Get order by order ID get https://vantage.tryterra.co/orders/{orderID} Returns complete order details including items, recipient, and status Authorizations BasicAuthchevron-down BasicAuth AuthorizationstringRequired Path parameters orderIDinteger · min: 1Required Order ID Responses chevron-right 200 Successfully retrieved order application/json Responseobject Full order information including items, recipient, address, and financials Show propertiesplus chevron-right 400 Invalid order ID format application/json chevron-right 401 Unauthorized - invalid credentials application/json chevron-right 404 Order not found application/json chevron-right 500 Internal server error application/json get /orders/{orderID} HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Successfully retrieved order chevron-down [PreviousClientschevron-left](https://docs.tryterra.co/vantage-api-reference/core-resources/clients) [NextProductschevron-right](https://docs.tryterra.co/vantage-api-reference/core-resources/products) Last updated 1 month ago Was this helpful? * [POSTCreate a new order](https://docs.tryterra.co/vantage-api-reference/core-resources/orders#post-orders) * [GETGet order by order ID](https://docs.tryterra.co/vantage-api-reference/core-resources/orders#get-orders-orderid) Was this helpful? sun-brightdesktopmoon Copy POST /orders HTTP/1.1 Host: vantage.tryterra.co Content-Type: application/json Accept: */* Content-Length: 769 { "client_order_reference_id": "ORDER-2024-001", "collection_type": "text", "items": [\ {\ "quantity": 1,\ "variant_id": "555666777"\ }\ ], "recipient": { "country_code": 44, "date_of_birth": "1990-05-15", "email": "[email protected]", "first_name": "Sarah", "gender_at_birth": "f", "id": "123456789", "last_name": "Johnson", "phone_number": 447700900123 }, "requested_lab_address": { "address_line_1": "123 Baker Street", "address_line_2": "Flat 4B", "administrative_area": "Greater London", "city": "London", "country_code": "GB", "id": 987654321, "is_validated": true, "postal_code": "NW1 6XE" }, "shipping_address": { "address_line_1": "123 Baker Street", "address_line_2": "Flat 4B", "administrative_area": "Greater London", "city": "London", "country_code": "GB", "id": 987654321, "is_validated": true, "postal_code": "NW1 6XE" } } Copy { "confirmed_lab_address": { "address_line_1": "123 Baker Street", "address_line_2": "Flat 4B", "administrative_area": "Greater London", "city": "London", "country_code": "GB", "id": 987654321, "is_validated": true, "postal_code": "NW1 6XE" }, "estimated_delivery": "2025-11-20", "order_id": "123456789", "order_items": [\ {\ "currency": 840,\ "item_status": 2,\ "lab_tracking_number": "LAB987654321",\ "order_id": "123456789",\ "order_item_id": "987654321",\ "price_per_item_cents": 9990,\ "product_type_id": "1",\ "quantity": 1,\ "results_status": "awaiting_sample",\ "variant_id": "555666777"\ }\ ], "order_status": "pending_shipment", "recipient_id": "987654321", "tracking_number": "TRK123456789GB" } Copy GET /orders/{orderID} HTTP/1.1 Host: vantage.tryterra.co Authorization: Basic username:password Accept: */* Copy { "client_id": "terra_client_abc123", "client_order_reference_id": "ORDER-2024-001", "collection_type": "AT_HOME", "confirmed_lab_address": { "address_line_1": "123 Baker Street", "address_line_2": "Flat 4B", "administrative_area": "Greater London", "city": "London", "country_code": "GB", "id": 987654321, "is_validated": true, "postal_code": "NW1 6XE" }, "items": [\ {\ "currency": 840,\ "item_status": 2,\ "lab_tracking_number": "LAB987654321",\ "order_id": "123456789",\ "order_item_id": "987654321",\ "price_per_item_cents": 9990,\ "product_type_id": "1",\ "quantity": 1,\ "results_status": "awaiting_sample",\ "variant_id": "555666777"\ }\ ], "order_financials": { "currency": 840, "discount_cents": 500, "total_cents": 10400 }, "order_id": "123456789", "order_status": "shipped", "recipient": { "country_code": 44, "date_of_birth": "1990-05-15", "email": "[email protected]", "first_name": "Sarah", "gender_at_birth": "f", "id": "123456789", "last_name": "Johnson", "phone_number": 447700900123 }, "requested_lab_address": { "address_line_1": "123 Baker Street", "address_line_2": "Flat 4B", "administrative_area": "Greater London", "city": "London", "country_code": "GB", "id": 987654321, "is_validated": true, "postal_code": "NW1 6XE" }, "shipping_address": { "address_line_1": "123 Baker Street", "address_line_2": "Flat 4B", "administrative_area": "Greater London", "city": "London", "country_code": "GB", "id": 987654321, "is_validated": true, "postal_code": "NW1 6XE" }, "supplier_id": "1" } sun-brightdesktopmoon --- # Products | Vantage API Reference | Terra Docs ### [hashtag](https://docs.tryterra.co/vantage-api-reference/core-resources/products#get-products) List all product types get https://vantage.tryterra.co/products Returns all available diagnostic test categories (e.g., Blood Tests, DNA Tests) Authorizations BasicAuthchevron-down BasicAuth AuthorizationstringRequired Responses chevron-right 200 Successfully retrieved product types application/json Responseobject\[\] Show propertiesplus chevron-right 401 Unauthorized - invalid credentials application/json chevron-right 500 Internal server error application/json get /products HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Successfully retrieved product types chevron-down ### [hashtag](https://docs.tryterra.co/vantage-api-reference/core-resources/products#get-products-id) Get products by type ID get https://vantage.tryterra.co/products/{id} Returns all products within a specific product type category Authorizations BasicAuthchevron-down BasicAuth AuthorizationstringRequired Path parameters idinteger · min: 1Required Product Type ID Responses chevron-right 200 Successfully retrieved products application/json Responseobject\[\] Show propertiesplus chevron-right 400 Invalid product type ID format application/json chevron-right 401 Unauthorized - invalid credentials application/json chevron-right 404 No product types were found application/json chevron-right 500 Internal server error application/json get /products/{id} HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Successfully retrieved products chevron-down ### [hashtag](https://docs.tryterra.co/vantage-api-reference/core-resources/products#get-products-id-variants) Get product variants by product ID get https://vantage.tryterra.co/products/{id}/variants Returns all available variants/options for a specific diagnostic test product (e.g., different panel sizes, customizations) Authorizations BasicAuthchevron-down BasicAuth AuthorizationstringRequired Path parameters idinteger · min: 1Required Product ID Responses chevron-right 200 Successfully retrieved variants application/json Responseobject\[\] Show propertiesplus chevron-right 400 Invalid product ID format application/json chevron-right 401 Unauthorized - invalid credentials application/json chevron-right 404 No product variants were found application/json chevron-right 500 Internal server error application/json get /products/{id}/variants HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Successfully retrieved variants chevron-down [PreviousOrderschevron-left](https://docs.tryterra.co/vantage-api-reference/core-resources/orders) [NextResultschevron-right](https://docs.tryterra.co/vantage-api-reference/core-resources/results) Last updated 1 month ago Was this helpful? * [GETList all product types](https://docs.tryterra.co/vantage-api-reference/core-resources/products#get-products) * [GETGet products by type ID](https://docs.tryterra.co/vantage-api-reference/core-resources/products#get-products-id) * [GETGet product variants by product ID](https://docs.tryterra.co/vantage-api-reference/core-resources/products#get-products-id-variants) Was this helpful? sun-brightdesktopmoon Copy GET /products HTTP/1.1 Host: vantage.tryterra.co Authorization: Basic username:password Accept: */* Copy [\ {\ "description": "text",\ "id": 1,\ "name": "text"\ }\ ] Copy GET /products/{id} HTTP/1.1 Host: vantage.tryterra.co Authorization: Basic username:password Accept: */* Copy [\ {\ "availability": 0,\ "basePriceCents": 1,\ "currency": 0,\ "description": "text",\ "id": 1,\ "images": [\ {\ "altText": "text",\ "displayOrder": 1,\ "height": 1,\ "id": 1,\ "productID": 1,\ "url": "text",\ "variantID": 1,\ "width": 1\ }\ ],\ "modelDescriptiveAttrs": {\ "ANY_ADDITIONAL_PROPERTY": "text"\ },\ "name": "text",\ "productTypeID": 1,\ "supplierID": 1,\ "variants": [\ {\ "availableCollectionTypes": [\ 1\ ],\ "currency": 1,\ "descriptiveAttrsOverride": {\ "ANY_ADDITIONAL_PROPERTY": "anything"\ },\ "id": 1,\ "images": [\ {\ "altText": "text",\ "displayOrder": 1,\ "height": 1,\ "id": 1,\ "productID": 1,\ "url": "text",\ "variantID": 1,\ "width": 1\ }\ ],\ "priceCents": 1,\ "productExternalSKU": "text",\ "productID": 1,\ "productTypeID": 1,\ "supplierID": 1,\ "variantAvailability": 1,\ "variantDefiningAttrs": {\ "ANY_ADDITIONAL_PROPERTY": "anything"\ },\ "variantName": "text"\ }\ ]\ }\ ] Copy GET /products/{id}/variants HTTP/1.1 Host: vantage.tryterra.co Authorization: Basic username:password Accept: */* Copy [\ {\ "availableCollectionTypes": [\ 1\ ],\ "currency": 1,\ "descriptiveAttrsOverride": {\ "ANY_ADDITIONAL_PROPERTY": "anything"\ },\ "id": 1,\ "images": [\ {\ "altText": "text",\ "displayOrder": 1,\ "height": 1,\ "id": 1,\ "productID": 1,\ "url": "text",\ "variantID": 1,\ "width": 1\ }\ ],\ "priceCents": 1,\ "productExternalSKU": "text",\ "productID": 1,\ "productTypeID": 1,\ "supplierID": 1,\ "variantAvailability": 1,\ "variantDefiningAttrs": {\ "ANY_ADDITIONAL_PROPERTY": "anything"\ },\ "variantName": "text"\ }\ ] sun-brightdesktopmoon --- # Clients | Vantage API Reference | Terra Docs ### [hashtag](https://docs.tryterra.co/vantage-api-reference/core-resources/clients#patch-clients-webhook-url) Update webhook URL patch https://vantage.tryterra.co/clients/webhook-url Update or clear the webhook URL for the authenticated client. The webhook URL must use HTTPS if provided, or can be empty to clear it. Note this means webhooks will no longer be sent to your previous endpoint Authorizations BasicAuthchevron-down BasicAuth AuthorizationstringRequired Body application/jsonchevron-down application/json webhook\_urlstringOptionalExample: `https://your-domain.com/webhooks/terra` Responses chevron-right 200 Webhook URL updated successfully application/json Responseobject Show propertiesplus chevron-right 400 Bad request - invalid URL format or validation error application/json chevron-right 401 Unauthorized - invalid client credentials application/json chevron-right 404 Client not found application/json chevron-right 500 Internal server error application/json patch /clients/webhook-url HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Webhook URL updated successfully chevron-down [PreviousActivationchevron-left](https://docs.tryterra.co/vantage-api-reference) [NextOrderschevron-right](https://docs.tryterra.co/vantage-api-reference/core-resources/orders) Last updated 1 month ago Was this helpful? Was this helpful? sun-brightdesktopmoon Copy PATCH /clients/webhook-url HTTP/1.1 Host: vantage.tryterra.co Authorization: Basic username:password Content-Type: application/json Accept: */* Content-Length: 56 { "webhook_url": "https://your-domain.com/webhooks/terra" } Copy { "client_id": "client_abc123", "customer_id": "cust_xyz789", "webhook_url": "https://your-domain.com/webhooks/terra" } sun-brightdesktopmoon --- # Results | Vantage API Reference | Terra Docs ### [hashtag](https://docs.tryterra.co/vantage-api-reference/core-resources/results#get-api-v1-results-orderitemid) Get presigned URL for test results get https://vantage.tryterra.co/api/v1/results/{orderItemID} Returns a time-limited presigned URL to download normalized test results in FHIR format (JSON). The URL is valid for 15 minutes. Note: Every orderItemID can only be associated with maximum 1 panel, hence results can be uniquely identified by orderItemID. Authorizations BasicAuthchevron-down BasicAuth AuthorizationstringRequired Path parameters orderItemIDinteger · min: 1Required Order Item ID Query parameters test\_taker\_idinteger · min: 1Required Test Taker ID Responses chevron-right 200 Successfully generated download URL application/json Responseobject Response containing a presigned URL to download test results Show propertiesplus chevron-right 400 Invalid or missing order item ID application/json chevron-right 401 Unauthorized - invalid client credentials application/json chevron-right 404 Results not found for this order item application/json chevron-right 500 Internal server error application/json get /api/v1/results/{orderItemID} HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Successfully generated download URL chevron-down ### [hashtag](https://docs.tryterra.co/vantage-api-reference/core-resources/results#post-results-orderitemid-acknowledge) Acknowledge results receipt post https://vantage.tryterra.co/results/{orderItemID}/acknowledge Confirms that test results have been successfully retrieved and processed by the test taker/end user. Required for compliance and audit trails. Authorizations BasicAuthchevron-down BasicAuth AuthorizationstringRequired Path parameters orderItemIDinteger · min: 1Required Order Item ID Query parameters test\_taker\_idinteger · min: 1Required Test Taker ID Responses chevron-right 200 Results acknowledged successfully application/json Responseobject Confirmation that results were acknowledged Show propertiesplus chevron-right 400 Invalid order item ID application/json chevron-right 401 Unauthorized - invalid credentials application/json chevron-right 404 Order item not found application/json chevron-right 500 Internal server error application/json post /results/{orderItemID}/acknowledge HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Results acknowledged successfully chevron-down [PreviousProductschevron-left](https://docs.tryterra.co/vantage-api-reference/core-resources/products) Last updated 1 month ago Was this helpful? * [GETGet presigned URL for test results](https://docs.tryterra.co/vantage-api-reference/core-resources/results#get-api-v1-results-orderitemid) * [POSTAcknowledge results receipt](https://docs.tryterra.co/vantage-api-reference/core-resources/results#post-results-orderitemid-acknowledge) Was this helpful? sun-brightdesktopmoon Copy GET /api/v1/results/{orderItemID}?test_taker_id=1 HTTP/1.1 Host: vantage.tryterra.co Authorization: Basic username:password Accept: */* Copy { "download_url": "https://storage.googleapis.com/bucket/results/123.json?signature=abc123", "expires_at": "2025-10-23T18:00:00Z", "format": "json" } Copy POST /results/{orderItemID}/acknowledge?test_taker_id=1 HTTP/1.1 Host: vantage.tryterra.co Authorization: Basic username:password Accept: */* Copy { "status": "acknowledged" } sun-brightdesktopmoon --- # What is Vantage API? | Vantage API Docs | Terra Docs The Terra **Vantage API** provides a comprehensive platform for managing blood test and DNA diagnostic products, processing orders, and delivering test results. This API enables healthcare providers, laboratories and partners to integrate diagnostic testing services directly into their applications! Vantage API allows you focus on providing the best healthcare experience for your end users while we handle the rest. ### [hashtag](https://docs.tryterra.co/vantage-api-docs#why-we-built-vantage-api) Why we built Vantage API The health tech space is currently at a turning point - with the commoditisation of highly accurate wearables, metrics like step counts, HRV and sleep scores are **readily available** to most end users. However, sensors alone **cannot provide truly actionable insights** without the most important factor - **biological context**. This is where **biomarker testing** comes in! The process of bringing biomarker testing to your users at a commercial scale is a complicated procedure, involving commercial agreements with third party labs, convoluted delivery and collection logistics and months of navigating compliance red tape required to provide a legally viable service. Instead, we provide a single API with **zero hoops to jump through**. Instead of endless complexity, Vantage API offers: * **Effortless integration** with numerous kit suppliers. * Bulk discounts without bulk minimum orders - we **pass on volume discounts** directly to your customers. * **No legal or compliance headaches** - start sending white-labelled panels within days instead of months. * Normalisation of test results into a **global format (FHIR)** for easy handling. * **Hands-off logistics networks** for fulfilment, shipping and result delivery. Essentially, Vantage API provides a **plug-and-play labs infrastructure** to bring the future of personalised health tech to your customers TODAY! ### [hashtag](https://docs.tryterra.co/vantage-api-docs#jump-right-in) Jump right in circle-info **🤖 Production Base URL:** Copy https://vantage.tryterra.co **🏝️ Sandbox Base URL:** Copy https://vantage-sandbox.tryterra.co ### [hashtag](https://docs.tryterra.co/vantage-api-docs#supported-countries) Supported Countries! * United Kingdom 🇬🇧 * USA 🇺🇸 ### [hashtag](https://docs.tryterra.co/vantage-api-docs#countries-coming-soon) Countries Coming Soon! * Germany 🇩🇪 * Spain 🇪🇸 * France 🇫🇷 If you are interested in getting involved as a client or supplier, please contact [\[email protected\]envelope](https://docs.tryterra.co/cdn-cgi/l/email-protection#c5b3a4aba0b6b6a485b1b7bcb1a0b7b7a4eba6aa) to find out more! [NextAccount setup and API keyschevron-right](https://docs.tryterra.co/vantage-api-docs/account-setup-and-api-keys) Last updated 1 month ago Was this helpful? * [Why we built Vantage API](https://docs.tryterra.co/vantage-api-docs#why-we-built-vantage-api) * [Jump right in](https://docs.tryterra.co/vantage-api-docs#jump-right-in) * [Supported Countries!](https://docs.tryterra.co/vantage-api-docs#supported-countries) * [Countries Coming Soon!](https://docs.tryterra.co/vantage-api-docs#countries-coming-soon) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Account setup and API keys | Vantage API Docs | Terra Docs **N.B** Your credentials will initially only work for sandbox environment. Production credentials will not be sent until later. ### [hashtag](https://docs.tryterra.co/vantage-api-docs/account-setup-and-api-keys#two-scenarios) Two Scenarios #### [hashtag](https://docs.tryterra.co/vantage-api-docs/account-setup-and-api-keys#id-1.-existing-terra-customer) 1\. Existing Terra Customer * Use existing testing credentials to configure webhook endpoint cURL Python Go Copy curl --location --request PATCH \ 'https://diagnostics-sandbox.tryterra.co/api/v1/clients/webhook-url' \ --header 'Content-Type: application/json' \ --header 'Authorization: Basic ' --data '{ "webhook_url": "https://your-domain.com/webhooks/terra" }' Copy import requests url = "https://diagnostics-sandbox.tryterra.co/api/v1/clients/webhook-url" headers = { 'Content-Type': 'application/json', 'Authorization': 'Basic ' } data = { "webhook_url": "https://your-domain.com/webhooks/terra" } response = requests.patch(url, headers=headers, json=data) print(response.text) print(response.status_code) * Start ordering! #### [hashtag](https://docs.tryterra.co/vantage-api-docs/account-setup-and-api-keys#id-2.-new-customer) 2\. New Customer * Contact [\[email protected\]envelope](https://docs.tryterra.co/cdn-cgi/l/email-protection#284b5d5a5c415b685c5a515c4d5a5a49064b47) * Provide necessary information (payment details etc.) * Provide endpoint to receive webhooks * Receive credentials * Start ordering!! [PreviousWhat is Vantage API?chevron-left](https://docs.tryterra.co/vantage-api-docs) [NextOrdering your first testchevron-right](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test) Last updated 1 month ago Was this helpful? Was this helpful? sun-brightdesktopmoon Copy package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { url := "https://diagnostics-sandbox.tryterra.co/api/v1/clients/webhook-url" payload := map[string]string{ "webhook_url": "https://your-domain.com/webhooks/terra", } jsonData, err := json.Marshal(payload) if err != nil { panic(err) } client := &http.Client{} req, err := http.NewRequest("PATCH", url, bytes.NewBuffer(jsonData)) if err != nil { panic(err) } req.Header.Add("Content-Type", "application/json") req.Header.Add("Authorization", "Basic ") res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { panic(err) } fmt.Println(string(body)) } sun-brightdesktopmoon --- # What is Terra API? | Terra Docs Terra is a **unified API for health and wearable data**. We make it simple for developers to connect their applications to a vast ecosystem of fitness trackers, smartwatches, and medical devices without building or maintaining individual integrations. [hashtag](https://docs.tryterra.co/#why-terra) Why Terra? -------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/#the-problem-we-solve) The problem we solve Accessing health data is complex. Each device and platform (like Garmin, Fitbit, Apple Health, Oura) has its own API and data formats. ### [hashtag](https://docs.tryterra.co/#our-solution) Our solution One unified API to access standardised data from hundreds of sources. We handle the complexity of: * Integrating with numerous providers. * Normalising diverse data formats. * Managing different authentication methods. Essentially, we handle the **infrastructure** so you can focus on **building the future of heath**. * * * [hashtag](https://docs.tryterra.co/#terra-api-products) Terra API products ------------------------------------------------------------------------------- Here's a brief overview to help you choose the right product for your needs. Each solution links to its dedicated documentation section for a deeper dive. ### [hashtag](https://docs.tryterra.co/#main-solution) Main solution The **Health & Fitness API** is Terra's **main product**. It integrate 500+ health data sources (including Oura, Garmin, Withings and other). It standardises access to varied data, such as activity, sleep, heart rate, readiness. [](https://docs.tryterra.co/health-and-fitness-api/getting-started) ![Cover](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FrMwsbthURoGdM5SjOhzj%252Fapi.jpg%3Falt%3Dmedia%26token%3Db1c9cee4-1d26-4052-87ea-0438ae9e6585&width=752&dpr=3&quality=100&sign=9bcb92bd&sv=2) **Health & Fitness API** **What it is:** Access rich current and historical user health data like activity, sleep, and workouts. **Use for:** Comprehensive wellness insights, user trend analysis. _Supports: Garmin, Fitbit, Oura, Apple Health, Google Fit, and 500+ more._ ### [hashtag](https://docs.tryterra.co/#additional-solutions) Additional Solutions You can also explore additional solutions. These includes RealTime Streaming of raw data (e.g. Steps, Heart Rate) from specific device models, or the Teams API which provides unified access to athlete monitoring platforms such as Vald and Catapult. [](https://docs.tryterra.co/streaming-api/getting-started) ![Cover](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FfPVZHmfkjp2U5164TADl%252FScreenshot%25202025-01-08%2520at%252015.17.14.png%3Falt%3Dmedia%26token%3D58a996e3-2c5a-41d7-8587-8b043f5104fa&width=752&dpr=3&quality=100&sign=f9a4f76f&sv=2) **Streaming API** **What it is:** Get live, real-time raw sensor data such as heart rate and distance from specific BLE & ANT+ devices to your websocket listener. **Used for:** Live workout feedback, real-time monitoring, interactive experiences _Supports: Apple Watch, BLE/ANT+ devices (e.g., heart rate monitors)._ [](https://docs.tryterra.co/teams-api/getting-started) ![Cover](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FRRkcSSPu9Rt157eXIx4W%252FScreenshot%25202025-01-08%2520at%252015.16.18.png%3Falt%3Dmedia%26token%3D1e79fc42-372a-478f-93b2-c84989c8743f&width=752&dpr=3&quality=100&sign=77a98c68&sv=2) **Teams API \[BETA\]** **What it is:** Aggregate and analyse data for groups or teams across across matches and individual athlete tests. **Used for:** Athlete performance tracking, team wellness dashboards. _Supports: Specialist athlete monitoring systems (e.g. Vald, Catapult, etc.)_ [hashtag](https://docs.tryterra.co/#ready-to-build-the-future) Ready to build the future? ---------------------------------------------------------------------------------------------- You've got the overview. Now, you can: * Proceed to [**Account setup & API keys**](https://docs.tryterra.co/introduction/account-setup-and-api-keys) to get your credentials. * We suggest you start with the **Health & Fitness API** and connecting one user. * We also recommend exploring our [**Core Concepts**](https://docs.tryterra.co/introduction/core-concepts) to understand how Terra works. [NextAccount setup and API keyschevron-right](https://docs.tryterra.co/introduction/account-setup-and-api-keys) Last updated 19 days ago Was this helpful? * [Why Terra?](https://docs.tryterra.co/#why-terra) * [The problem we solve](https://docs.tryterra.co/#the-problem-we-solve) * [Our solution](https://docs.tryterra.co/#our-solution) * [Terra API products](https://docs.tryterra.co/#terra-api-products) * [Main solution](https://docs.tryterra.co/#main-solution) * [Additional Solutions](https://docs.tryterra.co/#additional-solutions) * [Ready to build the future?](https://docs.tryterra.co/#ready-to-build-the-future) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Webhooks | Vantage API Docs | Terra Docs [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/webhooks#overview) Overview -------------------------------------------------------------------------------------------------- Webhooks are at the centre of how Vantage API is able to keep you connected to the kit throughout the fulfilment process. This guide will outline how we use webhooks and how you can integrate with them. ### [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/webhooks#webhook-verification) Webhook Verification * Diagnostics API uses **HMAC-SHA256** with your unique signing secret to generate webhook signatures * Below is some example code on how to verify a webhook secret Python Go Copy import hmac import hashlib import time from flask import Flask, request, abort app = Flask(__name__) SIGNING_SECRET = "your_signing_secret_here" TIMESTAMP_TOLERANCE = 300000 # 5 minutes in milliseconds def verify_webhook(request): # 1. Get signature header signature_header = request.headers.get('X-Terra-Signature') if not signature_header: return False, "Missing signature header" # 2. Parse signature header parts = dict(item.split('=') for item in signature_header.split(',')) try: timestamp = int(parts.get('t', 0)) received_signature = parts.get('v1', '') except (ValueError, AttributeError): return False, "Invalid signature format" # 3. Verify timestamp current_time = int(time.time() * 1000) age = current_time - timestamp if abs(age) > TIMESTAMP_TOLERANCE: return False, "Timestamp too old or in future" # 4. Get raw body body = request.get_data(as_text=True) # 5. Construct signed string signed_string = f"{timestamp}.{body}" # 6. Calculate expected signature expected_signature = hmac.new( SIGNING_SECRET.encode('utf-8'), signed_string.encode('utf-8'), hashlib.sha256 ).hexdigest() # 7. Compare signatures (constant-time) if not hmac.compare_digest(expected_signature, received_signature): return False, "Signature mismatch" return True, None @app.route('/webhooks/terra', methods=['POST']) def webhook_handler(): valid, error = verify_webhook(request) if not valid: abort(401, description=error) # Process webhook data = request.get_json() print(f"Received webhook: {data}") return '', 200 if __name__ == '__main__': app.run(port=3000) #### [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/webhooks#headers) Headers Every webhook Terra sends include these headers Header Description Example `X-Terra-Signature` HMAC signature with timestamp `t=1700000000000,v1=a1b2c3...` `X-Terra-Trace-Id` Unique request ID for debugging `251285377982321505` `Content-Type` Always `application/json` `application/json` #### [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/webhooks#signature-format) Signature Format The `X-Terra-Signature` header follows this format: * `t` = Unix timestamp in milliseconds when the webhook was sent * `v1` = HMAC-SHA256 signature in hexadecimal format **Example:** ### [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/webhooks#body) Body circle-exclamation `fulfilment.payment_processing` is not actually returned as a webhook but is part of the response once an order is placed Event Type Description Webhook Payload fulfilment.payment\_processing This is the default event returned once an order is placed. Not actually returned as an individual webhook. Look at hint above fulfilment.payment\_complete This event is sent once payment is confirmed fulfilment.delivery\_fulfilled This event is sent once delivery details such as tracking number is available results.kit\_activated The event is sent once an end user activates his/her kit. Only applies to suppliers which support 2-step activation process results.sample\_processing\_in\_lab This event is sent when test receipt is confirmed by the lab results.results\_ready This event is sent once result availability is confirmed by lab results.sample\_rejected This event is sent if the sample is rejected by the lab results.escalation\_raised This event is sent if there is an escalation in the result set [PreviousWorking with Sandboxchevron-left](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs) [NextTest Collection Methodschevron-right](https://docs.tryterra.co/vantage-api-docs/documentation/test-collection-methods) Last updated 1 month ago Was this helpful? * [Overview](https://docs.tryterra.co/vantage-api-docs/documentation/webhooks#overview) * [Webhook Verification](https://docs.tryterra.co/vantage-api-docs/documentation/webhooks#webhook-verification) * [Body](https://docs.tryterra.co/vantage-api-docs/documentation/webhooks#body) Was this helpful? sun-brightdesktopmoon Copy package main import ( "crypto/hmac" "crypto/sha256" "crypto/subtle" "encoding/hex" "fmt" "io" "net/http" "strconv" "strings" "time" ) func VerifyWebhook(r *http.Request, signingSecret string) (bool, error) { // 1. Read raw body bodyBytes, err := io.ReadAll(r.Body) if err != nil { return false, fmt.Errorf("failed to read body: %w", err) } defer r.Body.Close() // 2. Get signature header signatureHeader := r.Header.Get("X-Terra-Signature") if signatureHeader == "" { return false, fmt.Errorf("missing X-Terra-Signature header") } // 3. Parse signature header parts := strings.Split(signatureHeader, ",") if len(parts) != 2 { return false, fmt.Errorf("invalid signature format") } var timestamp int64 var receivedSig string for _, part := range parts { keyValue := strings.SplitN(part, "=", 2) if len(keyValue) != 2 { continue } switch keyValue[0] { case "t": timestamp, err = strconv.ParseInt(keyValue[1], 10, 64) if err != nil { return false, fmt.Errorf("invalid timestamp: %w", err) } case "v1": receivedSig = keyValue[1] } } // 4. Verify timestamp is recent (within 5 minutes) now := time.Now().UnixMilli() age := now - timestamp if age > 300000 || age < -300000 { return false, fmt.Errorf("timestamp too old or in future") } // 5. Construct signed string signedString := fmt.Sprintf("%d.%s", timestamp, string(bodyBytes)) // 6. Calculate expected signature mac := hmac.New(sha256.New, []byte(signingSecret)) mac.Write([]byte(signedString)) expectedSig := hex.EncodeToString(mac.Sum(nil)) // 7. Compare signatures (constant-time) if subtle.ConstantTimeCompare([]byte(expectedSig), []byte(receivedSig)) != 1 { return false, fmt.Errorf("signature mismatch") } return true, nil } // Example HTTP handler func WebhookHandler(w http.ResponseWriter, r *http.Request) { signingSecret := os.Getenv("TERRA_SIGNING_SECRET") valid, err := VerifyWebhook(r, signingSecret) if err != nil || !valid { http.Error(w, "Invalid signature", http.StatusUnauthorized) return } // Process webhook... w.WriteHeader(http.StatusOK) } Copy t=,v1= Copy X-Terra-Signature: t=1732115200000,v1=f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8 Copy { "data": { "order_id": 249956252111773696, "status": "fulfillment.payment_complete" }, "event_id": 249956266972192768, "event_type": "order.status_changed", "timestamp": 1763661418 } Copy { "data": { "order_id": 249956252111773696, "status": "fulfillment.delivery_fulfilled", "tracking_number": "KnD3d5PMZyq5ulNcWkrq" }, "event_id": 249956485092777984, "event_type": "order.status_changed", "timestamp": 1763661470 } Copy { "data": { "order_id": 249956252111773696, "order_item_id": 249956252111773699, "results_status": "results.kit_activated", "test_taker": { "test_taker_id": "257837964552478720", "country_code": 1, "email": "[email protected]", "first_name": "John", "last_name": "Doe", "phone_number": 4155551234 }, "variant_id": 100021 }, "event_id": 251744114461286400, "event_type": "order_item.results_status_change", "timestamp": 1764087674 } Copy { "data": { "order_id": 249956252111773696, "order_item_id": 249956252111773699, "results_status": "results.sample_processing_in_lab", "test_taker": { "test_taker_id": "257837964552478720", "email": "[email protected]", "first_name": "John", "last_name": "Doe", "country_code": 1, "phone_number": 4155551234 }, "variant_id": 100021 }, "event_id": 249958648347009024, "event_type": "order_item.results_status_change", "timestamp": 1763661985 } Copy { "data": { "order_id": 249956252111773696, "order_item_id": 249956252111773699, "results_status": "results.results_ready", "test_taker": { "test_taker_id": "257837964552478720", "country_code": 1, "email": "[email protected]", "first_name": "John", "last_name": "Doe", "phone_number": 4155551234 }, "variant_id": 100021 }, "event_id": 249958796259139584, "event_type": "order_item.results_status_change", "timestamp": 1763662021 } Copy { "data": { "failure_cause" : "blood contaminated", "order_id": 249956252111773696, "order_item_id": 249956252111773699, "results_status": "results.sample_rejected", "test_taker": { "test_taker_id": "257837964552478720", "country_code": 1, "email": "[email protected]", "first_name": "John", "last_name": "Doe", "phone_number": 4155551234 }, "variant_id": 100021 }, "event_id": 249958796259139584, "event_type": "order_item.results_status_change", "timestamp": 1763662021 } Copy { "data": { "escalation_level": "medium", "order_id": 249956252111773696, "order_item_id": 249956252111773699, "results_status": "results.escalation_raised", "test_taker": { "test_taker_id": "257837964552478720", "country_code": 44, "email": "[email protected]", "first_name": "John", "last_name": "Tan", "phone_number": 1234567890 }, "variant_id": 100011 }, "event_id": 252476147693166592, "event_type": "order_item.results_status_change", "timestamp": 1764262204 } sun-brightdesktopmoon --- # Test Collection Methods | Vantage API Docs | Terra Docs [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/test-collection-methods#overview) Overview ----------------------------------------------------------------------------------------------------------------- * Depending on the supplier and the product, some tests have multiple collection methods (ways for the end user to take a sample to be sent to the labs). * This document goes through examples of how to place orders for kits with different collection methods. * When looking at requests below, pay attention to `collection_type` and the following address fields * `shipping_address` * `requested_lab_address` * `confirmed_lab_address` Collection Method `AT_HOME` Kits are sent to the end-user's home. They are expected to follow instructions on how to take the test carefully. `GO_TO_LAB` A simplified name for mobile phlebotomy. The end-user goes to a specified lab where a registered nurse will conduct the test for them. ### [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/test-collection-methods#at_home-orders) AT\_HOME Orders Request Response Copy { "client_order_reference_id": "TEST-ORDER-001", "collection_type": "AT_HOME", "recipient": { "client_recipient_reference_id": "RECIP-CLIENT-001", "first_name": "John", "last_name": "Tan", "email": "[email protected]", "phone_number": 7436503302, "country_code": 44, "date_of_birth": "1995-10-10", "gender_at_birth": "m" }, "shipping_address": { "address_line_1": "123 High Street", "city": "London", "administrative_area": "England", "country_code": "GB", "postal_code": "SW1A 1AA" }, "items": [\ {\ "variant_id": 100011,\ "quantity": 1\ }\ ] } ### [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/test-collection-methods#go_to_lab-orders) GO\_TO\_LAB Orders * Using the `requested_lab_address` as a proxy, in the response we will route test takers to the closest lab available Request [PreviousWebhookschevron-left](https://docs.tryterra.co/vantage-api-docs/documentation/webhooks) [NextResultschevron-right](https://docs.tryterra.co/vantage-api-docs/documentation/results) Last updated 1 month ago Was this helpful? * [Overview](https://docs.tryterra.co/vantage-api-docs/documentation/test-collection-methods#overview) * [AT\_HOME Orders](https://docs.tryterra.co/vantage-api-docs/documentation/test-collection-methods#at_home-orders) * [GO\_TO\_LAB Orders](https://docs.tryterra.co/vantage-api-docs/documentation/test-collection-methods#go_to_lab-orders) Was this helpful? sun-brightdesktopmoon Copy { "order_id": 256488482397134848, "recipient_id": 256488482397134849, "order_items": [\ {\ "order_id": 256488482397134848,\ "order_item_id": 256488482397134851,\ "variant_id": 100011,\ "product_type_id": 1,\ "price_per_item_cents": 3999,\ "quantity": 1,\ "currency": 840,\ "results_status": "results.awaiting_sample"\ }\ ], "order_status": "order.payment_processing" } Copy { "client_order_reference_id": "TEST-ORDER-001", "collection_type": "GO_TO_LAB", "recipient": { "client_recipient_reference_id": "RECIP-CLIENT-001", "first_name": "John", "last_name": "Tan", "email": "[email protected]", "phone_number": 7436503302, "country_code": 44, "date_of_birth": "1995-10-10", "gender_at_birth": "m" }, "requested_lab_address": { "address_line_1": "123 High Street", "city": "London", "administrative_area": "England", "country_code": "GB", "postal_code": "SW1A 1AA" }, "items": [\ {\ "variant_id": 100011,\ "quantity": 1\ }\ ] } sun-brightdesktopmoon --- # Acknowledging Results | Vantage API Docs | Terra Docs [hashtag](https://docs.tryterra.co/vantage-api-docs/important-information/acknowledging-results#overview) Overview ----------------------------------------------------------------------------------------------------------------------- Acknowledging results is not optional—it is a fundamental requirement in the patient care workflow. This acknowledgment serves as documentation that clients have reviewed test outcomes and take responsibility for communicating appropriate severity levels to their end users. All results, whether indicating _**low**_ _to_ _**high**_ _**clinical escalation**_, must be explicitly acknowledged within the system before patients can access their results. This mandatory acknowledgment protects patients by ensuring they receive informed guidance about their test outcomes and any necessary next steps. triangle-exclamation Failure to acknowledge results initiates a chain of liability that transfers responsibility directly to you, and your organisation assumes full liability for any adverse outcomes resulting from delayed or unacknowledged results. circle-exclamation If results remain unacknowledged, test suppliers and medical teams are authorised to **reach out directly** to patients to ensure they receive critical health information. ### [hashtag](https://docs.tryterra.co/vantage-api-docs/important-information/acknowledging-results#example-acknowledgement-page) Example Acknowledgement Page * **N.B** Test taker cannot see results until acknowledging ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F2398619654-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FQnL9sbo31piU0slHHABv%252Fuploads%252FpsvPZjyn3qyMmc2eDYWT%252Fimage.png%3Falt%3Dmedia%26token%3D4230cf55-a8ff-44a6-8fd0-67138dd16a12&width=768&dpr=3&quality=100&sign=d13b2d2&sv=2) ### [hashtag](https://docs.tryterra.co/vantage-api-docs/important-information/acknowledging-results#acknowledgement-endpoint) Acknowledgement Endpoint cURL Python Go [PreviousResultschevron-left](https://docs.tryterra.co/vantage-api-docs/documentation/results) Last updated 1 month ago Was this helpful? * [Overview](https://docs.tryterra.co/vantage-api-docs/important-information/acknowledging-results#overview) * [Example Acknowledgement Page](https://docs.tryterra.co/vantage-api-docs/important-information/acknowledging-results#example-acknowledgement-page) * [Acknowledgement Endpoint](https://docs.tryterra.co/vantage-api-docs/important-information/acknowledging-results#acknowledgement-endpoint) Was this helpful? sun-brightdesktopmoon Copy POST /api/v1/results/{order_item_id}/acknowledge Copy curl --location --request POST \ 'https://vantage-sandbox.tryterra.co/api/v1/results/249956252111773699/acknowledge' \ --header 'Content-Type: application/json' \ --header 'Authorization: Basic ' Copy import requests order_item_id = 249956252111773699 url = f"https://vantage-sandbox.tryterra.co/api/v1/results/{order_item_id}/acknowledge" headers = { 'Content-Type': 'application/json', 'Authorization': 'Basic ' } response = requests.post(url, headers=headers) print(response.json()) print(response.status_code) Copy package main import ( "fmt" "io" "net/http" ) func main() { orderItemID := int64(249956252111773699) url := fmt.Sprintf("https://vantage-sandbox.tryterra.co/api/v1/results/%d/acknowledge", orderItemID) client := &http.Client{} req, err := http.NewRequest("POST", url, nil) if err != nil { panic(err) } req.Header.Add("Content-Type", "application/json") req.Header.Add("Authorization", "Basic ") res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { panic(err) } fmt.Println(string(body)) } sun-brightdesktopmoon --- # Terra AI | AI | Terra Docs Our AI suite allows your AI agents to interface with Terra's health data directly. Your AI agents can do this through our MCP (Model Context Protocol) which gives your AI agent the necessary tools and data. Our MCP allows you to: 1. Request only specific, relevant data sets 2. Access a user’s health memory 3. Access aggregated stats, trends and baselines 4. Access semantic meaning of health data ### [hashtag](https://docs.tryterra.co/ai-interface#why-we-built-terra-ai) Why we built Terra AI We built Terra AI so that your AI agents can retrieve and reason over health data in the most token efficient way. This means that you don't have to make API calls, handle webhooks, trigger backfills, store or parse data. It ensures that your agent only retrieves meaningful, relevant data for reasoning, without having to overfetch or bloat their context limits. ### [hashtag](https://docs.tryterra.co/ai-interface#quick-install) Quick install You need to add the MCP configuration to your client to get started. Below is the setup guide for some example AI IDEs to test the responses you would get for example prompts, but you can use Terra's AI suite with any system that supports an MCP. You will need to include your `dev-id` and `x-api-key` in the HTTP headers. You can find these on Terra's dashboard under **API keys.** The `user_id` is passed as part of the server URL. Claude Code Claude desktop Cursor VS code Windsurf Replit In your terminal, run the following command: Copy claude mcp add --transport http terra-mcp https://access.tryterra.co/api/v2/mcp/ \ --header "dev-id: " \ --header "x-api-key: " 1. On Claude Dektop, navigate to **Settings > Developer** 2. Select **Edit Config** to open the configuration file 3. Copy paste the following code snippet to update the **claude\_desktop\_config.json** Copy { "mcpServers": { "terra": { "url": "https://access.tryterra.co/api/v2/mcp/", "headers": { "dev-id": "YOUR_DEV_ID", "x-api-key": "YOUR_API_KEY" } } } } 1. Open Cursor, then navigate to **Cursor Settings** > **Tools & Integrations** 2. Select **New MCP Server** 3. Copy paste the following code snippet to update the **mcp.json** Copy { "mcpServers": { "terra": { "url": "https://access.tryterra.co/api/v2/mcp/", "headers": { "dev-id": "YOUR_DEV_ID", "x-api-key": "YOUR_API_KEY" } } } } 1. Open VS Code, then open the configuration file by running `MCP: Open User Configuration` in the command palette. 2. Copy paste the following code snippet to update the **mcp.json** 1. Open Windsurf, then navigate to **Windsurf Settings** > **Cascade** > **MCP servers** 2. Select **Manage MCP Servers** 3. Select **View raw config** 4. Copy paste the following code snippet to update the **mcp\_config.json** 1. Open Replit, navigate to **Integrations page**, and scroll down to MCP Servers for **Replit Agent** 2. Select **Add MCP server** 3. Enter the server URL `https://access.tryterra.co/api/v2/mcp/` 4. Add customer headers: `your dev-id` and your `x-api-key` 5. Select **Test & Save** ### [hashtag](https://docs.tryterra.co/ai-interface#available-tools) Available tools Tools are functions that your AI agent can call to get specific health data. They can be used to query specific data and perform aggregations. Once connected, you can use the below tools. Each tool uses parameters such as user\_id, list of data fields, and optional filter conditions. To see the full list of available data fields for each tool, visit our [data models](https://docs.tryterra.co/reference/health-and-fitness-api/data-models) . Tool Purpose Examples get\_sleep\_data Gets sleep data including quality and quantity of sleep * Sleep end time * Sleep start time * Total sleep * REM sleep * Deep sleep * Light sleep * Sleep latency * Average HR * Resting HR * Average HRV * Respiratory rate * Average SpO2 * Sleep score full list [herearrow-up-right](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#sleep) get\_activity\_data Gets activity and workout session data * Activity start time * Activity end time * Activity type (running, cycling) * Location * Active time * Inactive time * Rest time * Low intensity time * Moderate intensity time * Vigorous intensity time * Total distance * Step count * Floors climbed * Swimming laps full list [herearrow-up-right](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#activity) get\_daily\_data Gets health data summaries throughout a given day * Average heart rate * Maximum heart rate * Minimum heart rate * Average HRV * Minimum HRV * Max heart rate * Resting heart rate * Average SpO2 * Total calories burned * Net active calories * Activity time * Daily distance * Daily step count * Total stress duration * Activity stress duration * Strain level * Recovery score * Activity score full list [herearrow-up-right](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#daily) get\_body\_data Gets body measurements * Water consumption * VO2 max estimate * Average SpO2 * Blood pressure * Measurements * Temperature * Ketones * ECG data full list [herearrow-up-right](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#body) get\_nutrition\_data Gets nutrients and calorie consumption * Total calories * Protein * CArbohydrates * Total fat * Trans fat * Saturated fat * Sugar * Cholesterol * Fiber * Vitamins * Micronutrients * Amino Acids full list [herearrow-up-right](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#nutrition) get\_menstruation\_data Gets menstrual cycle and fertility data * Cycle start time * Cycle end time * Period start date * Current phase * Length of current phase * Days until next phase * Predicted cycle length * Actual cycle length * Fertility widnow start * Fertility window end * Predicted ovulation day full list [herearrow-up-right](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#menstruation) ### [hashtag](https://docs.tryterra.co/ai-interface#example-scenarios) Example scenarios To help you understand how to use our MCP, here is a list of scenarios and prompts that your AI agent get respond to using Terra's MCP: **Health insights and analysis** * Give me a complete health snapshot: sleep, activity, stress, and recovery for this week * Show me the relationship between my sleep quality and next-day performance * What's my longest streak of days with at least 7 hours of sleep? **Pattern recognition and correlations** * Show me the correlation between my sleep latency and my stress level * What's my average resting heart rate on days after poor sleep vs good sleep? **Training and recovery optimization** * What's my optimal recovery time between high-intensity workouts? * Find all days where I had low recovery score but still did intense workouts **Predictive and proactive insights** * What's my predicted recovery time for tomorrow based on today's workout? * Based on my HRV trends, should I train hard or take it easy today? ### [hashtag](https://docs.tryterra.co/ai-interface#what-terras-mcp-includes) What Terra's MCP includes Terra's MCP includes three primitives: 1. Tools: These are functions that your AI agent can call to get specific health data. They can be used to query specific data and perform aggregations. _Example: The sleep tool can be used to perform an analysis of a user's sleep architecture between the 12th November 2025 and 30th November 2025._ 2. Resources: These provide context about the available data and how the data schema is structured. 3. Prompts: These are text based templates that help your AI agent understand how to use the tools and how to get data from our resources. Last updated 2 days ago Was this helpful? * [Why we built Terra AI](https://docs.tryterra.co/ai-interface#why-we-built-terra-ai) * [Quick install](https://docs.tryterra.co/ai-interface#quick-install) * [Available tools](https://docs.tryterra.co/ai-interface#available-tools) * [Example scenarios](https://docs.tryterra.co/ai-interface#example-scenarios) * [What Terra's MCP includes](https://docs.tryterra.co/ai-interface#what-terras-mcp-includes) Was this helpful? sun-brightdesktopmoon Copy { "mcpServers": { "terra": { "url": "https://access.tryterra.co/api/v2/mcp/", "headers": { "dev-id": "YOUR_DEV_ID", "x-api-key": "YOUR_API_KEY" } } } } Copy { "mcpServers": { "terra": { "url": "https://access.tryterra.co/api/v2/mcp/", "headers": { "dev-id": "YOUR_DEV_ID", "x-api-key": "YOUR_API_KEY" } } } sun-brightdesktopmoon --- # Results | Vantage API Docs | Terra Docs All results will be given in the FHIR format [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/results#scenarios-to-note) Scenarios to note ------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/results#results-out-of-range) Results out of range * In the example below for `HDL Cholesterol` we have a result that is below normal * This can be clearly observed with the following values: * `high`: 100.0 * `low`: 40.0 * `value`: 35.2 ### [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/results#critical-results-must-be-handled-properly) Critical Results - Must be handled properly! * Depending on the test supplier you may receive a webhook indicating the overall severity of the results. * We called this `escalation_level` , reaching a maximum of `escalation_level.very_high` * Additionally, the `interpretation` field will likely have code `HH` or `LL` in critical cases. Please refer to this [linkarrow-up-right](https://hl7-definition.caristix.com/v2/HL7v2.8/Tables/0078) for more information. * Refer to [Webhooks](https://docs.tryterra.co/vantage-api-docs/documentation/webhooks) to see `results.escalation_raised.` ### [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/results#failed-tests) Failed Tests * You will receive a webhook with the failure reason when a sample has been rejected by the lab. Refer to [Webhooks](https://docs.tryterra.co/vantage-api-docs/documentation/webhooks) ### [hashtag](https://docs.tryterra.co/vantage-api-docs/documentation/results#example-results) Example Results [PreviousTest Collection Methodschevron-left](https://docs.tryterra.co/vantage-api-docs/documentation/test-collection-methods) [NextAcknowledging Resultschevron-right](https://docs.tryterra.co/vantage-api-docs/important-information/acknowledging-results) Last updated 1 month ago Was this helpful? * [Scenarios to note](https://docs.tryterra.co/vantage-api-docs/documentation/results#scenarios-to-note) * [Results out of range](https://docs.tryterra.co/vantage-api-docs/documentation/results#results-out-of-range) * [Critical Results - Must be handled properly!](https://docs.tryterra.co/vantage-api-docs/documentation/results#critical-results-must-be-handled-properly) * [Failed Tests](https://docs.tryterra.co/vantage-api-docs/documentation/results#failed-tests) * [Example Results](https://docs.tryterra.co/vantage-api-docs/documentation/results#example-results) Was this helpful? sun-brightdesktopmoon Copy { "entry": [\ {\ "fullUrl": "DiagnosticReport/dr-252463239248650243",\ "resource": {\ "code": {\ "text": "Laboratory Panel"\ },\ "effectiveDateTime": "1970-01-01T00:29:23+00:00",\ "id": "dr-252463239248650243",\ "issued": "1970-01-01T00:29:24+00:00",\ "resourceType": "DiagnosticReport",\ "result": [\ {\ "display": "Total Cholesterol",\ "reference": "Observation/obs-252463239248650243-CHOL"\ },\ {\ "display": "HDL Cholesterol",\ "reference": "Observation/obs-252463239248650243-HDL"\ },\ {\ "display": "LDL Cholesterol",\ "reference": "Observation/obs-252463239248650243-LDL"\ },\ {\ "display": "Triglycerides",\ "reference": "Observation/obs-252463239248650243-TRIG"\ },\ {\ "display": "Hemoglobin A1c",\ "reference": "Observation/obs-252463239248650243-HBA1C"\ }\ ],\ "status": "final",\ "subject": {\ "reference": "Patient/252463822202380289"\ }\ }\ },\ {\ "fullUrl": "Patient/252463822202380289",\ "resource": {\ "address": [\ {\ "city": "San Francisco",\ "country": "US",\ "line": [\ "123 Test Street",\ "Apt 4B"\ ],\ "postalCode": "94102",\ "state": "CA"\ }\ ],\ "birthDate": "1970-01-01",\ "gender": "male",\ "id": "252463822202380289",\ "name": [\ {\ "family": "Doe",\ "given": [\ "John"\ ]\ }\ ],\ "resourceType": "Patient",\ "telecom": [\ {\ "system": "email",\ "value": "[email protected]"\ },\ {\ "system": "phone",\ "value": "+14155551234"\ }\ ]\ }\ },\ {\ "fullUrl": "Observation/obs-252463239248650243-CHOL",\ "resource": {\ "code": {\ "coding": [\ {\ "code": "CHOL",\ "display": "Total Cholesterol",\ "system": "https://api.imaware.health/fhir/CodeSystem/test-codes"\ }\ ],\ "text": "Total Cholesterol"\ },\ "effectiveDateTime": "1970-01-01T00:29:23+00:00",\ "id": "obs-252463239248650243-CHOL",\ "interpretation": [\ {\ "coding": [\ {\ "code": "N",\ "display": "Normal",\ "system": "http://terminology.hl7.org/CodeSystem/v2-0078"\ }\ ]\ }\ ],\ "issued": "1970-01-01T00:29:24+00:00",\ "referenceRange": [\ {\ "high": {\ "value": 200\ },\ "text": "0.0 - 200.0"\ }\ ],\ "resourceType": "Observation",\ "status": "final",\ "subject": {\ "reference": "Patient/252463822202380289"\ },\ "valueQuantity": {\ "code": "mg/dL",\ "unit": "mg/dL",\ "value": 185.5\ }\ }\ },\ {\ "fullUrl": "Observation/obs-252463239248650243-HDL",\ "resource": {\ "code": {\ "coding": [\ {\ "code": "HDL",\ "display": "HDL Cholesterol",\ "system": "https://api.imaware.health/fhir/CodeSystem/test-codes"\ }\ ],\ "text": "HDL Cholesterol"\ },\ "effectiveDateTime": "1970-01-01T00:29:23+00:00",\ "id": "obs-252463239248650243-HDL",\ "interpretation": [\ {\ "coding": [\ {\ "code": "L",\ "display": "Below low normal",\ "system": "http://terminology.hl7.org/CodeSystem/v2-0078"\ }\ ]\ }\ ],\ "issued": "1970-01-01T00:29:24+00:00",\ "referenceRange": [\ {\ "high": {\ "value": 100\ },\ "low": {\ "value": 40\ },\ "text": "40.0 - 100.0"\ }\ ],\ "resourceType": "Observation",\ "status": "final",\ "subject": {\ "reference": "Patient/252463822202380289"\ },\ "valueQuantity": {\ "code": "mg/dL",\ "unit": "mg/dL",\ "value": 35.2\ }\ }\ },\ {\ "fullUrl": "Observation/obs-252463239248650243-LDL",\ "resource": {\ "code": {\ "coding": [\ {\ "code": "LDL",\ "display": "LDL Cholesterol",\ "system": "https://api.imaware.health/fhir/CodeSystem/test-codes"\ }\ ],\ "text": "LDL Cholesterol"\ },\ "effectiveDateTime": "1970-01-01T00:29:23+00:00",\ "id": "obs-252463239248650243-LDL",\ "interpretation": [\ {\ "coding": [\ {\ "code": "N",\ "display": "Normal",\ "system": "http://terminology.hl7.org/CodeSystem/v2-0078"\ }\ ]\ }\ ],\ "issued": "1970-01-01T00:29:24+00:00",\ "referenceRange": [\ {\ "high": {\ "value": 130\ },\ "text": "0.0 - 130.0"\ }\ ],\ "resourceType": "Observation",\ "status": "final",\ "subject": {\ "reference": "Patient/252463822202380289"\ },\ "valueQuantity": {\ "code": "mg/dL",\ "unit": "mg/dL",\ "value": 110.3\ }\ }\ },\ {\ "fullUrl": "Observation/obs-252463239248650243-TRIG",\ "resource": {\ "code": {\ "coding": [\ {\ "code": "TRIG",\ "display": "Triglycerides",\ "system": "https://api.imaware.health/fhir/CodeSystem/test-codes"\ }\ ],\ "text": "Triglycerides"\ },\ "effectiveDateTime": "1970-01-01T00:29:23+00:00",\ "id": "obs-252463239248650243-TRIG",\ "interpretation": [\ {\ "coding": [\ {\ "code": "N",\ "display": "Normal",\ "system": "http://terminology.hl7.org/CodeSystem/v2-0078"\ }\ ]\ }\ ],\ "issued": "1970-01-01T00:29:24+00:00",\ "referenceRange": [\ {\ "high": {\ "value": 150\ },\ "text": "0.0 - 150.0"\ }\ ],\ "resourceType": "Observation",\ "status": "final",\ "subject": {\ "reference": "Patient/252463822202380289"\ },\ "valueQuantity": {\ "code": "mg/dL",\ "unit": "mg/dL",\ "value": 120\ }\ }\ },\ {\ "fullUrl": "Observation/obs-252463239248650243-HBA1C",\ "resource": {\ "code": {\ "coding": [\ {\ "code": "HBA1C",\ "display": "Hemoglobin A1c",\ "system": "https://api.imaware.health/fhir/CodeSystem/test-codes"\ }\ ],\ "text": "Hemoglobin A1c"\ },\ "effectiveDateTime": "1970-01-01T00:29:23+00:00",\ "id": "obs-252463239248650243-HBA1C",\ "interpretation": [\ {\ "coding": [\ {\ "code": "N",\ "display": "Normal",\ "system": "http://terminology.hl7.org/CodeSystem/v2-0078"\ }\ ]\ }\ ],\ "issued": "1970-01-01T00:29:24+00:00",\ "referenceRange": [\ {\ "high": {\ "value": 5.6\ },\ "low": {\ "value": 4\ },\ "text": "4.0 - 5.6"\ }\ ],\ "resourceType": "Observation",\ "status": "final",\ "subject": {\ "reference": "Patient/252463822202380289"\ },\ "valueQuantity": {\ "code": "%",\ "unit": "%",\ "value": 5.2\ }\ }\ }\ ], "resourceType": "Bundle", "timestamp": "1970-01-01T00:29:24+00:00", "type": "collection" } sun-brightdesktopmoon --- # January Update 2026 | Changelog | Terra Docs Check out what we've been doing at Terra over the month of January 2026! [hashtag](https://docs.tryterra.co/changelog#backend) Backend 💾 --------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/changelog#features) Features * Terra now provides an MCP server! Get started [herearrow-up-right](https://docs.tryterra.co/ai-interface/configuration#mcp-client-configuration) ### [hashtag](https://docs.tryterra.co/changelog#bugs) Bugs * Freestylelibre has been removed from all integrations endpoints * Fixed a bug where MongoDB Destination did not specify the "database" for connection in the URL * Fixed a bug where "data\_provided" field showed duplicates for Google * Fixed an issue where Ketomojo data were sometimes not returned correctly * Fixed an issue where deauthentication would return a 500 eventhough it was successful due to already revoked tokens * Fixed an issue where sometimes Polar's Timezone offset was not provided correctly * Fixed an issue with revocation tokens for Polar, WHOOP and Zepp * Fixed an issue where Garmin backfills were sometimes not going through correctly * * * [hashtag](https://docs.tryterra.co/changelog#sdks) SDKs ------------------------------------------------------------ ### [hashtag](https://docs.tryterra.co/changelog#android) Android * (Samsung Data SDK) Fixed an issue where if the user's phone does not include Samsung Health is not installed, it crashes the app when opening the Play store for Samsung Health App * * * [hashtag](https://docs.tryterra.co/changelog#dashboard) Dashboard ---------------------------------------------------------------------- * Update Terms of Service modal text for clarity * * * [hashtag](https://docs.tryterra.co/changelog#landing-page) Landing Page ---------------------------------------------------------------------------- * Update end-user privacy policy * Update terms of service * We have released a reports page for you to see all the reports we have written. Have a [lookarrow-up-right](https://tryterra.co/reports) ! [NextDecember Update 2025chevron-right](https://docs.tryterra.co/changelog/2025/december-update-2025) Last updated 5 days ago Was this helpful? * [Backend 💾](https://docs.tryterra.co/changelog#backend) * [Features](https://docs.tryterra.co/changelog#features) * [Bugs](https://docs.tryterra.co/changelog#bugs) * [SDKs](https://docs.tryterra.co/changelog#sdks) * [Android](https://docs.tryterra.co/changelog#android) * [Dashboard](https://docs.tryterra.co/changelog#dashboard) * [Landing Page](https://docs.tryterra.co/changelog#landing-page) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Ordering your first test | Vantage API Docs | Terra Docs For more details on the specific endpoints, follow the OpenAPI reference Before we begin, let's clarify some key terminology you'll encounter with some analogies: * `Product Types`: The broadest category of offering (e.g., iPhone, MacBook, iPad) * `Products`: Individual products within each type (e.g., iPhone 17 Pro, iPhone 16 Pro Max) * `Product Variants`: The specific configuration an end user receives (e.g., iPhone 17 White 256GB) ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test#id-1.-explore-product-types) 1\. Explore Product Types * Start off by exploring what product types are available, by calling the `GET api/v1/products` endpoint circle-info **🤖 Production Base URL:** Copy https://vantage.tryterra.co **🏝️ Sandbox Base URL:** Copy https://vantage-sandbox.tryterra.co cURL Python GO Copy curl --location --request GET \ 'https://vantage-sandbox.tryterra.co/api/v1/products/' \ --header 'Authorization: Basic ' Copy import requests url = "https://vantage-sandbox.tryterra.co/api/v1/products/" headers = { 'Authorization': 'Basic ' } response = requests.get(url, headers=headers) print(response.text) Copy package main import ( "fmt" "io" "net/http" ) func main() { url := "https://vantage-sandbox.tryterra.co/api/v1/products/" req, _ := http.NewRequest("GET", url, nil) req.Header.Add("Authorization", "Basic ") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(string(body)) } 200 Copy [\ {\ "description": "Diagnostic blood panels and biomarker tests",\ "id": 1,\ "name": "Blood Test"\ }\ ] ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test#id-2.-explore-products-within-each-product-type) 2\. Explore Products within each product type * Suppose we are looking to order a blood test. Let's see what Vantage API offers. * **N.B: '**1' is the **product type** ID of a blood test as seen in the response above cURL Python GO 200 ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test#id-3.-explore-product-variants-within-each-product) 3\. Explore Product Variants within each Product * Now let's choose the exact blood test we would like to order * **N.B** 10002 is the product id of a blood test product as seen in the response above cURL Python GO 200 ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test#id-4.-order-a-test-kit) 4\. Order a test kit * Now let's order one 'Inflammation' test kit (`product_type_id` = 1, `product_id` = 10002, `product_variant_id` = 100041) * Note that all you need is the **variant ID** and quantity to make an order * For now all orders will be in USD (840 in IS0 4217 format) * Different suppliers have different constraints when ordering * If you try to order a product variant that does not exist, you can expect the 404 response below cURL Python GO 200 404 ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test#id-5.-receiving-webhooks-verification-of-receipt) 5\. Receiving Webhooks - Verification of Receipt * Below are the first two webhooks that you will receive if a order is placed successfully * **N.B:** You will still receive these webhooks even when working with sandbox :) circle-info Note that in products, `supplier_item_id` will not be provided as this information is only relevant to your end users Payment complete Delivery Fulfiled ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test#id-6.-relax-and-wait-for-your-new-kit) 6\. Relax and wait for your new kit 🎉 * If you are working in sandbox, move on to the next section to see how you would receive results!! * If you are working in prod, still read the next section to see the results flow 🤝 [PreviousAccount setup and API keyschevron-left](https://docs.tryterra.co/vantage-api-docs/account-setup-and-api-keys) [NextWorking with Sandboxchevron-right](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs) Last updated 1 month ago Was this helpful? * [1\. Explore Product Types](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test#id-1.-explore-product-types) * [2\. Explore Products within each product type](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test#id-2.-explore-products-within-each-product-type) * [3\. Explore Product Variants within each Product](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test#id-3.-explore-product-variants-within-each-product) * [4\. Order a test kit](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test#id-4.-order-a-test-kit) * [5\. Receiving Webhooks - Verification of Receipt](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test#id-5.-receiving-webhooks-verification-of-receipt) * [6\. Relax and wait for your new kit 🎉](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test#id-6.-relax-and-wait-for-your-new-kit) Was this helpful? sun-brightdesktopmoon Copy curl --location --request GET \ 'https://vantage-sandbox.tryterra.co/api/v1/products/1' \ --header 'Authorization: Basic ' Copy import requests product_type_id = 1 url = "https://vantage-sandbox.tryterra.co/api/v1/products/" + str(product_type_id) headers = { 'Authorization': 'Basic ' } response = requests.get(url, headers=headers) print(response.text) Copy package main import ( "fmt" "io" "net/http" ) func main() { productTypeID := 1 url := fmt.Sprintf("https://vantage-sandbox.tryterra.co/api/v1/products/%d", productTypeID) req, _ := http.NewRequest("GET", url, nil) req.Header.Add("Authorization", "Basic ") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(string(body)) } Copy [\ {\ "id": 10002,\ "product_type_id": 1,\ "supplier_id": 2,\ "name": "Blood Test",\ "description": "At-home blood test kit with lab processing.",\ "base_price_cents": 4999,\ "currency": 840,\ "availability": 1\ }\ ] Copy curl --location --request GET \ 'https://vantage-sandbox.tryterra.co/api/v1/products/10002/variants' \ --header 'Authorization: Basic ' Copy import requests product_id = 10002 url = "https://vantage-sandbox.tryterra.co/api/v1/products/" + str(product_id) + "/variants" headers = { 'Authorization': 'Basic ' } response = requests.get(url, headers=headers) print(response.text) Copy package main import ( "fmt" "io" "net/http" ) func main() { productID := 10002 url := fmt.Sprintf("https://vantage-sandbox.tryterra.co/api/v1/products/%d/variants", productID) req, _ := http.NewRequest("GET", url, nil) req.Header.Add("Authorization", "Basic ") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(string(body)) } Copy [\ {\ "id": 100041,\ "product_id": 10002,\ "product_type_id": 1,\ "product_external_sku": "TA_002",\ "supplier_id": 2,\ "variant_name": "Inflammation",\ "variant_defining_attrs": {\ "biomarkers": [\ "hs-CRP",\ "Vitamin D"\ ],\ "panel": "Inflammation",\ "turnaround_days": "3-5"\ },\ "descriptive_attrs_override": {\ "notes": "Inflammation marker testing"\ },\ "variant_availability": 1,\ "price_cents": 7900,\ "currency": 840,\ "available_collection_types": [\ "AT_HOME",\ "GO_TO_LAB"\ ]\ },\ ] Copy curl --location --request POST 'https://vantage-sandbox.tryterra.co/api/v1/orders' \ --header 'Content-Type: application/json' \ --header 'Authorization: Basic ' \ --data-raw '{ "client_order_reference_id": "TEST-ORDER-001", "recipient": { "first_name": "John", "last_name": "Smith", "email": "[email protected]", "phone_number": 4155551234, "country_code": 1, "date_of_birth": "1995-10-10", "gender_at_birth": "m" }, "shipping_address": { "address_line_1": "123 Market Street", "city": "San Francisco", "administrative_area": "CA", "country_code": "US", "postal_code": "94102" }, "items": [\ {\ "variant_id": 100041,\ "quantity": 1\ }\ ] }' Copy import requests import json url = "https://vantage-sandbox.tryterra.co/api/v1/orders" headers = { 'Content-Type': 'application/json', 'Authorization': 'Basic ' } payload = { "client_order_reference_id": "TEST-ORDER-001", "recipient": { "first_name": "John", "last_name": "Smith", "email": "[email protected]", "phone_number": 4155551234, "country_code": 1, "date_of_birth": "1995-10-10", "gender_at_birth": "m" }, "shipping_address": { "address_line_1": "123 Market Street", "city": "San Francisco", "administrative_area": "CA", "country_code": "US", "postal_code": "94102" }, "items": [\ {\ "variant_id": 100021,\ "quantity": 1\ }\ ] } response = requests.post(url, headers=headers, json=payload) print(response.text) Copy package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) func main() { url := "https://vantage-sandbox.tryterra.co/api/v1/orders" payload := map[string]interface{}{ "client_order_reference_id": "TEST-ORDER-001", "recipient": map[string]any{ "first_name": "John", "last_name": "Smith", "email": "[email protected]", "phone_number": 4155551234, "country_code": 1, "date_of_birth": "1995-10-10", "gender_at_birth": "m", }, "shipping_address": map[string]any{ "address_line_1": "123 Market Street", "city": "San Francisco", "administrative_area": "CA", "country_code": "US", "postal_code": "94102", }, "items": []map[string]interface{}{ { "variant_id": 100021, "quantity": 1, }, }, } jsonData, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) req.Header.Add("Content-Type", "application/json") req.Header.Add("Authorization", "Basic ") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(string(body)) } Copy { "order_id": 251285377984405504, "recipient_id": 251285377984405505, "order_items": [\ {\ "order_id": 251285377984405504,\ "order_item_id": 251285377984405507,\ "variant_id": 100021,\ "product_type_id": 1,\ "price_per_item_cents": 4999,\ "quantity": 1,\ "currency": 840,\ "results_status": "results.awaiting_sample"\ }\ ], "order_status": "order.payment_processing" } Copy { "detail": "resource not found", "instance": "/api/v1/orders", "status": 404, "title": "Resource Not Found", "type": "https://docs.tryterra.co/errors/not-found-error" } Copy { "data": { "order_id": 249956252111773696, "status": "fulfillment.payment_complete" }, "event_id": 249956266972192768, "event_type": "order.status_changed", "timestamp": 1763661418 } Copy { "data": { "order_id": 249956252111773696, "status": "fulfillment.delivery_fulfilled", "supplier_item_id": "249956258550030336", "tracking_number": "KnD3d5PMZyq5ulNcWkrq" }, "event_id": 249956485092777984, "event_type": "order.status_changed", "timestamp": 1763661470 } sun-brightdesktopmoon --- # Working with Sandbox | Vantage API Docs | Terra Docs * To familiarise yourself with the API, we provide a **comprehensive sandbox environment** where you can simulate ordering kits from different suppliers * Below we will simulate an ordering a kit + end user's flow from a supplier that supports a 2 step activation process triangle-exclamation ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#kit-activation-in-sandbox) **Kit Activation in Sandbox** Certain suppliers require end-users to activate the kit themselves (i.e scanning a QR code on the kit). For **Sandbox** you will have to mimic this step by calling the `api/v1/orders/activate` endpoint (as shown below) circle-check You will receive automated webhooks in sandbox to your configured endpoint ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-1.-order-a-test-kit) 1\. Order a test kit * Follow the steps as outlined in [Ordering your first test](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test) within the sandbox ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-2.-receiving-suppliers-item-id) 2\. Receiving supplier's item ID * After ordering a kit you should receive the following webhook: * Notice how `supplier_item_id` is only available when working in sandbox Sandbox Production Copy { "data": { "order_id": 249956252111773696, "status": "fulfillment.delivery_fulfilled", "supplier_item_id": "249602021676720128", "tracking_number": "KnD3d5PMZyq5ulNcWkrq" }, "event_id": 249956485092777984, "event_type": "order.status_changed", "timestamp": 1763661470 } Copy { "data": { "order_id": 249956252111773696, "status": "fulfillment.delivery_fulfilled", "tracking_number": "KnD3d5PMZyq5ulNcWkrq" }, "event_id": 249956485092777984, "event_type": "order.status_changed", "timestamp": 1763661470 } ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-3.-activating-the-kit) 3\. Activating the kit * For suppliers who support 2 step activation, on each kit there will be a QR code that embeds the following URL which links to prod * To simulate scanning the QR code: * Replace the production domain with sandbox domain * Paste `supplier_item_id` as the query parameter Sandbox Production * You should be redirected to the page below - fill out the details and activate your kit! ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-4.-lab-received-kit--results) 4\. Lab received kit + results ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F2398619654-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FQnL9sbo31piU0slHHABv%252Fuploads%252F2pwg9vIRcgSBOFzfEjvW%252Fimage.png%3Falt%3Dmedia%26token%3Dbf08004c-f616-4bef-9355-fa2f4bb78339&width=768&dpr=3&quality=100&sign=bfb657c1&sv=2) ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F2398619654-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FQnL9sbo31piU0slHHABv%252Fuploads%252FP4tcVlFlDi8vLZV7ehD1%252Fimage.png%3Falt%3Dmedia%26token%3D1ec83e86-59d0-49a8-b224-75889b24abb4&width=768&dpr=3&quality=100&sign=2924ef09&sv=2) ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-4.-lab-received-kit--results-1) 4\. Lab received kit + Results * At this point your end user will take the test and post it to the lab to be analysed. Upon arriving at the lab, a webhook will be sent to you. * Results will be available shortly after arrival of the kit at the lab, with a second webhook sent. * To simulate this, the sandbox environment automatically sends the following two webhooks after successful kit activation, sent at 1-2 minute intervals. * **N.B** There is also a change you will get a `results.sample_rejected` webhook Lab Processing Results Ready ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-5.-fetching-results) 5\. Fetching results * When fetching results, a pre-signed URL will be returned which can be used to download test results * Use `order_item_id` and `test_taker_id` to fetch results cURL Python GO 200 ### [hashtag](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-6.-acknowledge-results) 6\. Acknowledge Results * Once an end user sees their results, they are **required** to acknowledge it * How an end-user interfaces with the acknowledgement page must adhere to [Acknowledging Results](https://docs.tryterra.co/vantage-api-docs/important-information/acknowledging-results) to be compliant * Importantly you need to inform us an end-user has acknowledged their results by hitting the following endpoint * We also use `order_item_id` and `test_taker_id` to acknowledge cURL Python Go [PreviousOrdering your first testchevron-left](https://docs.tryterra.co/vantage-api-docs/getting-started/ordering-your-first-test) [NextWebhookschevron-right](https://docs.tryterra.co/vantage-api-docs/documentation/webhooks) Last updated 1 month ago Was this helpful? * [1\. Order a test kit](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-1.-order-a-test-kit) * [2\. Receiving supplier's item ID](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-2.-receiving-suppliers-item-id) * [3\. Activating the kit](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-3.-activating-the-kit) * [4\. Lab received kit + results](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-4.-lab-received-kit--results) * [4\. Lab received kit + Results](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-4.-lab-received-kit--results-1) * [5\. Fetching results](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-5.-fetching-results) * [6\. Acknowledge Results](https://docs.tryterra.co/vantage-api-docs/getting-started/publish-your-docs#id-6.-acknowledge-results) Was this helpful? sun-brightdesktopmoon Copy https://vantage-sandbox.tryterra.co/api/v1/orders/activate?kit_id=249602021676720128 Copy https://vantage.tryterra.co/api/v1/orders/activate?kit_id=249602021676720128 Copy { "data": { "order_id": 249956252111773696, "order_item_id": 249956252111773699, "results_status": "results.sample_processing_in_lab", "test_taker": { "test_taker_id": "257837964552478720", "country_code": 1, "email": "[email protected]", "first_name": "John", "last_name": "Doe", "phone_number": 4155551234 }, "variant_id": 100021 }, "event_id": 249958648347009024, "event_type": "order_item.results_status_change", "timestamp": 1763661985 } Copy { "data": { "order_id": 249956252111773696, "order_item_id": 249956252111773699, "results_status": "results.results_ready", "test_taker": { "test_taker_id": "257837964552478720", "country_code": 1, "email": "[email protected]", "first_name": "John", "last_name": "Doe", "phone_number": 4155551234 }, "variant_id": 100021 }, "event_id": 249958796259139584, "event_type": "order_item.results_status_change", "timestamp": 1763662021 } Copy curl --location --request GET \ 'https://vantage-sandbox.tryterra.co/api/v1/results/249956252111773699?test_taker_id=257837964552478720' \ --header 'Content-Type: application/json' \ --header 'Authorization: Basic ' Copy import requests order_item_id = "249956252111773699" test_taker_id = "257837964552478720" url = f"https://vantage-sandbox.tryterra.co/api/v1/results/{order_item_id}?test_taker_id={test_taker_id}" headers = { 'Content-Type': 'application/json', 'Authorization': 'Basic ' } response = requests.get(url, headers=headers) print(response.text) print(response.status_code) Copy package main import ( "fmt" "io" "net/http" ) func main() { orderItemID := "249956252111773699" testTakerID := "257837964552478720" url := fmt.Sprintf("https://vantage-sandbox.tryterra.co/api/v1/results/%s?test_taker_id=", orderItemID, testTakerID) client := &http.Client{} req, err := http.NewRequest("GET", url, nil) if err != nil { panic(err) } req.Header.Add("Content-Type", "application/json") req.Header.Add("Authorization", "Basic ") res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { panic(err) } fmt.Println(string(body)) } Copy { "download_url": "https://storage.googleapis.com/terra-diagnostics-results-sandbox-terra-diagnostics-sandbox/client/terra-client-payable/results/249717507/normalised.json?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=terra-diagnostics-sa%40terra-diagnostics-sandbox.iam.gserviceaccount.com%2F20251119%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20251119T185304Z&X-Goog-Expires=899&X-Goog-Signature=c3d7b929233b6e08bd41d8f9959950736db897226b99014e2f10238185851f6fe2191d5c8e34a518a6325c21ff7c627a1a6753e5f3b4e52d219e3107be9c6feaa0362eb442a5766404bdab19bbb53c408584e15e68f00b1099dd71f6a82282ba3d970917562583a589aceca7d20599f4215874d3af9853661c6d31bc52407bdf59287415b162860b691e39fbf13f9e5a18768279cc8c318ea79383a6315ebaabec814f097a83c8102657a47d20f00c0dcac3152eb62f86c40190053824206bb21b27c01febf818a02aec1587de2770881f332c5e688d55f169ef61e7f15708963681a27665805863e313aa9fce39d3201177&X-Goog-SignedHeaders=host", "format": "json", "expires_at": "2025-11-19T19:08:04.40025031Z" } Copy https://vantage-sandbox.tryterra.co/api/v1/results/{order_item_id}/acknowledge?test_taker_id={test_taker_id} Copy curl --location --request POST \ 'https://vantage-sandbox.tryterra.co/api/v1/results/249956252111773699/acknowledge?test_taker_id=257837964552478720' \ --header 'Content-Type: application/json' \ --header 'Authorization: Basic ' Copy import requests order_item_id = "249956252111773699" test_taker_id = "257837964552478720" url = f"https://vantage-sandbox.tryterra.co/api/v1/results/{order_item_id}/acknowledge?test_taker_id={test_taker_id}" headers = { 'Content-Type': 'application/json', 'Authorization': 'Basic ' } response = requests.post(url, headers=headers) print(response.text) print(response.status_code) Copy package main import ( "fmt" "io" "net/http" ) func main() { orderItemID := "249956252111773699" testTakerID := "257837964552478720" url := fmt.Sprintf("https://vantage-sandbox.tryterra.co/api/v1/results/%s/acknowledge?test_taker_id=%s", orderItemID, testTakerID) client := &http.Client{} req, err := http.NewRequest("POST", url, nil) if err != nil { panic(err) } req.Header.Add("Content-Type", "application/json") req.Header.Add("Authorization", "Basic ") res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { panic(err) } fmt.Println(string(body)) } sun-brightdesktopmoon --- # User authentication | Terra Docs User authentication allows Terra to accessing your users' health and fitness data and is essential to using the Health & Fitness API. Authentication allows your end-users to grant your application permission to retrieve data from their wearables or fitness platforms (like Fitbit, Garmin, Oura, etc.). Once a user is successfully authenticated, Terra automatically pushes their health data events to your configured destination. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication#implementation-guides) Implementation guides ------------------------------------------------------------------------------------------------------------------------------- 1 [**Authentication flow overview**](https://docs.tryterra.co/health-and-fitness-api/user-authentication/authentication-flow) Get an overview of the user authentication process, from the initial user action in your app to receiving their Terra User ID. 2 [**Authenticating with the Terra widget**](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-terra-widget) The quickest way to get started. Learn how to integrate Terra's pre-built, customisable UI to handle the provider selection and authentication process with a single API call. 3 [**Handling authentication events**](https://docs.tryterra.co/health-and-fitness-api/user-authentication/handling-authentication-events) Understand the different types of authentication events Terra sends (success, failure, deauthorisation) and how to process their payloads effectively. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication#configuration) Configuration --------------------------------------------------------------------------------------------------------------- [**Customising authentication redirects**](https://docs.tryterra.co/health-and-fitness-api/user-authentication/customising-authentication-redirects) * Learn how to customise the success or failure screen that users see after they complete the authentication flow but before they are redirected back to your app. [**Authenticating with your own UI**](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui) * For maximum control over the user experience. This guide details how to build your own device connection screen and use Terra's API to authenticate users with specific providers. circle-info 💡 **Pro-Tip:** Start with the widget because it’s the: 1. **Fastest way to go live:** no need to build or maintain your own auth UI 2. **Easiest to implement:** just one backend call to generate the link 3. **Optimized UX:** designed and tested for high end-user completion rates across devices and platforms * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication#checklist) ✅ Checklist --------------------------------------------------------------------------------------------------------- circle-check [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication#implementing-the-user-authentication-in-your-app) Implementing the User Authentication in your App ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1. **API**: 1. **Credentials:** Did you find your Terra API Keys and Dev-ID in your Terra Dashboard? 2. **Endpoint**: Did you make a **successful** **request** from your backend to one of the /auth endpoints? 1. `POST` `/auth/generateWidgetSession` 2. `POST` `/auth/authenticateUser?resource=oura` 3. **Response**: Did you get a **200 response** and parse the authentication url? Either: 1. `"url"`: the widget screen (via the widget endpoint) 2. `"auth_url"` : the provider's login screen (via the authenticateUser endpoint) 4. **End-user:** Was your end-user redirected to an **Auth** **Success** **Screen**? 2. **Event**: Did you receive an **Success "Authentication Event"** to your destination? 3. **Database**: Did you save this user in your Database using `user_id` ? [PreviousUnderstanding Terra environmentschevron-left](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-terra-environments) [NextAuthentication flowchevron-right](https://docs.tryterra.co/health-and-fitness-api/user-authentication/authentication-flow) Last updated 8 months ago Was this helpful? * [Implementation guides](https://docs.tryterra.co/health-and-fitness-api/user-authentication#implementation-guides) * [Configuration](https://docs.tryterra.co/health-and-fitness-api/user-authentication#configuration) * [✅ Checklist](https://docs.tryterra.co/health-and-fitness-api/user-authentication#checklist) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Managing user health data | Terra Docs Once your integrations are setup and you're successfully authenticating users, the next step is to interact with their health and fitness data. This section covers the methods for accessing the data Terra collects and the procedures for sending data back to supported providers. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data#retrieving-user-data) Retrieving user data ----------------------------------------------------------------------------------------------------------------------------------- [**Receiving data events (automatic updates)**](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates) * Learn how Terra automatically pushes new health and fitness data as events to your configured destination whenever it becomes available from a user's connected source (e.g. via Webhooks). This is the primary method for receiving ongoing user data. [**Requesting historical data**](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data) * Understand how to make API requests to fetch batches of past data for a user. This is useful for initial data backfills, analytics, or ad-hoc data retrieval. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data#writing-data) Writing data ------------------------------------------------------------------------------------------------------------------- [**Writing data to user accounts (e.g. planned workouts)**](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/write-data) * Understand how to use Terra to send data, such as planned workouts, from your application back to a user's account on their fitness platform. [PreviousCustomising authentication redirectschevron-left](https://docs.tryterra.co/health-and-fitness-api/user-authentication/customising-authentication-redirects) [NextReceiving health data updates (events)chevron-right](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates) Last updated 8 months ago Was this helpful? * [Retrieving user data](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data#retrieving-user-data) * [Writing data](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data#writing-data) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Mobile-only sources | Terra Docs [hashtag](https://docs.tryterra.co/health-and-fitness-api/mobile-only-sources#overview) Overview ----------------------------------------------------------------------------------------------------- The primary use of the mobile SDKs is to allow you to access data from providers **that do not have a Web API.** circle-exclamation [hashtag](https://docs.tryterra.co/health-and-fitness-api/mobile-only-sources#data-sources-requiring-the-terra-mobile-sdk) Data Sources requiring the Terra **Mobile-SDK** ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The **Mobile SDK** is **ONLY** used to connect to the following integrations: 1. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FDH2JWDtg632mUQlEdrLH%252F4p3k173m8ihe71872bi9r0292q-0af5626e815091005bacb793985c1870.png%3Falt%3Dmedia%26token%3D062c917e-02fe-4029-9809-fc881cf09de3&width=40&dpr=3&quality=100&sign=efd2f029&sv=2)**Apple Health -** iOS 2. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252F0lTv9KpldVVjBdg3JJQs%252Fimgbin_samsung-galaxy-samsung-health-samsung-electronics-android-png.png%3Falt%3Dmedia%26token%3Db58f3118-a2e1-4b09-9d30-4f862253adb6&width=40&dpr=3&quality=100&sign=39e1314b&sv=2) **Samsung Health -** Android 3. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FmotL0wnZKiEWOKt46zOU%252Fvecteezy_google-fit-icon-logo-symbol_22484515.png%3Falt%3Dmedia%26token%3Da2d0ae73-5116-49fd-8ce1-0f7b5e6f716b&width=40&dpr=3&quality=100&sign=e5ed166f&sv=2) **Google Fit & Health Connect**\- Android. Note: the [Health & Fitness API](https://docs.tryterra.co/health-and-fitness-api/getting-started) is the preferred way to connect to Google Fit due to better reliability. For **ALL** other integrations, please refer to Integration Setup the [Health & Fitness API](https://docs.tryterra.co/health-and-fitness-api/getting-started) . ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252F6AmHWjQeikbUuA4S94yh%252Fsdk_flow.png%3Falt%3Dmedia%26token%3D421846d0-68ca-42e4-966b-a3dacd4dead8&width=768&dpr=3&quality=100&sign=32f16da8&sv=2) Data flow diagram for data from Apple Health/Samsung Health/Google Fit. Implementation details will vary based on your development framework/platform. Please refer to your framework's respective guide below: [](https://docs.tryterra.co/health-and-fitness-api/mobile-only-sources/ios-swift) ![Cover](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FcFdL8NtF8kHBmwAIrNUo%252Fapple_logo.png%3Falt%3Dmedia%26token%3D7b91a5ea-df1a-4e9f-8b38-7c46bb49e076&width=752&dpr=3&quality=100&sign=104b3bcc&sv=2) **iOS (Swift)** [](https://docs.tryterra.co/health-and-fitness-api/mobile-only-sources/android-kotlin) ![Cover](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252Fi1jbwHjs2mNj8rEuFYJH%252Fandroid_kotlin.svg%3Falt%3Dmedia%26token%3D903aee80-7c1f-4fc3-8a51-4ed7e142b989&width=752&dpr=3&quality=100&sign=a16f7f4a&sv=2) **Android (Kotlin)** [](https://docs.tryterra.co/health-and-fitness-api/mobile-only-sources/react-native) ![Cover](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FWqnjo39pyL9Dsp0xSMed%252Freact_native_logo.svg%3Falt%3Dmedia%26token%3D61ecc49c-95b8-4db7-8a89-b075b7fa0f95&width=752&dpr=3&quality=100&sign=855100c3&sv=2) **React Native** [](https://docs.tryterra.co/health-and-fitness-api/mobile-only-sources/flutter) ![Cover](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252F0dctvWjKHY7vVQVwtIrG%252Fflutter_logo.svg%3Falt%3Dmedia%26token%3D3dc959ed-94f8-4510-8748-bb9ee99cb074&width=752&dpr=3&quality=100&sign=6f2e3a8c&sv=2) **Flutter** [PreviousWriting datachevron-left](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/write-data) [NextiOS (Swift)chevron-right](https://docs.tryterra.co/health-and-fitness-api/mobile-only-sources/ios-swift) Last updated 8 months ago Was this helpful? Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Troubleshooting | Terra Docs Some users may inquire about missing data, and you may not be sure what's going on. Here are a few common issues & debugging steps. circle-info [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#no-data-events-common-reasons) No Data Events: Common Reasons ------------------------------------------------------------------------------------------------------------------------------------------ Terra sends data automatically as soon as it is available on a data source's cloud. Here are a few potential reasons why you're not receiving Data Events: 1. If the user has connected to the wrong account. 2. If the wearable hasn't synced to the respective app on the end user's phone, or if the app has not synced to the cloud, Terra will be unable to retrieve that data. 3. If you have not completed additional destination configurations (e.g. to [integrations requiring dedicated credentials](https://docs.tryterra.co/health-and-fitness-api/integration-setup) ). 4. If your Destination is incorrectly configured. If this is the case, you can see 400 or 500 errors on your [Terra Dashboard > Payload Historyarrow-up-right](https://dashboard.tryterra.co/dashboard/debug) . circle-check [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#no-data-events-possible-solutions) **No Data EVENTS: Possible Solutions** ------------------------------------------------------------------------------------------------------------------------------------------------------ * Wait a bit longer to rule out regular data delays from the data sources. * Try to **force** **a** **sync** (using a "pull down to sync" feature or equivalent available in most apps) * In order to verify if the data has synced to the respective cloud, you may instruct the **user** to go on their **web** **dashboard** for their device using a browser to verify the data is present. * Submit a **Support** **Ticket** via your **Terra** **Dashboard** if you are unsure. [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#id-1.-user-has-logged-in-with-the-wrong-account) 1\. User has logged in with the wrong account --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#this-happens-more-often-than-youd-think) (This happens more often than you'd think) Some users may have logged in with the wrong account. In order to verify the account that they're using matches with the Terra user ID that they've generated, you may follow the following procedure for the integrations below. #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#getting-the-accounts-user-id-on-the-providers-end) Getting the account's user ID on the provider's end Terra always provides a `user_id` for each connection. To get the user ID that the provider (e.g. Garmin, Fitbit etc) uses, you can use the [REST API Endpoints](https://docs.tryterra.co/reference#athlete) endpoint in order to retrieve that, which will be under the field `provider_user_id`. Once you have obtained that, follow the guidelines below for each provider. To get the user ID that the provider (e.g. Garmin, Fitbit etc) uses, you can use the [REST API Endpoints](https://docs.tryterra.co/reference#athlete) endpoint in order to retrieve that, which will be under the field `provider_user_id`. Once you have obtained that, follow the guidelines below for each provider. ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#fitbit) Fitbit Launch your Fitbit app (make sure you're using the latest Fitbit app version), click your Fitbit avatar in the top left corner, then click your Fitbit display name to view your profile. Then Click "Personal" and go to the next page, your Fitbit User ID is located at the bottom. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Ffiles.readme.io%2F369b62f-image.png&width=300&dpr=3&quality=100&sign=82275983&sv=2) Check to make sure your user's Fitbit user ID matches the one retrieved by the [REST API Endpoints](https://docs.tryterra.co/reference#athlete) endpoint ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#myfitnesspal) MyFitnessPal Using the `provider_user_id` obtained above, navigate to [https://www.myfitnesspal.com/food/diary/{provider\_user\_id}arrow-up-right](https://www.myfitnesspal.com/food/diary/%7Bprovider_user_id%7D) . #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#id-1.-invalid-username) 1\. Invalid username Seeing a page like this: ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Ffiles.readme.io%2Fb2e0cc6-image.png&width=300&dpr=3&quality=100&sign=fe023ed0&sv=2) indicates that the username entered by the end user is invalid. In the case above, the user accidentally entered **their email** instead of **their username**. Have them log in once more, following the "how-to" guide presented in the login screen #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#id-2.-disabled-diary-sharing) 2\. Disabled diary sharing The page below: ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Ffiles.readme.io%2F9e78b18-image.png&width=300&dpr=3&quality=100&sign=a11a8f03&sv=2) Indicates the user failed to enable diary sharing/disabled it since they authenticated through Terra. In order to remediate this, have the user re-enable diary sharing with the same password used during initial authentication, or have them re-authenticate after having enabled diary sharing as per the "how-to" guide in the login screen [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#id-2.-user-needs-to-follow-additional-steps) 2\. User needs to follow additional steps ------------------------------------------------------------------------------------------------------------------------------------------------------------------- In those cases the first step is always to ensure that the data is showing up in the partner app (e.g. Garmin Connect, Fitbit, etc..). Next would be to check if the data is correctly synchronized with the partner cloud, by using their web portal. ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#garmin) Garmin Ensure that the data is showing up in [the Garmin connect web dashboardarrow-up-right](https://connect.garmin.com/modern/) . If not, then pull down from the top in the Garmin connect mobile app, and hit the circle arrow until everything refreshes. If the data shows up in the web dashboard for Garmin Connect, but not through the API after 1-2 minutes, please contact support. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Ffiles.readme.io%2F3efde45-ezgif.com-optimize.gif&width=300&dpr=3&quality=100&sign=8bef7c73&sv=2) ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#apple-health) Apple Health The most likely culprit would be background app refresh being turned on/background updates not working as expected. In order to verify this, first request a backfill (requires TerraiOS >= 1.6.12) through your Terra Dashboard, in Tools > Debug > Users for that specific `user_id`. If data does come through, this means that background delivery is not operating as expected. To Troubleshoot, follow the steps below. #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#culprit-1-battery-saving-mode-is-on) Culprit 1: Battery saving mode is on For this, have the user go to Settings > Battery, and make sure "Low Power Mode" is turned **OFF** #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#culprit-2-background-app-refresh-is-turned-off-for-your-app) Culprit 2: Background app refresh is turned off for your app For this, have the user visit Settings > General > Background App Refresh, and verify that your app is toggled on ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Ffiles.readme.io%2F27bfad6-RPReplay_Final1719410146-ezgif.com-optimize.gif&width=300&dpr=3&quality=100&sign=c26f3ce&sv=2) ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#google-fit) Google Fit Go inside the Google Fit app, and ensure that your data is up to date on the display. Thereafter, pull down from the top of the screen to synchronize with the cloud. Please note that even after that, there can be some delay for Google to make the data available through their API. You should be able to see that data after at most 30-60 minutes in most cases. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Ffiles.readme.io%2F28c7b76-RPReplay_Final1719407216-ezgif.com-optimize.gif&width=300&dpr=3&quality=100&sign=787c4739&sv=2) #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#ios-specific) iOS-specific Ensure background app refresh is turned on for Google Fit ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Ffiles.readme.io%2F27bfad6-RPReplay_Final1719410146-ezgif.com-optimize.gif&width=300&dpr=3&quality=100&sign=c26f3ce&sv=2) [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#id-3.-mobile-sdk-known-issues) 3\. Mobile SDK Known Issues --------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#google-fit-sdk-samsung-health-health-connect-hc-based-integrations) Google Fit (SDK), Samsung Health: Health Connect (HC)-based integrations Currently these integrations go through the newly developed Health Connect platform, which is an on-device storage system developed by Google. This platform however is still in its infancy, and comes with a number of issues. triangle-exclamation #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#health-connect-known-issues) Health connect known issues We have seen numerous cases of apps not being able to sync into Health Connect due to bugs in the Health Connect platform itself. This could be, for example, Samsung Health not being able to send **steps** into HC. We've also seen cases where HC data simply could not be accessed, for no apparent reason, leading to limited or no syncing of data possible. Before going LIVE (release), you will ALSO need to apply for permissions to access the Health Connect API with Google. Use [this application formarrow-up-right](https://docs.google.com/forms/d/1LFjbq1MOCZySpP5eIVkoyzXTanpcGTYQH26lKcrQUJo/viewform?edit_requested=true) . In the form, you will need to specify which data types you intend to read from Health Connect. [PreviousFlutterchevron-left](https://docs.tryterra.co/health-and-fitness-api/mobile-only-sources/flutter) [NextPricingchevron-right](https://docs.tryterra.co/health-and-fitness-api/pricing) Last updated 1 month ago Was this helpful? * [1\. User has logged in with the wrong account](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#id-1.-user-has-logged-in-with-the-wrong-account) * [Fitbit](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#fitbit) * [MyFitnessPal](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#myfitnesspal) * [2\. User needs to follow additional steps](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#id-2.-user-needs-to-follow-additional-steps) * [Garmin](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#garmin) * [Apple Health](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#apple-health) * [Google Fit](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#google-fit) * [3\. Mobile SDK Known Issues](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#id-3.-mobile-sdk-known-issues) * [Google Fit (SDK), Samsung Health: Health Connect (HC)-based integrations](https://docs.tryterra.co/health-and-fitness-api/debugging-faq#google-fit-sdk-samsung-health-health-connect-hc-based-integrations) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Event Types | API Reference | Terra Docs circle-info Every request made to Terra, and every event sent from Terra will contain a `terra-reference` header containing a unique identifier for the request or event. The `terra-reference` identifier uniquely ties together a request -> event pair, whenever a request for data leads to data being asynchronously sent to your server. This can be useful for keeping track of whether or not a data transfer request has been fulfilled, or is still pending transfer Type Explanation `auth` Occurs when a user attempts to authenticate `deauth` Occurs when a user deauthenticates through the Terra `user_reauth` Occurs when a user successfully authenticates for a second time, with the same account. You will receive a successful `auth` and a `user_reauth` payload `access_revoked` Occurs when a user revokes Terra's access from the provider's end `connection_error` Occurs when a request to a provider returns an HTTP response of 401, 403 or 412 `google_no_datasource` Occurs when a Google Fit user doesn't have a data source linked to their account. All data requests for the user will be empty unless they link a data source `processing` Occurs when data is being fetched asynchronously from the provider. The data will be sent through automatically via your [Destination](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) , and you can also safely request for it after the time in the `retry_after_seconds` field. `large_request_sending` Occurs when more than one month of data has been requested and all data has been successfully submitted `rate_limit_hit` Occurs when an asynchronous request has failed due to rate limiting and is going to be retried. `large_request_processing` Occurs when more a request for over one month of data has been submitted to Terra. Data will be sent in chunks with the same reference field after this request. Each chunk will be at most 10 objects in the `data` field or 10 MB in size, whichever limit gets hit first `activity`, `athlete`, `body`, `daily`, `menstruation`, `nutrition`, `sleep` Occurs throughout the day as users use their wearables. `activity` updates when new activity is completed `healthcheck` Healthcheck event sent periodically to verify your event is functional `s3_upload` Data event sent as a download link. [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#misc) Misc ----------------------------------------------------------------------------------------------- chevron-rightHealthcheck[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#healthcheck) **Slug:** `healthcheck` **Trigger:** This will periodically be sent to your [destination](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) to confirm its health status **Recommended action:** **N/A** **Format:** Copy { "type": "healthcheck", "status": String, "creation_timestamp": String, "trend_percentage": Number, "sent_webhooks_last_hour": Number } [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#authentication) Authentication ------------------------------------------------------------------------------------------------------------------- chevron-rightDevice account connection success/failure[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#device-account-connection-success-failure) **Slug:** `auth` **Trigger:** A user just finished going through connecting a device account to your app **Recommended action:** If `status` = `success`, save the [user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) to your database. Use the `reference_id` parameter to link this back to an [end user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#end-user) profile in your app. If `status` = `error`, do nothing and treat this as an informational event **Format:** chevron-rightDevice account disconnection/deauthentication[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#device-account-disconnection-deauthentication) **Slug:** `deauth` **Trigger:** A user just disconnected their device account from your app **Recommended action:** Remove the user from your database using the `user_id` field and remove all their data records according to your data retention policy. **Format:** chevron-rightDevice account re-authentication[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#device-account-re-authentication) **Slug:** `user_reauth` **Trigger:** A user just connected a wearable account to your app which was previously already linked to you. **Recommended action:** Remove the `old_user` record from your database using the `user_id` field Replace all references of the `user_id` from `old_user` with the `user_id` from `new_user` **Format:** chevron-rightUser access revoked[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#user-access-revoked) **Slug:** `access_revoked` **Trigger:** A user revoked access to data access for your app through their wearable app's settings **Recommended action:** Remove the user from your database and remove all their data records according to your data retention policy. **Format:** chevron-rightUser data connection error[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#user-data-connection-error) **Slug:** `connection_error` **Trigger:** A user potentially revoked access to data access for your app through their wearable app's settings, or modified their credentials in a way which invalidated the tokens for data access. Unlike [User access revoked](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#user-access-revoked) , Terra cannot determine for sure that this was due to the user explicitly removing access for your app, or that this isn't a temporary connection error. **Recommended action:** Remove the user from your database, and ask the user to re-connect their device. You may need remove all their data records according to your data retention policy. **Format:** chevron-rightNo datasource available[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#no-datasource-available) **Slug:** `google_no_datasource` **Trigger:** A user was just created, but has no data sources associated with their account. **Recommended action:** Inform the user they do not have any data sources associated with their Google Fit account, and you may not receive data for them as a result. Keep a log of this for future reference (e.g. if the [end user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#end-user) logs a support ticket regarding this) **Format:** chevron-rightPermission change[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#permission-change) **Slug:** `permission_change` **Trigger:** A user has authenticated a second time, potentially on a separate dev ID, and modified the permissions granted to Terra **Recommended action:** Log this as an informational bit of data, which would help understand why some data type(s) are no longer provided down the line. **Format:** [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#data-requests) Data requests ----------------------------------------------------------------------------------------------------------------- chevron-rightRequest processing[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#request-processing) **Slug:** `google_no_datasource` **Trigger:** Terra needs to fetch data asynchronously from the data provider. This is an HTTP-only event (only returned as an HTTP response, and never sent as an [event](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#event) to your [destination](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) ) **Recommended action:** * Await for the data to arrive in your destination * Request for it after (at worst) the time allotted in the `retry_after_seconds` field. **Format:** chevron-rightLarge request processing[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#large-request-processing) **Slug:** `large_request_processing` **Trigger:** A [large request](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#large-request) has been submitted to Terra, and is being processed. A [`large_request_sending`](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#large-request-sending) [event](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#event) will follow **Recommended action:** Await for data chunks to be sent. Use the `terra_reference` to keep track of any events tied back to the initial request. The `terra_reference` will match the one in the response to the initial HTTP request. **Format:** chevron-rightLarge request sending[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#large-request-sending) **Slug:** `large_request_sending` **Trigger:** A [large request](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#large-request) has been submitted to Terra, and data pertaining to it is about to be sent. [Data chunks](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#data-types) will be sent to your [destination](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) following this [event](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#event) , all with the same `terra_reference` header **Recommended action:** Await for data chunks to be sent. Use the `terra_reference` header or `reference` field to tie those back to the initial request. The `reference` will match the `terra-reference` header in the response to the initial HTTP request. You may keep track of the sync progress using the `expected_payloads` field, which indicates how many [data events](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#data-events) will follow **Format:** chevron-rightRate limit hit[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#rate-limit-hit) **Slug:** rate\_limit\_hit **Trigger:** Rate limits for the data provider were hit during an asynchronous request. Terra will reschedule the request for a later time **Recommended action:** Keep a log of this occurrence **Format:** [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#data-events) Data events ------------------------------------------------------------------------------------------------------------- chevron-rightActivity[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#activity) **Slug:** `activity` **Trigger:** New activity records are available for the [user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) account **Recommended action:** Save the data in your database, and overwrite previous records based off the `metadata.summary_id` entry **Format:** chevron-rightAthlete[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#athlete) **Slug:** `athlete` **Trigger:** New data is available for the [user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) account **Recommended action:** Save the data in your database **Format:** chevron-rightBody[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#body) **Slug:** `body` **Trigger:** New body data is available for the [user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) account **Recommended action:** Save the data in your database, and overwrite previous records based off the `metadata.start_time` entry **Format:** chevron-rightDaily[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#daily) **Slug:** `daily` **Trigger:** New daily activity summary data is available for the [user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) account **Recommended action:** Save the data in your database, and overwrite previous records based off the `metadata.start_time` entry **Format:** chevron-rightMenstruation[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#menstruation) **Slug:** `menstruation` **Trigger:** New menstruation data is available for the [user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) account **Recommended action:** Save the data in your database, and overwrite previous records based off the `metadata.start_time` entry **Format:** chevron-rightNutrition[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#nutrition) **Slug:** `nutrition` **Trigger:** New nutrition records are available for the [user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) account **Recommended action:** Save the data in your database, and overwrite previous records based off the `metadata.start_time` entry **Format:** chevron-rightSleep[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#sleep) **Slug:** `sleep` **Trigger:** New sleep records are available for the [user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) account **Recommended action:** Save the data in your database, and overwrite previous records based off the `metadata.summary_id` entry **Format:** chevron-rightS3 Upload[hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#s3-upload) **Slug:** `s3_payload` **Trigger:** New data (activity/daily/body/sleep/nutrition/menstruation) records are available for the [user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) account **Recommended action:** Make a request to the `url` provided, and handle the resulting payload as you would one of the above [Data events](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#data-events) (i.e. save the data in your database, and overwrite previous records based off the `metadata.summary_id` /`metadata.start_time` entry) **Format:** [PreviousSupported integrationschevron-left](https://docs.tryterra.co/reference/health-and-fitness-api/supported-integrations) [NextData modelschevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/data-models) Last updated 8 months ago Was this helpful? * [Misc](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#misc) * [Authentication](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#authentication) * [Data requests](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#data-requests) * [Data events](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#data-events) Was this helpful? sun-brightdesktopmoon Copy { "type": "auth", "user": User, "status": "success", "reference_id": String, "widget_session_id": String } Copy { "type": "auth", "user": User, "provider": "GARMIN" }, "status": "error", "message": "User failed to authenticate and has been deleted", "reason": String, "reference_id": String, "widget_session_id": String } Copy { "type": "deauth", "user": User, "status": "success", "message": "User has deauthenticated" } Copy { "type": "user_reauth", "new_user": User, "old_user": User, "status": "warning", "message": "User has reauthenticated and old ID has been deleted" } Copy { "type": "access_revoked", "user": User, "status": "warning", "message": "User revoked access" } Copy { "type": "connection_error", "user": User, "status": "warning", "message": "User connection degraded" } Copy { "type": "connection_error", "user": User, "status": "warning", "message": "User connection degraded" } Copy { "type": "permission_change", "user": User, "status": "warning", "message": "User permissions have been modified", "version": "2022-03-16", "scopes_added": "fitness.blood_glucose.read", "scopes_removed": "fitness.oxygen_saturation.read" } Copy { "type": "processing", "status": "success", "message": "Request is processing, try again later", "user": TerraUser, "retry_after_seconds": Number, } Copy { "type": "large_request_processing", "status": "processing", "message": "Large request is processing", "user": TerraUser, "reference": String } Copy { "user": User, "reference": String, "message": "Large request is being sent", "expected_payloads": Number, "type": "large_request_sending", } Copy { "user": User, "start_date": DateTime, "end_date": DateTime, "retrying_at": DateTime, "message": "Rate limit reached whilst processing async query", "type": "rate_limit_hit", } Copy { "data": [Activity], "user": User, "type": "activity", "version": String } Copy { "athlete": Athlete, "user": User, "type": "athlete", "version": String } Copy { "data": [Body], "user": User, "type": "body", "version": String } Copy { "data": [Daily], "user": User, "type": "daily", "version": String } Copy { "data": [Menstruation], "user": User, "type": "menstruation", "version": String } Copy { "data": [Nutrition], "user": User, "type": "nutrition", "version": String } Copy { "data": [Sleep], "user": User, "type": "sleep", "version": String } Copy { "status": "success", "type": "s3_payload", "url": "https://example.com", "expires_in": 300, } sun-brightdesktopmoon --- # Supported integrations | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/supported-integrations#integrations-list) Integrations List ------------------------------------------------------------------------------------------------------------------------------------ circle-info **Event-Driven** integrations update instantly as soon as new data is available **Periodically** fetched integrations are polled by Terra every 5-10 minutes for new data **Managed** credentials for integrations mean that you may create your own credentials and provide them to Terra, using the integration's developer dashboard Integration Name Enum Value Data Sync Method Integration credentials Developer portal Apple APPLE Event-Driven N/A Biostrap BIOSTRAP Periodically fetched Managed [https://app.biostrap.com/loginarrow-up-right](https://app.biostrap.com/login) Cardiomood CARDIOMOOD Periodically fetched N/A Concept2 CONCEPT2 Periodically fetched Managed [https://log.concept2.com/developers/keysarrow-up-right](https://log.concept2.com/developers/keys) Coros COROS Periodically fetched Managed [https://support.coros.com/hc/en-us/articles/17085887816340-Submit-an-API-Applicationarrow-up-right](https://support.coros.com/hc/en-us/articles/17085887816340-Submit-an-API-Application) Core CORE Periodically fetched N/A Cronometer CRONOMETER Event-Driven Managed Case by case. Contact Terra Support to be intro'd to Cronometer team Dexcom DEXCOM Periodically fetched Required [https://developer.dexcom.com/docs/dexcom/getting-started/arrow-up-right](https://developer.dexcom.com/docs/dexcom/getting-started/) Dexcom EU DEXCOM\_EU Periodically fetched Required See above & contact Dexcom support Dexcom JP DEXCOM\_JP Periodically fetched Required See above & contact Dexcom support EatThisMuch EATTHISMUCH Periodically fetched N/A FatSecret FATSECRET Periodically fetched Managed [https://platform.fatsecret.com/registerarrow-up-right](https://platform.fatsecret.com/register) FinalSurge FINALSURGE Periodically fetched N/A Fitbit FITBIT Event-Driven Managed [https://dev.fitbit.com/appsarrow-up-right](https://dev.fitbit.com/apps) FreeStyleLibre FREESTYLELIBRE Periodically fetched Managed [https://www.libreview.com/createPracticearrow-up-right](https://www.libreview.com/createPractice) Garmin GARMIN Event-Driven Managed [https://developerportal.garmin.comarrow-up-right](https://developerportal.garmin.com/) Google Fit (Health Connect-based) GOOGLEFIT Periodically fetched N/A Google Fit GOOGLE Periodically fetched Managed [https://console.cloud.google.com/apis/api/fitness.googleapis.comarrow-up-right](https://console.cloud.google.com/apis/api/fitness.googleapis.com) Hammerhead HAMMERHEAD Periodically fetched N/A Huawei HUAWEI Event-Driven Required [https://developer.huawei.com/consumer/en/hms/huaweihealth/arrow-up-right](https://developer.huawei.com/consumer/en/hms/huaweihealth/) InBody INBODY Periodically fetched Required [https://inbodyusa.com/web-api/arrow-up-right](https://inbodyusa.com/web-api/) Komoot KOMOOT Periodically fetched N/A LiveRowing LIVEROWING Periodically fetched N/A Lezyne LEZYNE Periodically fetched N/A Moxy MOXY Periodically fetched N/A MapMyFitness MAPMYFITNESS Periodically fetched Managed [https://developer.mapmyfitness.com/requestkey/arrow-up-right](https://developer.mapmyfitness.com/requestkey/) MyFitnessPal MYFITNESSPAL Periodically fetched N/A NutraCheck NUTRACHECK Periodically fetched Managed Case by case. Contact Terra Support to be intro'd Omron OMRON Periodically fetched Managed [https://omronhealthcare.com/api/arrow-up-right](https://omronhealthcare.com/api/) Omron US OMRONUS Periodically fetched Managed [https://omronhealthcare.com/api/arrow-up-right](https://omronhealthcare.com/api/) Oura OURA Event-Driven Managed [https://cloud.ouraring.com/oauth/applicationsarrow-up-right](https://cloud.ouraring.com/oauth/applications) Peloton PELOTON Periodically fetched N/A Polar POLAR Event-Driven Managed [https://admin.polaraccesslink.com/arrow-up-right](https://admin.polaraccesslink.com/) Pūl PUL Event-Driven Managed Case by case. Contact Terra Support to be intro'd RideWithGPS RIDEWITHGPS Periodically fetched N/A Rouvy ROUVY Periodically fetched N/A Samsung SAMSUNG Event-Driven Required [https://developer.samsung.com/SHealth/business-partner/m48wvqi1mt9w2w4c arrow-up-right](https://developer.samsung.com/SHealth/business-partner/m48wvqi1mt9w2w4c) Suunto SUUNTO Event-Driven Managed Applications no longer open Technogym TECHNOGYM Periodically fetched N/A Tempo TEMPO Periodically fetched N/A TriDot TRIDOT Periodically fetched N/A Tredict TREDICT Periodically fetched Managed Case by case. Contact Terra Support to be intro'd TrainingPeaks TRAININGPEAKS Event-Driven Managed Case by case. Contact Terra Support to be intro'd TrainAsOne TRAINASONE Periodically fetched N/A TrainerRoad TRAINERROAD Periodically fetched N/A Virtuagym VIRTUAGYM Periodically fetched Required [https://virtuagym.com/public-apiarrow-up-right](https://virtuagym.com/public-api) Wahoo WAHOO Event-Driven Managed [https://developers.wahooligan.com/applicationsarrow-up-right](https://developers.wahooligan.com/applications) Whoop WHOOP Event-Driven Required [https://external-developer-portal.whoop.com/arrow-up-right](https://external-developer-portal.whoop.com/) Catapult One CATAPULTONE Periodically fetched N/A Withings WITHINGS Event-Driven Managed [https://developer.withings.com/dashboard/welcomearrow-up-right](https://developer.withings.com/dashboard/welcome) Xoss XOSS Periodically fetched N/A Zepp ZEPP Periodically fetched Managed Applications not currently open Zwift ZWIFT Periodically fetched N/A Xert XERT Periodically fetched N/A BrytonSport BRYTONSPORT Periodically fetched N/A TodaysPlan TODAYSPLAN Periodically fetched N/A Tenovi TENOVI Event-Driven Managed Case by case. Contact Terra Support to be intro'd Wger WGER Periodically fetched N/A VeloHero VELOHERO Periodically fetched N/A Cycling Analytics CYCLINGANALYTICS Periodically fetched Managed [https://www.cyclinganalytics.com/developer/api/app-creationarrow-up-right](https://www.cyclinganalytics.com/developer/api/app-creation) Nolio NOLIO Periodically fetched Managed [https://www.nolio.io/api/arrow-up-right](https://www.nolio.io/api/) TrainXhale TRAINXHALE Periodically fetched N/A KetoMojo US KETOMOJOUS Periodically fetched Managed [https://keto-mojo.com/developers/arrow-up-right](https://keto-mojo.com/developers/) KetoMojo EU KETOMOJOEU Periodically fetched Managed [https://keto-mojo.com/developers/arrow-up-right](https://keto-mojo.com/developers/) Strava STRAVA Event-Driven Required [https://strava.com/settings/apiarrow-up-right](https://strava.com/settings/api) Clue CLUE Periodically fetched N/A Health Gauge HEALTHGAUGE Periodically fetched N/A MacrosFirst MACROSFIRST Periodically fetched Managed Case by case. Contact Terra Support to be intro'd Somnofy SOMNOFY Periodically fetched N/A Aktiia AKTIIA Periodically fetched N/A Decathlon DECATHLON Periodically fetched Managed Case by case. Contact Terra Support to be intro'd Flo FLO Periodically fetched N/A MapMyTracks MAPMYTRACKS Periodically fetched N/A Insiders INSIDERS Periodically fetched N/A Elite HRV ELITEHRV Periodically fetched N/A [PreviousOpenAPI Specchevron-left](https://docs.tryterra.co/reference/health-and-fitness-api/openapi-spec) [NextEvent Typeschevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/event-types) Last updated 4 months ago Was this helpful? Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Core Concepts | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/streaming-api/core-concepts#data-stream) Data Stream ------------------------------------------------------------------------------------------------------ The continuous flow of heart rate data from the user's wearable device. The data moves through Terra's system and reaches the developer's backend in real time via a WebSocket connection. As long as the connection is open, the data keeps coming without needing to ask for it again. Think of it like a pipe, to which multiple [producers](https://docs.tryterra.co/reference/streaming-api/core-concepts#producer) can pump data into, and multiple [consumers](https://docs.tryterra.co/reference/streaming-api/core-concepts#consumer) can connect to in order to receive that data. [hashtag](https://docs.tryterra.co/reference/streaming-api/core-concepts#producer) Producer ------------------------------------------------------------------------------------------------ The **producer** is the Terra Real-Time SDK, which collects heart rate data (or other supported data types) from the wearable device and sends it to Terra’s API. It connects to the wearable using technologies like Bluetooth and ensures the data is constantly transmitted. [hashtag](https://docs.tryterra.co/reference/streaming-api/core-concepts#consumer) Consumer ------------------------------------------------------------------------------------------------ Your system that receives the heart rate data from Terra’s API. Once connected, it gets the data in real time and can use it in the app, display it to users, or store it for later use. [hashtag](https://docs.tryterra.co/reference/streaming-api/core-concepts#broker) Broker -------------------------------------------------------------------------------------------- In the context of Terra API, the **broker** is the intermediary that manages the real-time data stream between producers and consumers. Terra API acts as the broker by receiving data from [producer connections](https://docs.tryterra.co/reference/streaming-api/core-concepts#producer) (the TerraRT SDK in your mobile app) and distributing it to [consumer connections](https://docs.tryterra.co/reference/streaming-api/core-concepts#consumer) (e.g., your application’s backend). [hashtag](https://docs.tryterra.co/reference/streaming-api/core-concepts#phone) Phone ------------------------------------------------------------------------------------------ In the context of this documentation, an Android/iOS device will be referred to as a phone. This will be an iOS or Android phone which connects to a streaming wearable, and sends data to the [broker](https://docs.tryterra.co/reference/streaming-api/core-concepts#broker) . You can think of the device itself as being a [producer](https://docs.tryterra.co/reference/streaming-api/core-concepts#producer) for all intents and purposes. [hashtag](https://docs.tryterra.co/reference/streaming-api/core-concepts#device) Device -------------------------------------------------------------------------------------------- For all intents and purposes throughout this documentation, a device will be any wearable capable of streaming data through either a BLE or ANT+ connection. If the wearable is a Watch OS, Apple Watch, or Samsung wearable (which have a special connection & data streaming process), this will be explicitly made clear [hashtag](https://docs.tryterra.co/reference/streaming-api/core-concepts#data-transfer-protocols) Data transfer Protocols ------------------------------------------------------------------------------------------------------------------------------ These are means by which a [wearable](https://docs.tryterra.co/reference/streaming-api/core-concepts#wearable) will transfer data to a user's [phone](https://docs.tryterra.co/reference/streaming-api/core-concepts#phone) , and can take one of the following forms. * Bluetooth Low Energy (BLE) - most popular * ANT+ - allows one-to-many broadcasting of data * Custom Bluetooth protocols (Apple Watch, WatchOS, Samsung Watch...) [PreviousSupported Integrationschevron-left](https://docs.tryterra.co/reference/streaming-api/supported-integrations) [NextWebsocket Referencechevron-right](https://docs.tryterra.co/reference/streaming-api/websocket-reference) Was this helpful? * [Data Stream](https://docs.tryterra.co/reference/streaming-api/core-concepts#data-stream) * [Producer](https://docs.tryterra.co/reference/streaming-api/core-concepts#producer) * [Consumer](https://docs.tryterra.co/reference/streaming-api/core-concepts#consumer) * [Broker](https://docs.tryterra.co/reference/streaming-api/core-concepts#broker) * [Phone](https://docs.tryterra.co/reference/streaming-api/core-concepts#phone) * [Device](https://docs.tryterra.co/reference/streaming-api/core-concepts#device) * [Data transfer Protocols](https://docs.tryterra.co/reference/streaming-api/core-concepts#data-transfer-protocols) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Mobile SDK | API Reference | Terra Docs [apple-wholeiOS (Swift)chevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift) [androidAndroid (Kotlin)chevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin) [reactReact Nativechevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native) [flutterFlutterchevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter) [PreviousDestinationschevron-left](https://docs.tryterra.co/reference/health-and-fitness-api/destinations) [NextiOS (Swift)chevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift) Was this helpful? Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Mobile SDK | API Reference | Terra Docs [apple-wholeiOS (Swift)chevron-right](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift) [androidAndroid (Kotlin)chevron-right](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin) [flutterFlutterchevron-right](https://docs.tryterra.co/reference/streaming-api/reference/flutter) [reactReact Nativechevron-right](https://docs.tryterra.co/reference/streaming-api/reference/react-native) [PreviousWebsocket Referencechevron-left](https://docs.tryterra.co/reference/streaming-api/websocket-reference) [NextiOS (Swift)chevron-right](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift) Last updated 1 year ago Was this helpful? Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # REST API Endpoints | API Reference | Terra Docs Error while loading OpenAPI operation — Failed to fetch OpenAPI file ### [hashtag](https://docs.tryterra.co/reference/streaming-api/api-endpoints#post-auth-developer) Stream - Generate developer token post https://ws.tryterra.co/auth/developer Endpoint for generation of a token for a developer (consumer) connection Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Header parameters dev-idstringRequired your developer ID x-api-keystringRequired your API key Responses chevron-right 200 Successful response application/json Responseobject Show propertiesplus chevron-right 403 Forbidden text/plain post /auth/developer HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Successful response chevron-down ### [hashtag](https://docs.tryterra.co/reference/streaming-api/api-endpoints#post-auth-user) Stream - Generate user token post https://ws.tryterra.co/auth/user Endpoint for generation of a token for a user (producer) connection Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Query parameters idstringOptional The ID of the user to generate a token for Header parameters dev-idstringRequired your developer ID x-api-keystringRequired your API key Responses chevron-right 200 Successful response application/json Responseobject Show propertiesplus chevron-right 403 Forbidden text/plain post /auth/user HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Successful response chevron-down [PreviousFlutterchevron-left](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter) [NextSupported Integrationschevron-right](https://docs.tryterra.co/reference/streaming-api/supported-integrations) Was this helpful? * [POSTStream - Generate developer token](https://docs.tryterra.co/reference/streaming-api/api-endpoints#post-auth-developer) * [POSTStream - Generate user token](https://docs.tryterra.co/reference/streaming-api/api-endpoints#post-auth-user) Was this helpful? sun-brightdesktopmoon Copy POST /auth/developer HTTP/1.1 Host: ws.tryterra.co x-api-key: text dev-id: text Accept: */* Copy { "token": "cG9RvLY5.yvKm778XMIPm1ig93BJEoRCVGHzlrBNjzWdeXePTaMM" } Copy POST /auth/user HTTP/1.1 Host: ws.tryterra.co x-api-key: text dev-id: text Accept: */* Copy { "token": "OTYwNWFi5ZWQMTAxMjg0Y2Qw.gzrPzZcS3Gy8QDOxbiPRwu30PTB3VxW0eE" } sun-brightdesktopmoon --- # Core concepts | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#developer-id-dev-id) Developer ID (Dev ID) --------------------------------------------------------------------------------------------------------------------------------- Your developer ID is your unique identifier for access to the API. This is how Terra identifies you, and ties [Users](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) & their data back to you. circle-info Think of your dev ID like your username It does not constitute sensitive information. Making it publicly available is not a security conern You may find your dev ID in the credentials section of your Terra Dashboard account [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#api-key) API Key ------------------------------------------------------------------------------------------------------- Your API key is your secret access token for the API. This is how Terra knows you're legitimately the developer behind the dev ID you're using. circle-info Think of your API Key like your **password** It constitutes sensitive information. Making it publicly available is a big security risk You may find your API Key in the credentials section of your Terra Dashboard account [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) Destinations ----------------------------------------------------------------------------------------------------------------- Terra sends data to your server through a **Destination**. At its most basic, this is a Webhook, but can also take the form of an SQL database, an Azure Blog storage, or an Amazon SQS queue. You can customize which **Destination** is active at any given time through your [Terra Dashboardarrow-up-right](https://dashboard.tryterra.co/dashboard/connections) . [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#source-provider-integration) Source/Provider/Integration ----------------------------------------------------------------------------------------------------------------------------------------------- A **Source** (also referred to as a **Provider,** or **Integration**) is a wearable fitness & health data supplier, such as Fitbit, Garmin or Apple Health. These can be turned on or off (enabling or interrupting the flow of data) through your [Terra Dashboardarrow-up-right](https://dashboard.tryterra.co/dashboard/connections) . Check out the list of supported integrations [here](https://docs.tryterra.co/reference/health-and-fitness-api/supported-integrations) [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) User ------------------------------------------------------------------------------------------------- Throughout this documentation, a connection made to one fitness wearable account (e.g. one Fitbit account, or one Garmin account) will be referred to as "one User". This means that multiple Users can be created for one individual, also referred to as an [End User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#end-user) . Any time a e.g. Fitbit/Garmin/Google Fit account is connected through Terra, a [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) is created [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#end-user) End User --------------------------------------------------------------------------------------------------------- An End User represents a person who may own one or more wearable devices, and can have multiple Users associated to them through Terra. [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#reference-id) Reference ID ----------------------------------------------------------------------------------------------------------------- You can use a Reference ID in order to tie a [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) back to an [End User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#end-user) . The `reference_id` should be the identifier of the End User on your systems. This could be the End User's username, their email address, or any way in which you identify them. When creating a User, you will have the option of passing in a `reference_id` to conveniently link it back to an End User [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#event) Event --------------------------------------------------------------------------------------------------- An **Event** is a piece of data (usually a JSON object) sent to your [Destination](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) . This can be one of the [Data Types](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#data-types) or a metadata event type [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#large-request) Large Request ------------------------------------------------------------------------------------------------------------------- A [data](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#data-types) request spanning more than 28 days (unless defined otherwise). This type of request will **always** be processed asynchronously, and sent to your [destinations](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) in chunks. The chunks sent to you will each be of either * at most 10MB * at most 10 objects within the `data` array whichever limit of the two gets hit first will determine the chunk's size [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#polled-event-driven-integrations) Polled/Event-Driven integrations --------------------------------------------------------------------------------------------------------------------------------------------------------- Integrations that are **Event-Driven** allow for the fastest data retrieval speeds. As soon as new data is synced from the user's wearable's app (e.g. the Fitbit app) to the [Provider's](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#source-provider-integration) cloud, a notification (or **event**) gets sent to Terra with the newest data, following which Terra sends you a [payload](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#payload) to your [Destination](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) with the latest available data. Integrations that are **Polled** do not have an event-sending system, and require Terra to periodically check for data updates by **polling** their servers. This will be done as often as **every 5 minutes**. [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#data-types) Data Types ------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#activity) Activity This represents a workout session completed (not currently active or planned) by the user, with a **defined start and end time**. For example, this corresponds to when a user woud press "start workout" on their Garmin smartwatch, go for a run, then press "end workout". ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#sleep) Sleep This represents a sleep session completed by the user. The start time and end time can be representative of the time that the user **got in bed** instead of the time that they **fell asleep** at, if tracked by the wearable device. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#daily) Daily This represents a summary of the total activity completed by a user for a given 24 hour period, defined by the **start and end time of the payload.** These payloads will be sent multiple times throughout a given day, as a user moves around, and will be a total of their activity **up until that point in the day**. When ingesting **Daily** events, always overwrite data for a given date with the latest one sent to your [Destination](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) . ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#menstruation) Menstruation This represents a day in the user's menstrual cycle, and includes information about that day within the context of their overall monthly cycle, such as current phase, and any metadata associated with that day (bleeding level, feelings of nausea, etc). ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#body) Body This represents the various Body metrics for a user for a given 24 hour period, defined by the **start and end time of the payload**. These payloads will be sent multiple times throughout a given day, as a user generates more body-related metrics (weigh-ins, blood glucose measurements etc), and will be a total **up until that point in the day**. When ingesting **Body** events, always overwrite data for a given date with the latest one sent to your [Destination](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) . ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#nutrition) Nutrition This represents the various food logged by a user for a given 24 hour period, defined by the **start and end time of the payload**. This will be data logged in Food Diary apps such as MyFitnessPal, Fitbit or MacrosFirst. Each `meal` represents a given food item logged within that day. [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#api-versions) API Versions ----------------------------------------------------------------------------------------------------------------- Terra API is versioned in two main ways. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#major-api-versions) Major API versions These API versions are **very** infrequent and represent a large architectural change in the API endpoints, and underlying infrastructure. You will identify these with the base URL (i.e. **api.tryterra.co/v2,** **api.tryterra.co/v1**, and **access.tryterra.co** are 3 separate major versions) ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#minor-api-versions) Minor API versions These can be identified by the `version` included in every payload you receive from Terra, and will be versioned by date. For example, at the time of writing, the latest API version is `2022-03-16`. The version prior to it was `2022-03-02`. Only breaking changes to the API are versioned. Any non breaking changes will be continuously developed, tested, and deployed. [PreviousSampleschevron-left](https://docs.tryterra.co/reference/health-and-fitness-api/samples) [NextDestinationschevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/destinations) Last updated 11 months ago Was this helpful? * [Developer ID (Dev ID)](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#developer-id-dev-id) * [API Key](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#api-key) * [Destinations](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) * [Source/Provider/Integration](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#source-provider-integration) * [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) * [End User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#end-user) * [Reference ID](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#reference-id) * [Event](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#event) * [Large Request](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#large-request) * [Polled/Event-Driven integrations](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#polled-event-driven-integrations) * [Data Types](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#data-types) * [Activity](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#activity) * [Sleep](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#sleep) * [Daily](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#daily) * [Menstruation](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#menstruation) * [Body](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#body) * [Nutrition](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#nutrition) * [API Versions](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#api-versions) * [Major API versions](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#major-api-versions) * [Minor API versions](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#minor-api-versions) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Supported Integrations | API Reference | Terra Docs * Apple watch * Series 1 through 11 (all models supported) * SE models (1st gen through 3rd gen) * Ultra models (1st gen through 3rd gen) * Bryton * Hammerhead * WearOS devices from WearOS 7 and above * Polar H10 * Polar OH1 * Polar Verity * Polar Sense * Polar H9 * All Garmin watches that support Heart rate broadcasting: [https://support.garmin.com/en-US/?faq=Zj1947s6pqAHzBCAhLhrC9arrow-up-right](https://support.garmin.com/en-US/?faq=Zj1947s6pqAHzBCAhLhrC9) * Garmin HRM dual, * Garmin HRM pro, * Garmin HRM pro plus * Ultrahuman Ring Air * Wahoo TICKER (FIT, X, X2) * Wahoo TICKER X * Wahoo TICKER 2 * Wahoo TICKER X2 * WHOOP 4.0, 5.0 * Xiaomi bands (5th gen through 10th gen) * Samsung (Watch 4 through Watch 8, FE, Ultra) * Suunto smart heart rate belt * MyZone (including Go, HRM MZ, HRM MZ-2, HRM MZ3) We offer real-time streaming from wearables that advertise BLE broadcasting for heart rate data. [PreviousREST API Endpointschevron-left](https://docs.tryterra.co/reference/streaming-api/api-endpoints) [NextCore Conceptschevron-right](https://docs.tryterra.co/reference/streaming-api/core-concepts) Last updated 5 days ago Was this helpful? Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # OpenAPI Spec | API Reference | Terra Docs All Terra OpenAPI specs can be found on GitHub: [https://github.com/tryterra/openapi/arrow-up-right](https://github.com/tryterra/openapi/) ![](https://images.gitbook.com/__img/width=256,format=auto,signature=485166135/https%3A%2F%2Ffiles.gitbook.com%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fintegrations%252Fgithub-files%252Ficon%252FyLv8rmwlZaZ4xBFdwZLt%252Ficon.png%3Falt%3Dmedia) https://github.com/tryterra/openapi/blob/master/v5.yaml [PreviousREST API Endpointschevron-left](https://docs.tryterra.co/reference) [NextSupported integrationschevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/supported-integrations) Last updated 1 month ago Was this helpful? Was this helpful? sun-brightdesktopmoon Copy openapi: 3.1.0 info: description: The Terra API title: TerraAPI version: 2022.03.16 license: name: "Apache-2.0" url: https://github.com/tryterra/openapi/blob/master/LICENSE termsOfService: https://tryterra.co/terms-of-service contact: name: Terra API url: https://tryterra.co/ email: "[email protected]" servers: - url: https://api.tryterra.co/v2 security: - ApiKeyAuth: [] - DevID: [] paths: /auth/authenticateUser: post: summary: Generate an authentication link description: Creates a login link that allows end users to connect their fitness tracking account tags: - Authentication operationId: Authentication_AuthenticateUser parameters: - name: resource in: query description: Provider resource identifier (e.g., 'FITBIT', 'GARMIN', 'OURA'). See "Get detailed list of integrations" for available providers schema: type: string example: FITBIT required: true - name: dev-id in: header description: your developer ID required: true schema: type: string example: testingTerra requestBody: content: application/json: schema: type: object properties: language: type: string reference_id: type: string auth_success_redirect_url: type: string auth_failure_redirect_url: type: string required: false responses: "200": description: Returned when authentication link could be successfully generated content: application/json: schema: type: object properties: status: type: string enum: [success, error] description: indicates that the request was successful example: success user_id: description: User ID for the user being created type: string example: 23dc2540-7139-44c6-8158-f81196e2cf2e auth_url: type: string description: authentication URL the user must be redirected to in order to link their account example: https://www.fitbit.com/oauth2/authorize?response_type=code&client_id=23BBG9&scope=settings+nutrition+sleep+heartrate+electrocardiogram+weight+respiratory_rate+oxygen_saturation+profile+temperature+cardio_fitness+activity+location&state=bLqqjPie9ptwoWm6VBxHCu6JkkoWJp "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "404": description: Returned when a parameter does not exist on Terra's end (e.g. resource) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [success, error] description: indicates that an error happened (value is error) /auth/generateWidgetSession: post: summary: Generate an authentication link, using the Terra Authentication Widget description: Generates a link to redirect an end user to for them to select an integration and log in with their fitness data provider tags: - Authentication operationId: Authentication_GenerateWidgetSession requestBody: content: application/json: schema: $ref: "#/components/schemas/WidgetSessionParams" required: true responses: "200": description: Returned when authentication link could be successfully generated content: application/json: schema: type: object properties: session_id: description: Session ID for the widget authentication session type: string example: 23dc2540-7139-44c6-8158-f81196e2cf2e url: type: string description: the widget URL the user must be redirected to in order to link their account example: https://widget.tryterra.co/session/344d475f-296a-489a-a88c-54183671dafd status: type: string enum: [success, error] description: indicates that the request was successful (value is success) example: success expires_in: type: number description: a number in seconds depicting how long the url is valid for example: 900 "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) /users/{user_id}: patch: summary: Modify user description: Update a Terra user's reference_id or active status tags: - User operationId: User_ModifyUser parameters: - name: user_id in: path description: Terra user ID to update required: true schema: type: string requestBody: required: false content: application/json: schema: type: object properties: reference_id: type: string description: Identifier on your system to associate with this user example: "updatedUser123" active: type: boolean description: Whether the user should remain active responses: "200": description: Returned upon successful user modification content: application/json: schema: type: object properties: user: $ref: "#/components/schemas/User" status: type: string enum: [success, error] description: Indicates that the request was successful example: success "400": description: Returned if the parameters are malformed or no user is found content: application/json: schema: type: object properties: message: description: A detailed message describing the error type: string status: type: string enum: [success, error] description: Indicates an error happened /auth/deauthenticateUser: delete: summary: Deauthenticates a user and deletes any cached data for them description: Deletes all records of the user on Terra's end, revoking Terra's access to their data tags: - Authentication operationId: Authentication_DeauthenticateUser parameters: - name: user_id in: query description: Terra user ID (UUID format) to deauthenticate and remove from Terra system schema: type: string required: true responses: "200": description: Returned when user is successfully deauthenticated and data is deleted content: application/json: schema: type: object properties: status: enum: [success, error] description: indicates that the deauthentication was successful (value is success) type: string "404": description: Returned when the user_id is not existent content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [success, error] description: indicates that an error happened (value is error) /auth/generateAuthToken: post: tags: - Authentication summary: Generates an authentication token for the Terra mobile SDKs description: Creates a token to be used with initConnection() functions in the Terra mobile SDKs in order to create a user record for Apple Health or Samsung Health (or equivalent) operationId: Authentication_GenerateAuthToken responses: "200": description: "200" content: application/json: examples: Result: value: status: success token: 250c68b9c21b78e40e7a3285a2d538d3bc24aabd3b4c76a782fb0a571ca4501d expires_in: 180 schema: type: object properties: status: type: string example: success token: type: string example: 250c68b9c21b78e40e7a3285a2d538d3bc24aabd3b4c76a782fb0a571ca4501d expires_in: type: integer example: 180 default: 0 "404": description: "404" content: application/json: examples: Result: value: status: "error" message: "Invalid dev-id was provided" schema: type: object properties: status: type: string example: error message: type: string example: Invalid dev-id was provided deprecated: false /activity: get: summary: Retrieve activity data for a given user ID description: Fetches completed workout sessions, with a defined start and end time and activity type (e.g. running, cycling, etc.) tags: - Activity operationId: Activity_Fetch parameters: - name: user_id in: query description: Terra user ID (UUID format) to retrieve data for schema: type: string required: true - name: start_date in: query description: Start date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: true - name: end_date in: query description: End date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: false - name: to_webhook in: query description: | Boolean flag specifying whether to send the data retrieved to the webhook instead of in the response (default: true if not provided) schema: type: boolean required: false - name: with_samples in: query description: | Boolean flag specifying whether to include detailed samples in the returned payload (default: false) schema: type: boolean required: false responses: "200": description: Returned upon successful data request content: application/json: schema: oneOf: - type: object properties: user: $ref: "#/components/schemas/User" data: type: array items: $ref: "#/components/schemas/Activity" type: type: [string, "null"] - $ref: "#/components/schemas/NoDataReturned" - $ref: "#/components/schemas/DataSentToWebhook" - $ref: "#/components/schemas/RequestProcessing" - $ref: "#/components/schemas/RateLimitRequestProcessing" - $ref: "#/components/schemas/LargeRequestProcessingResponse" "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "401": description: Returned when credentials (dev ID and API key) are invalid content: application/json: schema: type: object properties: message: description: An error message type: string example: unauthorized "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) post: tags: - Activity operationId: Activity_Write description: Used to post activity data to a provider. This endpoint only works for users connected via Wahoo. Returns error for other providers. summary: Post activity data to a provider requestBody: content: application/json: schema: type: object properties: data: description: List of user-tracked workouts to post to data provider type: array items: $ref: "#/components/schemas/Activity" required: - data required: true responses: "201": description: Returned when activity was successfully created on the provider content: application/json: schema: type: object properties: user: $ref: "#/components/schemas/User" log_ids: description: List of identifiers for the objects created, returned in the same order they were posted. I.e. Posting [ObjectA, ObjectB] will return [IdentifierA, IdentifierB] type: array items: type: string message: type: string default: Activity successfully logged "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) /athlete: get: summary: Retrieve user profile info for a given user ID description: Fetches relevant profile info such as first & last name, birth date etc. for a given user ID tags: - Athlete operationId: Athlete_Fetch parameters: - name: user_id in: query description: Terra user ID (UUID format) to retrieve data for schema: type: string required: true - name: to_webhook in: query description: | Boolean flag specifying whether to send the data retrieved to the webhook instead of in the response (default: true if not provided) schema: type: boolean required: false responses: "200": description: Returned upon successful data request content: application/json: schema: oneOf: - $ref: "#/components/schemas/AthleteCollection" - $ref: "#/components/schemas/NoDataReturned" - $ref: "#/components/schemas/DataSentToWebhook" "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "401": description: Returned when credentials (dev ID and API key) are invalid content: application/json: schema: type: object properties: message: description: An error message type: string example: unauthorized "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) /body: get: summary: Retrieve body metrics for a given user ID description: Fetches body metrics such as weight, height, body fat percentage etc. for a given user ID tags: - Body operationId: Body_Fetch parameters: - name: user_id in: query description: Terra user ID (UUID format) to retrieve data for schema: type: string required: true - name: start_date in: query description: Start date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: true - name: end_date in: query description: End date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: false - name: to_webhook in: query description: | Boolean flag specifying whether to send the data retrieved to the webhook instead of in the response (default: true if not provided) schema: type: boolean required: false - name: with_samples in: query description: | Boolean flag specifying whether to include detailed samples in the returned payload (default: false) schema: type: boolean required: false responses: "200": description: Returned upon successful data request content: application/json: schema: oneOf: - type: object properties: user: $ref: "#/components/schemas/User" data: type: array items: $ref: "#/components/schemas/Body" type: type: [string, "null"] - $ref: "#/components/schemas/NoDataReturned" - $ref: "#/components/schemas/DataSentToWebhook" - $ref: "#/components/schemas/RequestProcessing" - $ref: "#/components/schemas/RateLimitRequestProcessing" - $ref: "#/components/schemas/LargeRequestProcessingResponse" "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "401": description: Returned when credentials (dev ID and API key) are invalid content: application/json: schema: type: object properties: message: description: An error message type: string example: unauthorized "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) post: tags: - Body operationId: Body_Write description: Used to post body data to a provider. This endpoint only works for users connected via Google Fit. Returns error for other providers. summary: Post body data to a provider requestBody: content: application/json: schema: type: object properties: data: description: Body measurement metrics to post to data provider type: array items: $ref: "#/components/schemas/Body" required: - data required: true responses: "201": description: Returned when activity was successfully created on the provider content: application/json: schema: type: object properties: user: $ref: "#/components/schemas/User" log_ids: description: List of identifiers for the objects created, returned in the same order they were posted. I.e. Posting [ObjectA, ObjectB] will return [IdentifierA, IdentifierB] type: array items: type: string message: type: string default: Body data successfully logged "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) delete: tags: - Body operationId: Body_Delete description: Used to delete Body metrics the user has registered on their account summary: Delete body metrics for a given user ID parameters: - name: user_id in: query description: Terra user ID (UUID format) to retrieve data for schema: type: string required: true requestBody: content: application/json: schema: type: object properties: log_ids: type: array description: List of identifiers for body metrics entries to be deleted items: type: string required: - data required: true responses: "200": description: Returned when all records were deleted successfully content: application/json: schema: type: object properties: user: $ref: "#/components/schemas/User" processed_data: type: array items: type: object properties: id: type: string description: Identifier of the body metric entries whose deletion was attempted response_code: type: integer description: Response code from the provider when attempting to delete the body metric entries "207": description: Returned when multiple status codes were obtained from attempting to delete the requested records content: application/json: schema: type: object properties: user: $ref: "#/components/schemas/User" processed_data: type: array items: type: object properties: id: type: string description: Identifier of the body metric entry whose deletion was attempted response_code: type: integer description: Response code from the provider when attempting to delete the body metric entry "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "401": description: Returned when credentials (dev ID and API key) are invalid content: application/json: schema: type: object properties: message: description: An error message type: string example: unauthorized "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) /daily: get: summary: Retrieve daily activity summaries for a given user ID description: Fetches daily summaries of activity metrics such as steps, distance, calories burned etc. for a given user ID tags: - Daily operationId: Daily_Fetch parameters: - name: user_id in: query description: Terra user ID (UUID format) to retrieve data for schema: type: string required: true - name: start_date in: query description: Start date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: true - name: end_date in: query description: End date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: false - name: to_webhook in: query description: | Boolean flag specifying whether to send the data retrieved to the webhook instead of in the response (default: true if not provided) schema: type: boolean required: false - name: with_samples in: query description: | Boolean flag specifying whether to include detailed samples in the returned payload (default: false) schema: type: boolean required: false responses: "200": description: Returned upon successful data request content: application/json: schema: oneOf: - type: object properties: user: $ref: "#/components/schemas/User" data: type: array items: $ref: "#/components/schemas/Daily" type: type: [string, "null"] - $ref: "#/components/schemas/NoDataReturned" - $ref: "#/components/schemas/DataSentToWebhook" - $ref: "#/components/schemas/RequestProcessing" - $ref: "#/components/schemas/RateLimitRequestProcessing" - $ref: "#/components/schemas/LargeRequestProcessingResponse" "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "401": description: Returned when credentials (dev ID and API key) are invalid content: application/json: schema: type: object properties: message: description: An error message type: string example: unauthorized "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) /menstruation: get: summary: Retrieve menstruation data for a given user ID description: Fetches menstruation data such as cycle length, period length, ovulation date etc. for a given user ID tags: - Menstruation operationId: Menstruation_Fetch parameters: - name: user_id in: query description: Terra user ID (UUID format) to retrieve data for schema: type: string required: true - name: start_date in: query description: Start date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: true - name: end_date in: query description: End date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: false - name: to_webhook in: query description: | Boolean flag specifying whether to send the data retrieved to the webhook instead of in the response (default: true if not provided) schema: type: boolean required: false - name: with_samples in: query description: | Boolean flag specifying whether to include detailed samples in the returned payload (default: false) schema: type: boolean required: false responses: "200": description: Returned upon successful data request content: application/json: schema: oneOf: - type: object properties: user: $ref: "#/components/schemas/User" data: type: array items: $ref: "#/components/schemas/Menstruation" type: type: [string, "null"] - $ref: "#/components/schemas/NoDataReturned" - $ref: "#/components/schemas/DataSentToWebhook" - $ref: "#/components/schemas/RequestProcessing" - $ref: "#/components/schemas/RateLimitRequestProcessing" - $ref: "#/components/schemas/LargeRequestProcessingResponse" "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "401": description: Returned when credentials (dev ID and API key) are invalid content: application/json: schema: type: object properties: message: description: An error message type: string example: unauthorized "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) /nutrition: get: summary: Retrieve nutrition log data for a given user ID description: Fetches nutrition log data such as meal type, calories, macronutrients etc. for a given user ID tags: - Nutrition operationId: Nutrition_Fetch parameters: - name: user_id in: query description: Terra user ID (UUID format) to retrieve data for schema: type: string required: true - name: start_date in: query description: Start date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: true - name: end_date in: query description: End date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: false - name: to_webhook in: query description: | Boolean flag specifying whether to send the data retrieved to the webhook instead of in the response (default: true if not provided) schema: type: boolean required: false - name: with_samples in: query description: | Boolean flag specifying whether to include detailed samples in the returned payload (default: false) schema: type: boolean required: false responses: "200": description: Returned upon successful data request content: application/json: schema: oneOf: - type: object properties: user: $ref: "#/components/schemas/User" data: type: array items: $ref: "#/components/schemas/Nutrition" type: type: [string, "null"] - $ref: "#/components/schemas/NoDataReturned" - $ref: "#/components/schemas/DataSentToWebhook" - $ref: "#/components/schemas/RequestProcessing" - $ref: "#/components/schemas/RateLimitRequestProcessing" - $ref: "#/components/schemas/LargeRequestProcessingResponse" "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "401": description: Returned when credentials (dev ID and API key) are invalid content: application/json: schema: type: object properties: message: description: An error message type: string example: unauthorized "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) post: tags: - Nutrition operationId: Nutrition_Write description: Used to post nutrition logs to a provider. This endpoint only works for users connected via Fitbit. Returns error for other providers. summary: Post nutrition logs to a provider requestBody: content: application/json: schema: type: object properties: data: description: Nutrition entry to post to data provider type: array items: $ref: "#/components/schemas/Nutrition" required: - data required: true responses: "201": description: Returned when activity was successfully created on the provider content: application/json: schema: type: object properties: user: $ref: "#/components/schemas/User" log_ids: description: List of identifiers for the objects created, returned in the same order they were posted. I.e. Posting [ObjectA, ObjectB] will return [IdentifierA, IdentifierB] type: array items: type: string message: type: string default: Nutrition successfully logged "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) delete: tags: - Nutrition operationId: Nutrition_Delete description: Used to delete nutrition logs the user has registered on their account summary: Delete nutrition logs for a given user ID parameters: - name: user_id in: query description: Terra user ID (UUID format) to retrieve data for schema: type: string required: true requestBody: content: application/json: schema: type: object properties: data: type: array description: List of identifiers for nutrition entries to be deleted items: type: string required: - data required: true responses: "200": description: Returned when all records were deleted successfully content: application/json: schema: type: object properties: user: $ref: "#/components/schemas/User" processed_data: type: array items: type: object properties: id: type: string description: Identifier of the nutrition log whose deletion was attempted response_code: type: integer description: Response code from the provider when attempting to delete the nutrition log "207": description: Returned when multiple status codes were obtained from attempting to delete the requested records content: application/json: schema: type: object properties: user: $ref: "#/components/schemas/User" processed_data: type: array items: type: object properties: id: type: string description: Identifier of the nutrition log whose deletion was attempted response_code: type: integer description: Response code from the provider when attempting to delete the nutrition log "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "401": description: Returned when credentials (dev ID and API key) are invalid content: application/json: schema: type: object properties: message: description: An error message type: string example: unauthorized "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: enum: [success, error] type: string description: indicates that an error happened (value is error) /sleep: get: summary: Retrieve sleep sessions for a given user ID description: Fetches sleep data such as sleep duration, sleep stages, sleep quality etc. for a given user ID, for sleep sessions with a defined start and end time tags: - Sleep operationId: Sleep_Fetch parameters: - name: user_id in: query description: Terra user ID (UUID format) to retrieve data for schema: type: string required: true - name: start_date in: query description: Start date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: true - name: end_date in: query description: End date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: false - name: to_webhook in: query description: | Boolean flag specifying whether to send the data retrieved to the webhook instead of in the response (default: true if not provided) schema: type: boolean required: false - name: with_samples in: query description: | Boolean flag specifying whether to include detailed samples in the returned payload (default: false) schema: type: boolean required: false responses: "200": description: Returned upon successful data request content: application/json: schema: oneOf: - type: object properties: user: $ref: "#/components/schemas/User" data: type: array items: $ref: "#/components/schemas/Sleep" type: type: [string, "null"] - $ref: "#/components/schemas/NoDataReturned" - $ref: "#/components/schemas/DataSentToWebhook" - $ref: "#/components/schemas/RequestProcessing" - $ref: "#/components/schemas/RateLimitRequestProcessing" - $ref: "#/components/schemas/LargeRequestProcessingResponse" "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "401": description: Returned when credentials (dev ID and API key) are invalid content: application/json: schema: type: object properties: message: description: An error message type: string example: unauthorized "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) /plannedWorkout: post: tags: - PlannedWorkout operationId: PlannedWorkout_Write description: Used to post workout plans users can follow on their wearable. This can be strength workouts (sets, reps, weight lifted) or cardio workouts (warmup, intervals of different intensities, cooldown etc) summary: Post workout plans to a provider parameters: - name: user_id in: query description: Terra user ID (UUID format) to retrieve data for schema: type: string required: true requestBody: content: application/json: schema: type: object properties: data: description: PlannedWorkout entry to post to data provider type: array items: $ref: "#/components/schemas/PlannedWorkout" required: - data required: true responses: "201": description: Returned when activity was successfully created on the provider content: application/json: schema: type: object properties: user: $ref: "#/components/schemas/User" log_ids: description: List of identifiers for the objects created, returned in the same order they were posted. I.e. Posting [ObjectA, ObjectB] will return [IdentifierA, IdentifierB] type: array items: type: string message: type: string default: Planned workout successfully created "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) get: summary: Retrieve workout plans for a given user ID description: Used to get workout plans the user has registered on their account. This can be strength workouts (sets, reps, weight lifted) or cardio workouts (warmup, intervals of different intensities, cooldown etc) tags: - PlannedWorkout operationId: PlannedWorkout_Fetch parameters: - name: user_id in: query description: Terra user ID (UUID format) to retrieve data for schema: type: string required: true - name: start_date in: query description: Start date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: true - name: end_date in: query description: End date for data query - either ISO8601 date (YYYY-MM-DD) or unix timestamp in seconds (10-digit) schema: oneOf: - type: integer - type: string format: date required: false - name: to_webhook in: query description: | Boolean flag specifying whether to send the data retrieved to the webhook instead of in the response (default: true if not provided) schema: type: boolean required: false responses: "200": description: Returned upon successful data request content: application/json: schema: oneOf: - type: object properties: user: $ref: "#/components/schemas/User" data: type: array items: $ref: "#/components/schemas/PlannedWorkout" type: type: [string, "null"] - $ref: "#/components/schemas/NoDataReturned" - $ref: "#/components/schemas/DataSentToWebhook" "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "401": description: Returned when credentials (dev ID and API key) are invalid content: application/json: schema: type: object properties: message: description: An error message type: string example: unauthorized "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) delete: tags: - PlannedWorkout operationId: PlannedWorkout_Delete description: Used to delete workout plans the user has registered on their account. This can be strength workouts (sets, reps, weight lifted) or cardio workouts (warmup, intervals of different intensities, cooldown etc) summary: Delete workout plans for a given user ID parameters: - name: user_id in: query description: Terra user ID (UUID format) to retrieve data for schema: type: string required: true requestBody: content: application/json: schema: type: object properties: data: type: array description: List of identifiers for planned workout entries to be deleted items: type: string required: - data required: true responses: "200": description: Returned when all records were deleted successfully content: application/json: schema: type: object properties: user: $ref: "#/components/schemas/User" processed_data: type: array items: type: object properties: id: type: string description: Identifier of the planned workout whose deletion was attempted response_code: type: integer description: Response code from the provider when attempting to delete the planned workout "207": description: Returned when multiple status codes were obtained from attempting to delete the requested records content: application/json: schema: type: object properties: user: $ref: "#/components/schemas/User" processed_data: type: object properties: id: type: string description: Identifier of the planned workout whose deletion was attempted response_code: type: integer description: Response code from the provider when attempting to delete the planned workout "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "401": description: Returned when authorization with a data provider has failed content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: enum: [success, error] type: string description: indicates that an error happened (value is error) "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) /userInfo: get: tags: - User operationId: User_GetInfoForUserID description: Used to query for information on one Terra user ID, or to query for all registered Terra User objects under one reference ID summary: Get information for a single user ID or multiple users by reference ID parameters: - name: user_id in: query description: user ID to query for schema: type: string required: false - name: reference_id in: query description: reference ID to query for schema: type: string required: false responses: "200": description: Returned when the provided resources are found content: application/json: schema: oneOf: - description: User information for one connection (single User object) type: object properties: user: $ref: "#/components/schemas/User" status: type: string enum: [success, error] default: success is_authenticated: type: boolean - description: List of multiple User objects the reference_id is associated to type: array items: $ref: "#/components/schemas/User" "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) /subscriptions: get: tags: - User operationId: User_GetAllUserIDs description: Used to query for information for all Terra User IDs. Supports optional pagination via `page` and `per_page`. If `page` is not provided, it returns all users in one go (backwards compatibility). summary: Get all Terra User IDs parameters: - name: page in: query required: false schema: type: integer description: Zero-based page number. If omitted, results are not paginated. example: 0 - name: per_page in: query required: false schema: type: integer description: Number of results per page (default is 500). example: 500 responses: "200": description: Returned upon a successful request content: application/json: schema: oneOf: - type: object properties: users: type: array items: $ref: "#/components/schemas/User" - type: object properties: data: type: object properties: next: type: [integer, "null"] description: The next page number, or null if there is no next page max_page: type: integer description: The maximum page index results: type: array items: $ref: "#/components/schemas/User" "400": description: Returned when one or more parameters are malformed content: application/json: schema: type: object properties: message: description: A detailed message describing the error type: string status: type: string enum: [error] description: Indicates that an error occurred (value is `error`) /bulkUserInfo: post: tags: - User operationId: User_GetInfoForMultipleUserIDs description: Used to query for information for multiple Terra User IDs summary: Get information for multiple user IDs requestBody: content: application/json: schema: type: array description: List of user IDs to get information for items: type: string required: true responses: "200": description: Returned upon successful request content: application/json: schema: description: List of User objects type: array items: $ref: "#/components/schemas/User" "400": description: Returned when one or more parameters is malformed - an appropriate error message will be returned content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) "404": description: Returned when a parameter does not exist on Terra's end (e.g. user_id) content: application/json: schema: type: object properties: message: description: a detailed message describing the error type: string status: type: string enum: [error] description: indicates that an error happened (value is error) /integrations: get: summary: Get list of available integrations tags: - Integrations operationId: Integrations_Fetch description: Retrieve a list of all available provider integrations on the API. security: [] # No authentication required responses: "200": description: Returns list of all available integrations on the API content: application/json: schema: type: object properties: providers: type: array items: type: string example: FITBIT sdk_resource: type: array items: type: string example: APPLE status: enum: [success, error] type: string default: success /integrations/detailed: get: tags: - Integrations operationId: Integrations_DetailedFetch summary: Get detailed list of integrations description: Retrieve a detailed list of supported integrations, optionally filtered by the developer's enabled integrations and the requirement for SDK usage. parameters: - in: query name: sdk required: false schema: type: boolean description: If `true`, allows SDK integrations to be included in the response. responses: "200": description: Successful response containing a list of integrations. content: application/json: schema: $ref: "#/components/schemas/IntegrationsResponse" security: [] components: securitySchemes: ApiKeyAuth: type: apiKey in: header name: x-api-key description: Your API key for authentication DevID: type: apiKey in: header name: dev-id description: Your developer ID for authentication and tracking schemas: WidgetSessionParams: type: object properties: providers: type: string description: "Comma separated list of providers to display on the device selection page. This overrides your selected sources on your dashboard" example: "GARMIN,FITBIT,OURA,WITHINGS,SUUNTO" language: type: string description: "Display language of the widget" example: "en" reference_id: type: string description: "Identifier of the end user on your system, such as a user ID or email associated with them" example: "[email protected]" auth_success_redirect_url: type: string description: "URL the user is redirected to upon successful authentication" example: "https://myapp.com/success" auth_failure_redirect_url: type: string description: "URL the user is redirected to upon unsuccessful authentication" example: "https://myapp.com/failure" User: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/TerraUser.yaml" NoDataReturned: type: object properties: status: type: string enum: [success, error] example: "error" message: type: string example: "No data available for specified time range" type: type: [string, "null"] example: "no_data" user: description: Terra User object type: object allOf: - $ref: "#/components/schemas/User" RequestProcessing: type: object properties: retry_after_seconds: type: number description: Recommended time after which the request may be retried nullable: true example: 30 message: type: string nullable: false example: "Request is being processed" type: type: string nullable: false example: "processing" user: description: Terra User object type: object allOf: - $ref: "#/components/schemas/User" RateLimitRequestProcessing: type: object properties: message: type: string nullable: false example: "Rate limit exceeded" type: type: string nullable: false example: "rate_limit" user: $ref: "#/components/schemas/User" required: - user DataSentToWebhook: type: object properties: reference: type: string description: Payload reference, tying the request to the webhook payload which will be received nullable: true example: "webhook_ref_123" message: type: string nullable: false example: "Data will be sent to webhook" type: type: string nullable: false example: "webhook" user: description: Terra User object type: object allOf: - $ref: "#/components/schemas/User" Activity: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/Activity.yaml" Athlete: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/Athlete.yaml" AthleteCollection: type: object properties: athlete: description: Object containing the user's information type: object allOf: - $ref: "#/components/schemas/Athlete" type: type: string nullable: true example: "athlete" user: description: Terra User object type: object allOf: - $ref: "#/components/schemas/User" Body: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/Body.yaml" Daily: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/Daily.yaml" Menstruation: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/Menstruation.yaml" Nutrition: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/Nutrition.yaml" Sleep: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/Sleep.yaml" PlannedWorkoutStepTarget: type: object properties: target_type: description: Type of target for the workout - i.e. metric type for which a criterion must be met for the workout to be completed nullable: false type: string enum: - SPEED - HEART_RATE - OPEN - CADENCE - POWER - GRADE - RESISTANCE - POWER_LAP - SWIM_STROKE - SPEED_LAP - HEART_RATE_LAP - PACE - HEART_RATE_THRESHOLD_PERCENTAGE - HEART_RATE_MAX_PERCENTAGE - SPEED_PERCENTAGE - POWER_PERCENTAGE - REPETITION - TSS - IF example: "HEART_RATE" CadencePlannedWorkoutStepTarget: type: object properties: cadence: type: integer description: Ideal cadence value to be maintained for the workout step nullable: true example: 90 target_type: description: Type of target for the workout - i.e. metric type for which a criterion must be met for the workout to be completed nullable: false type: string enum: - SPEED - HEART_RATE - OPEN - CADENCE - POWER - GRADE - RESISTANCE - POWER_LAP - SWIM_STROKE - SPEED_LAP - HEART_RATE_LAP - PACE - HEART_RATE_THRESHOLD_PERCENTAGE - HEART_RATE_MAX_PERCENTAGE - SPEED_PERCENTAGE - POWER_PERCENTAGE - REPETITION - TSS - IF example: "CADENCE" cadence_low: type: integer description: Minimum cadence threshold for the workout step - i.e. the user is to stay above this value during the workout nullable: true example: 85 cadence_high: type: integer description: Maximum cadence threshold for the workout step - i.e. the user is to stay under this value during the workout step nullable: true example: 95 HRPlannedWorkoutStepTarget: type: object properties: hr_percentage_low: type: number description: Maximum max heart rate percentage threshold for the workout step - i.e. the user is to stay under this value during the workout step nullable: true example: 65.5 target_type: description: Type of target for the workout - i.e. metric type for which a criterion must be met for the workout to be completed nullable: false type: string enum: - SPEED - HEART_RATE - OPEN - CADENCE - POWER - GRADE - RESISTANCE - POWER_LAP - SWIM_STROKE - SPEED_LAP - HEART_RATE_LAP - PACE - HEART_RATE_THRESHOLD_PERCENTAGE - HEART_RATE_MAX_PERCENTAGE - SPEED_PERCENTAGE - POWER_PERCENTAGE - REPETITION - TSS - IF example: "HEART_RATE" hr_percentage_high: type: number description: Minimum heart rate percentage threshold for the workout step - i.e. the user is to stay above this value during the workout nullable: true example: 85.5 hr_percentage: type: number description: Ideal percentage of user's maximum HR to be maintained workout step nullable: true example: 75.5 hr_bpm_high: type: integer description: Maximum heart rate threshold for the workout step - i.e. the user is to stay under this value during the workout step nullable: true example: 175 hr_bpm_low: type: integer description: Minimum heart rate threshold for the workout step - i.e. the user is to stay above this value during the workout nullable: true example: 130 PowerPlannedWorkoutStepTarget: type: object properties: target_type: description: Type of target for the workout - i.e. metric type for which a criterion must be met for the workout to be completed nullable: false type: string enum: - SPEED - HEART_RATE - OPEN - CADENCE - POWER - GRADE - RESISTANCE - POWER_LAP - SWIM_STROKE - SPEED_LAP - HEART_RATE_LAP - PACE - HEART_RATE_THRESHOLD_PERCENTAGE - HEART_RATE_MAX_PERCENTAGE - SPEED_PERCENTAGE - POWER_PERCENTAGE - REPETITION - TSS - IF example: "POWER" power_percentage_low: type: number description: Maximum percentage of Functional Threshold Power for the workout step - i.e. the user is to stay under this value during the workout step nullable: true example: 65.5 power_percentage_high: type: number description: Minimum percentage of Functional Threshold Power for the workout step - i.e. the user is to stay above this value during the workout nullable: true example: 85.5 power_watt_high: type: integer description: Maximum power threshold for the workout step - i.e. the user is to stay under this value during the workout step nullable: true example: 300 power_watt_low: type: integer description: Minimum power threshold for the workout step - i.e. the user is to stay above this value during the workout nullable: true example: 200 power_watt: type: integer default: null nullable: true example: 250 power_percentage: type: number description: Ideal percentage of user's Functional Threshold Power to be maintained workout step nullable: true example: 75.5 SpeedPlannedWorkoutStepTarget: type: object properties: target_type: description: Type of target for the workout - i.e. metric type for which a criterion must be met for the workout to be completed nullable: false type: string enum: - SPEED - HEART_RATE - OPEN - CADENCE - POWER - GRADE - RESISTANCE - POWER_LAP - SWIM_STROKE - SPEED_LAP - HEART_RATE_LAP - PACE - HEART_RATE_THRESHOLD_PERCENTAGE - HEART_RATE_MAX_PERCENTAGE - SPEED_PERCENTAGE - POWER_PERCENTAGE - REPETITION - TSS - IF example: "SPEED" speed_percentage_high: type: number description: Maximum speed threshold for the workout step - i.e. the user is to stay under this value during the workout step nullable: true example: 85.5 speed_percentage_low: type: number description: Minimum speed threshold for the workout step - i.e. the user is to stay above this value during the workout step nullable: true example: 65.5 speed_percentage: type: number description: Ideal percentage of user's Threshold Speed, based off their Threshold Pace, to be maintained workout step. Usually, the Threshold Pace is defined as the pace one could race at for 50 to 60 minutes nullable: true example: 75.5 speed_meters_per_second: type: number description: Ideal speed value to be maintained for the workout step nullable: true example: 4.2 PacePlannedWorkoutStepTarget: type: object properties: target_type: description: Type of target for the workout - i.e. metric type for which a criterion must be met for the workout to be completed nullable: false type: string enum: - SPEED - HEART_RATE - OPEN - CADENCE - POWER - GRADE - RESISTANCE - POWER_LAP - SWIM_STROKE - SPEED_LAP - HEART_RATE_LAP - PACE - HEART_RATE_THRESHOLD_PERCENTAGE - HEART_RATE_MAX_PERCENTAGE - SPEED_PERCENTAGE - POWER_PERCENTAGE - REPETITION - TSS - IF example: "PACE" pace_minutes_per_kilometer: type: number description: Ideal pace value to be maintained for the workout step nullable: true example: 5.5 TSSPlannedWorkoutStepTarget: type: object properties: target_type: description: Type of target for the workout - i.e. metric type for which a criterion must be met for the workout to be completed nullable: false type: string enum: - SPEED - HEART_RATE - OPEN - CADENCE - POWER - GRADE - RESISTANCE - POWER_LAP - SWIM_STROKE - SPEED_LAP - HEART_RATE_LAP - PACE - HEART_RATE_THRESHOLD_PERCENTAGE - HEART_RATE_MAX_PERCENTAGE - SPEED_PERCENTAGE - POWER_PERCENTAGE - REPETITION - TSS - IF example: "TSS" tss: type: number description: Planned Training Stress Score to be achieved for the workout step nullable: true example: 100.5 IFPlannedWorkoutStepTarget: type: object properties: if_high: type: number description: Maximum Intensity Factor to be achieved for the workout step nullable: true example: 1.2 target_type: description: Type of target for the workout - i.e. metric type for which a criterion must be met for the workout to be completed nullable: false type: string enum: - SPEED - HEART_RATE - OPEN - CADENCE - POWER - GRADE - RESISTANCE - POWER_LAP - SWIM_STROKE - SPEED_LAP - HEART_RATE_LAP - PACE - HEART_RATE_THRESHOLD_PERCENTAGE - HEART_RATE_MAX_PERCENTAGE - SPEED_PERCENTAGE - POWER_PERCENTAGE - REPETITION - TSS - IF example: "IF" if_low: type: number description: Minimum Intensity Factor to be achieved for the workout step nullable: true example: 0.8 RepetitionPlannedWorkoutStepTarget: type: object properties: target_type: description: Type of target for the workout - i.e. metric type for which a criterion must be met for the workout to be completed nullable: false type: string enum: - SPEED - HEART_RATE - OPEN - CADENCE - POWER - GRADE - RESISTANCE - POWER_LAP - SWIM_STROKE - SPEED_LAP - HEART_RATE_LAP - PACE - HEART_RATE_THRESHOLD_PERCENTAGE - HEART_RATE_MAX_PERCENTAGE - SPEED_PERCENTAGE - POWER_PERCENTAGE - REPETITION - TSS - IF example: "REPETITION" repetitions: type: number description: Number of repetitions of the workout step to be performed nullable: true example: 10 SwimStrokePlannedWorkoutStepTarget: type: object properties: target_type: description: Type of target for the workout - i.e. metric type for which a criterion must be met for the workout to be completed nullable: false type: string enum: - SPEED - HEART_RATE - OPEN - CADENCE - POWER - GRADE - RESISTANCE - POWER_LAP - SWIM_STROKE - SPEED_LAP - HEART_RATE_LAP - PACE - HEART_RATE_THRESHOLD_PERCENTAGE - HEART_RATE_MAX_PERCENTAGE - SPEED_PERCENTAGE - POWER_PERCENTAGE - REPETITION - TSS - IF example: "SWIM_STROKE" swim_strokes: type: integer description: Number of swim strokes to be performed during the workout step nullable: true example: 50 PlannedWorkoutStepTargets: type: object properties: {} oneOf: - $ref: "#/components/schemas/PlannedWorkoutStepTarget" - $ref: "#/components/schemas/CadencePlannedWorkoutStepTarget" - $ref: "#/components/schemas/HRPlannedWorkoutStepTarget" - $ref: "#/components/schemas/PowerPlannedWorkoutStepTarget" - $ref: "#/components/schemas/SpeedPlannedWorkoutStepTarget" - $ref: "#/components/schemas/PacePlannedWorkoutStepTarget" - $ref: "#/components/schemas/TSSPlannedWorkoutStepTarget" - $ref: "#/components/schemas/IFPlannedWorkoutStepTarget" - $ref: "#/components/schemas/RepetitionPlannedWorkoutStepTarget" - $ref: "#/components/schemas/SwimStrokePlannedWorkoutStepTarget" discriminator: propertyName: type mapping: PlannedWorkoutStepTarget: "#/components/schemas/PlannedWorkoutStepTarget" CadencePlannedWorkoutStepTarget: "#/components/schemas/CadencePlannedWorkoutStepTarget" HRPlannedWorkoutStepTarget: "#/components/schemas/HRPlannedWorkoutStepTarget" PowerPlannedWorkoutStepTarget: "#/components/schemas/PowerPlannedWorkoutStepTarget" SpeedPlannedWorkoutStepTarget: "#/components/schemas/SpeedPlannedWorkoutStepTarget" PacePlannedWorkoutStepTarget: "#/components/schemas/PacePlannedWorkoutStepTarget" TSSPlannedWorkoutStepTarget: "#/components/schemas/TSSPlannedWorkoutStepTarget" IFPlannedWorkoutStepTarget: "#/components/schemas/IFPlannedWorkoutStepTarget" RepetitionPlannedWorkoutStepTarget: "#/components/schemas/RepetitionPlannedWorkoutStepTarget" SwimStrokePlannedWorkoutStepTarget: "#/components/schemas/SwimStrokePlannedWorkoutStepTarget" PlannedWorkoutStepDuration: type: object properties: duration_type: description: Type of condition that must be fulfilled to consider the workout step complete nullable: false type: string enum: - TIME - DISTANCE_METERS - HR_LESS_THAN - HR_GREATER_THAN - CALORIES - OPEN - POWER_LESS_THAN - POWER_GREATER_THAN - REPETITION_TIME - REPS - FIXED_REST - TIME_AT_VALID_CDA - STEPS TimePlannedWorkoutStepDuration: type: object properties: seconds: type: integer description: Time duration to be elapsed for the workout step nullable: true duration_type: description: Type of condition that must be fulfilled to consider the workout step complete nullable: false type: string enum: - TIME - DISTANCE_METERS - HR_LESS_THAN - HR_GREATER_THAN - CALORIES - OPEN - POWER_LESS_THAN - POWER_GREATER_THAN - REPETITION_TIME - REPS - FIXED_REST - TIME_AT_VALID_CDA - STEPS PowerAbovePlannedWorkoutStepDuration: type: object properties: power_above_watts: type: integer description: Threshold power goal to complete the workout step - once the user reaches above this power level, the step will be completed nullable: true duration_type: description: Type of condition that must be fulfilled to consider the workout step complete nullable: false type: string enum: - TIME - DISTANCE_METERS - HR_LESS_THAN - HR_GREATER_THAN - CALORIES - OPEN - POWER_LESS_THAN - POWER_GREATER_THAN - REPETITION_TIME - REPS - FIXED_REST - TIME_AT_VALID_CDA - STEPS PowerBelowPlannedWorkoutStepDuration: type: object properties: power_below_watts: type: integer description: Threshold power goal to complete the workout step - once the user reaches below this power level, the step will be completed nullable: true duration_type: description: Type of condition that must be fulfilled to consider the workout step complete nullable: false type: string enum: - TIME - DISTANCE_METERS - HR_LESS_THAN - HR_GREATER_THAN - CALORIES - OPEN - POWER_LESS_THAN - POWER_GREATER_THAN - REPETITION_TIME - REPS - FIXED_REST - TIME_AT_VALID_CDA - STEPS FixedRestPlannedWorkoutStepDuration: type: object properties: duration_type: description: Type of condition that must be fulfilled to consider the workout step complete nullable: false type: string enum: - TIME - DISTANCE_METERS - HR_LESS_THAN - HR_GREATER_THAN - CALORIES - OPEN - POWER_LESS_THAN - POWER_GREATER_THAN - REPETITION_TIME - REPS - FIXED_REST - TIME_AT_VALID_CDA - STEPS rest_seconds: type: integer description: Time duration to be elapsed for the rest period nullable: true CaloriesPlannedWorkoutStepDuration: type: object properties: calories: type: integer description: Calorie burn target for the workout step - once the user reaches the target, the step will be completed nullable: true duration_type: description: Type of condition that must be fulfilled to consider the workout step complete nullable: false type: string enum: - TIME - DISTANCE_METERS - HR_LESS_THAN - HR_GREATER_THAN - CALORIES - OPEN - POWER_LESS_THAN - POWER_GREATER_THAN - REPETITION_TIME - REPS - FIXED_REST - TIME_AT_VALID_CDA - STEPS HRAbovePlannedWorkoutStepDuration: type: object properties: duration_type: description: Type of condition that must be fulfilled to consider the workout step complete nullable: false type: string enum: - TIME - DISTANCE_METERS - HR_LESS_THAN - HR_GREATER_THAN - CALORIES - OPEN - POWER_LESS_THAN - POWER_GREATER_THAN - REPETITION_TIME - REPS - FIXED_REST - TIME_AT_VALID_CDA - STEPS hr_above_bpm: type: integer description: Threshold heart rate goal to complete the workout step - once the user's heart rate reaches above below this value, the step will be completed nullable: true HRBelowPlannedWorkoutStepDuration: type: object properties: hr_below_bpm: type: integer description: Threshold heart rate goal to complete the workout step - once the user's heart rate reaches below this value, the step will be completed nullable: true duration_type: description: Type of condition that must be fulfilled to consider the workout step complete nullable: false type: string enum: - TIME - DISTANCE_METERS - HR_LESS_THAN - HR_GREATER_THAN - CALORIES - OPEN - POWER_LESS_THAN - POWER_GREATER_THAN - REPETITION_TIME - REPS - FIXED_REST - TIME_AT_VALID_CDA - STEPS RepsPlannedWorkoutStepDuration: type: object properties: reps: type: integer description: Target number of reps for the workout step - once the user completes this rep target, the step will be completed nullable: true duration_type: description: Type of condition that must be fulfilled to consider the workout step complete nullable: false type: string enum: - TIME - DISTANCE_METERS - HR_LESS_THAN - HR_GREATER_THAN - CALORIES - OPEN - POWER_LESS_THAN - POWER_GREATER_THAN - REPETITION_TIME - REPS - FIXED_REST - TIME_AT_VALID_CDA - STEPS DistancePlannedWorkoutStepDuration: type: object properties: duration_type: description: Type of condition that must be fulfilled to consider the workout step complete nullable: false type: string enum: - TIME - DISTANCE_METERS - HR_LESS_THAN - HR_GREATER_THAN - CALORIES - OPEN - POWER_LESS_THAN - POWER_GREATER_THAN - REPETITION_TIME - REPS - FIXED_REST - TIME_AT_VALID_CDA - STEPS distance_meters: type: integer description: Target distance for the workout step - once the user covers this distance, the step will be completed nullable: true StepsPlannedWorkoutStepDuration: type: object properties: steps: type: integer description: Target number of steps for the workout step - once the user performs this number of steps, the step will be completed nullable: true duration_type: description: Type of condition that must be fulfilled to consider the workout step complete nullable: false type: string enum: - TIME - DISTANCE_METERS - HR_LESS_THAN - HR_GREATER_THAN - CALORIES - OPEN - POWER_LESS_THAN - POWER_GREATER_THAN - REPETITION_TIME - REPS - FIXED_REST - TIME_AT_VALID_CDA - STEPS PlannedWorkoutStepDurations: type: object properties: {} oneOf: - $ref: "#/components/schemas/PlannedWorkoutStepDuration" - $ref: "#/components/schemas/TimePlannedWorkoutStepDuration" - $ref: "#/components/schemas/PowerAbovePlannedWorkoutStepDuration" - $ref: "#/components/schemas/PowerBelowPlannedWorkoutStepDuration" - $ref: "#/components/schemas/FixedRestPlannedWorkoutStepDuration" - $ref: "#/components/schemas/CaloriesPlannedWorkoutStepDuration" - $ref: "#/components/schemas/HRAbovePlannedWorkoutStepDuration" - $ref: "#/components/schemas/HRBelowPlannedWorkoutStepDuration" - $ref: "#/components/schemas/RepsPlannedWorkoutStepDuration" - $ref: "#/components/schemas/DistancePlannedWorkoutStepDuration" - $ref: "#/components/schemas/StepsPlannedWorkoutStepDuration" discriminator: propertyName: type mapping: PlannedWorkoutStepDuration: "#/components/schemas/PlannedWorkoutStepDuration" TimePlannedWorkoutStepDuration: "#/components/schemas/TimePlannedWorkoutStepDuration" PowerAbovePlannedWorkoutStepDuration: "#/components/schemas/PowerAbovePlannedWorkoutStepDuration" PowerBelowPlannedWorkoutStepDuration: "#/components/schemas/PowerBelowPlannedWorkoutStepDuration" FixedRestPlannedWorkoutStepDuration: "#/components/schemas/FixedRestPlannedWorkoutStepDuration" CaloriesPlannedWorkoutStepDuration: "#/components/schemas/CaloriesPlannedWorkoutStepDuration" HRAbovePlannedWorkoutStepDuration: "#/components/schemas/HRAbovePlannedWorkoutStepDuration" HRBelowPlannedWorkoutStepDuration: "#/components/schemas/HRBelowPlannedWorkoutStepDuration" RepsPlannedWorkoutStepDuration: "#/components/schemas/RepsPlannedWorkoutStepDuration" DistancePlannedWorkoutStepDuration: "#/components/schemas/DistancePlannedWorkoutStepDuration" StepsPlannedWorkoutStepDuration: "#/components/schemas/StepsPlannedWorkoutStepDuration" PlannedWorkoutStep: type: object properties: targets: type: array description: List of targets for the workout items: $ref: "#/components/schemas/PlannedWorkoutStepTargets" type: description: Type of workout step - either repeat or one-off type: string enum: - STEP - REPEAT_STEP intensity: description: Planned intensity for the workout step type: string enum: - REST - WARMUP - COOLDOWN - RECOVERY - INTERVAL - ACTIVE order: type: integer description: Position of the workout step in the overall workout description: type: string description: Description of workout step durations: type: array description: List of conditions to be fulfilled for the workout step to be completed - all of the conditions must be completed items: $ref: "#/components/schemas/PlannedWorkoutStepDurations" name: type: string description: Name of workout step PlannedWorkoutRepeatStep: type: object properties: targets: type: array description: List of targets for the workout items: $ref: "#/components/schemas/PlannedWorkoutStepTarget" type: description: Type of workout step - either repeat or one-off nullable: false type: string enum: - STEP - REPEAT_STEP steps: type: array description: List of steps to be repeated for this workout step - e.g. if a user wants to schedule 5 repetitions of 100m sprints plus 20s rest in between items: $ref: "#/components/schemas/PlannedWorkoutStep" intensity: type: integer description: Planned intensity for the workout step nullable: true order: type: integer description: Position of the workout step in the overall workout nullable: true description: type: string description: Description of workout step nullable: true durations: type: array description: List of conditions to be fulfilled for the workout step to be completed - all of the conditions must be completed items: $ref: "#/components/schemas/PlannedWorkoutStepDuration" name: type: string description: Name of workout step nullable: true SwimmingPlannedWorkoutStep: type: object properties: targets: type: array description: List of targets for the workout items: $ref: "#/components/schemas/PlannedWorkoutStepTarget" type: description: Type of workout step - either repeat or one-off nullable: false type: string enum: - STEP - REPEAT_STEP intensity: type: integer description: Planned intensity for the workout step nullable: true order: type: integer description: Position of the workout step in the overall workout nullable: true equipment_type: description: Workout equipment to be used during the workout step nullable: false type: string enum: - NONE - SWIM_FINS - SWIM_KICKBOARD - SWIM_PADDLES - SWIM_PULL_BUOY - SWIM_SNORKEL description: type: string description: Description of workout step nullable: true durations: type: array description: List of conditions to be fulfilled for the workout step to be completed - all of the conditions must be completed items: $ref: "#/components/schemas/PlannedWorkoutStepDuration" name: type: string description: Name of workout step nullable: true stroke_type: description: Stroke type used for the workout step (e.g. breaststroke) nullable: false type: string enum: - OTHER - FREESTYLE - BACKSTROKE - BREASTSTROKE - BUTTERFLY - REST CardioPlannedWorkoutStep: type: object properties: targets: type: array description: List of targets for the workout items: $ref: "#/components/schemas/PlannedWorkoutStepTarget" type: description: Type of workout step - either repeat or one-off nullable: false type: string enum: - STEP - REPEAT_STEP intensity: type: integer description: Planned intensity for the workout step nullable: true order: type: integer description: Position of the workout step in the overall workout nullable: true exercise_name: type: string description: Name of exercise to be performed for the workout step nullable: true description: type: string description: Description of workout step nullable: true durations: type: array description: List of conditions to be fulfilled for the workout step to be completed - all of the conditions must be completed items: $ref: "#/components/schemas/PlannedWorkoutStepDuration" exercise_category: description: Type of exercise to be performed for the workout step nullable: false type: string enum: - UNKNOWN - BENCH_PRESS - CALF_RAISE - CARDIO - CARRY - CHOP - CORE - CRUNCH - CURL - DEADLIFT - FLYE - HIP_RAISE - HIP_STABILITY - HIP_SWING - HYPEREXTENSION - LATERAL_RAISE - LEG_CURL - LEG_RAISE - LUNGE - OLYMPIC_LIFT - PLANK - PLYO - PULL_UP - PUSH_UP - ROW - SHOULDER_PRESS - SHOULDER_STABILITY - SHRUG - SIT_UP - SQUAT - TOTAL_BODY - TRICEPS_EXTENSION - WARM_UP - RUN - BIKE - CARDIO_SENSORS name: type: string description: Name of workout step nullable: true StrengthPlannedWorkoutStep: type: object properties: weight_kg: type: number description: Weight to be lifted for the exercise nullable: true targets: type: array description: List of targets for the workout items: $ref: "#/components/schemas/PlannedWorkoutStepTarget" type: description: Type of workout step - either repeat or one-off nullable: false type: string enum: - STEP - REPEAT_STEP intensity: type: integer description: Planned intensity for the workout step nullable: true order: type: integer description: Position of the workout step in the overall workout nullable: true exercise_name: type: string description: Name of strength exercise to be performed for the workout step nullable: true description: type: string description: Description of workout step nullable: true durations: type: array description: List of conditions to be fulfilled for the workout step to be completed - all of the conditions must be completed items: $ref: "#/components/schemas/PlannedWorkoutStepDuration" exercise_category: description: Type of strength exercise to be performed for the workout step nullable: false type: string enum: - UNKNOWN - BENCH_PRESS - CALF_RAISE - CARDIO - CARRY - CHOP - CORE - CRUNCH - CURL - DEADLIFT - FLYE - HIP_RAISE - HIP_STABILITY - HIP_SWING - HYPEREXTENSION - LATERAL_RAISE - LEG_CURL - LEG_RAISE - LUNGE - OLYMPIC_LIFT - PLANK - PLYO - PULL_UP - PUSH_UP - ROW - SHOULDER_PRESS - SHOULDER_STABILITY - SHRUG - SIT_UP - SQUAT - TOTAL_BODY - TRICEPS_EXTENSION - WARM_UP - RUN - BIKE - CARDIO_SENSORS name: type: string description: Name of workout step nullable: true YogaPlannedWorkoutStep: type: object properties: targets: type: array description: List of targets for the workout items: $ref: "#/components/schemas/PlannedWorkoutStepTarget" type: description: Type of workout step - either repeat or one-off nullable: false type: string enum: - STEP - REPEAT_STEP intensity: type: integer description: Planned intensity for the workout step nullable: true order: type: integer description: Position of the workout step in the overall workout nullable: true description: type: string description: Description of workout step nullable: true durations: type: array description: List of conditions to be fulfilled for the workout step to be completed - all of the conditions must be completed items: $ref: "#/components/schemas/PlannedWorkoutStepDuration" name: type: string description: Name of workout step nullable: true PilatesPlannedWorkoutStep: type: object properties: targets: type: array description: List of targets for the workout items: $ref: "#/components/schemas/PlannedWorkoutStepTarget" type: description: Type of workout step - either repeat or one-off nullable: false type: string enum: - STEP - REPEAT_STEP intensity: type: integer description: Planned intensity for the workout step nullable: true order: type: integer description: Position of the workout step in the overall workout nullable: true description: type: string description: Description of workout step nullable: true durations: type: array description: List of conditions to be fulfilled for the workout step to be completed - all of the conditions must be completed items: $ref: "#/components/schemas/PlannedWorkoutStepDuration" name: type: string description: Name of workout step nullable: true RunningPlannedWorkoutStep: type: object properties: targets: type: array description: List of targets for the workout items: $ref: "#/components/schemas/PlannedWorkoutStepTarget" type: description: Type of workout step - either repeat or one-off nullable: false type: string enum: - STEP - REPEAT_STEP intensity: type: integer description: Planned intensity for the workout step nullable: true order: type: integer description: Position of the workout step in the overall workout nullable: true description: type: string description: Description of workout step nullable: true durations: type: array description: List of conditions to be fulfilled for the workout step to be completed - all of the conditions must be completed items: $ref: "#/components/schemas/PlannedWorkoutStepDuration" name: type: string description: Name of workout step nullable: true CyclingPlannedWorkoutStep: type: object properties: targets: type: array description: List of targets for the workout items: $ref: "#/components/schemas/PlannedWorkoutStepTarget" type: description: Type of workout step - either repeat or one-off nullable: false type: string enum: - STEP - REPEAT_STEP intensity: type: integer description: Planned intensity for the workout step nullable: true order: type: integer description: Position of the workout step in the overall workout nullable: true description: type: string description: Description of workout step nullable: true durations: type: array description: List of conditions to be fulfilled for the workout step to be completed - all of the conditions must be completed items: $ref: "#/components/schemas/PlannedWorkoutStepDuration" name: type: string description: Name of workout step nullable: true PlannedWorkoutSteps: type: object properties: {} oneOf: - $ref: "#/components/schemas/PlannedWorkoutStep" - $ref: "#/components/schemas/PlannedWorkoutRepeatStep" - $ref: "#/components/schemas/SwimmingPlannedWorkoutStep" - $ref: "#/components/schemas/CardioPlannedWorkoutStep" - $ref: "#/components/schemas/StrengthPlannedWorkoutStep" - $ref: "#/components/schemas/YogaPlannedWorkoutStep" - $ref: "#/components/schemas/PilatesPlannedWorkoutStep" - $ref: "#/components/schemas/RunningPlannedWorkoutStep" - $ref: "#/components/schemas/CyclingPlannedWorkoutStep" discriminator: propertyName: type mapping: PlannedWorkoutStep: "#/components/schemas/PlannedWorkoutStep" PlannedWorkoutRepeatStep: "#/components/schemas/PlannedWorkoutRepeatStep" SwimmingPlannedWorkoutStep: "#/components/schemas/SwimmingPlannedWorkoutStep" CardioPlannedWorkoutStep: "#/components/schemas/CardioPlannedWorkoutStep" StrengthPlannedWorkoutStep: "#/components/schemas/StrengthPlannedWorkoutStep" YogaPlannedWorkoutStep: "#/components/schemas/YogaPlannedWorkoutStep" PilatesPlannedWorkoutStep: "#/components/schemas/PilatesPlannedWorkoutStep" RunningPlannedWorkoutStep: "#/components/schemas/RunningPlannedWorkoutStep" CyclingPlannedWorkoutStep: "#/components/schemas/CyclingPlannedWorkoutStep" PlannedWorkoutMetadata: type: object properties: estimated_energy_kj: type: [number, "null"] description: Estimated energy expenditure for the workout estimated_speed_meters_per_second: type: [number, "null"] description: Estimated speed for the workout estimated_elevation_gain_meters: type: [number, "null"] description: Estimated elevation gain for the workout estimated_tss: type: [number, "null"] description: Estimated Training Stress Score for the workout estimated_calories: type: [integer, "null"] description: Estimated calorie burn for the workout created_date: type: [string, "null"] description: The creation datetime of the associated workout, in ISO8601 format with microsecond precision. TimeZone info will be provided whenever possible. If absent, the time corresponds to the user's local time example: "2022-11-23T09:00:00.000000+02:00" format: date-time planned_date: type: string description: The planned start datetime, in ISO8601 format with microsecond precision. TimeZone info will be provided whenever possible. If absent, the time corresponds to the user's local time example: "2022-11-24T09:00:00.000000+02:00" format: date-time nullable: true type: description: The name - either user-entered or given by the fitness data provider - of the associated workout plan nullable: false type: string enum: - IN_VEHICLE - BIKING - STILL - UNKNOWN - TILTING - WALKING - RUNNING - AEROBICS - BADMINTON - BASEBALL - BASKETBALL - BIATHLON - HANDBIKING - MOUNTAIN_BIKING - ROAD_BIKING - SPINNING - STATIONARY_BIKING - UTILITY_BIKING - BOXING - CALISTHENICS - CIRCUIT_TRAINING - CRICKET - DANCING - ELLIPTICAL - FENCING - AMERICAN_FOOTBALL - AUSTRALIAN_FOOTBALL - ENGLISH_FOOTBALL - FRISBEE - GARDENING - GOLF - GYMNASTICS - HANDBALL - HIKING - HOCKEY - HORSEBACK_RIDING - HOUSEWORK - JUMPING_ROPE - KAYAKING - KETTLEBELL_TRAINING - KICKBOXING - KITESURFING - MARTIAL_ARTS - MEDITATION - MIXED_MARTIAL_ARTS - P90X_EXERCISES - PARAGLIDING - PILATES - POLO - RACQUETBALL - ROCK_CLIMBING - ROWING - ROWING_MACHINE - RUGBY - JOGGING - RUNNING_ON_SAND - TREADMILL_RUNNING - SAILING - SCUBA_DIVING - SKATEBOARDING - SKATING - CROSS_SKATING - INDOOR_ROLLERBLADING - SKIING - BACK_COUNTRY_SKIING - CROSS_COUNTRY_SKIING - DOWNHILL_SKIING - KITE_SKIING - ROLLER_SKIING - SLEDDING - SNOWBOARDING - SNOWMOBILE - SNOWSHOEING - SQUASH - STAIR_CLIMBING - STAIR_CLIMBING_MACHINE - STAND_UP_PADDLEBOARDING - STRENGTH_TRAINING - SURFING - SWIMMING - SWIMMING_SWIMMING_POOL - SWIMMING_OPEN_WATER - TABLE_TENNIS - TEAM_SPORTS - TENNIS - TREADMILL - VOLLEYBALL - VOLLEYBALL_BEACH - VOLLEYBALL_INDOOR - WAKEBOARDING - WALKING_FITNESS - NORDIC_WALKING - WALKING_TREADMILL - WATERPOLO - WEIGHTLIFTING - WHEELCHAIR - WINDSURFING - YOGA - ZUMBA - DIVING - ERGOMETER - ICE_SKATING - INDOOR_SKATING - CURLING - OTHER - CROSSFIT - HIIT - INTERVAL_TRAINING - WALKING_STROLLER - ELEVATOR - ESCALATOR - ARCHERY - SOFTBALL - GUIDED_BREATHING - CARDIO_TRAINING - LACROSSE - STRETCHING - TRIATHLON - INLINE_SKATING - SKY_DIVING - PADDLING - MOUNTAINEERING - FISHING - WATER_SKIING - INDOOR_RUNNING id: type: [string, "null"] default: null estimated_duration_seconds: type: [integer, "null"] description: Estimated workout duration estimated_pace_minutes_per_kilometer: type: [number, "null"] description: Estimated pace for the workout provider: type: string description: Name of the original source of the workout plan estimated_tscore: type: [number, "null"] description: "Estimated training stress score for the workout (normalized power-based metric)" description: type: [string, "null"] description: Description of the workout name: type: [string, "null"] description: Name of the workout plan estimated_distance_meters: type: [integer, "null"] description: Estimated distance for the workout estimated_if: type: [number, "null"] description: Estimated Intensity Factor for the workout pool_length_meters: type: [integer, "null"] description: Pool length of the pool used for the workout - only relevant for swimming activity types PlannedWorkout: type: object properties: steps: type: array description: List of exercises/steps/intervals for the workout plan items: $ref: "#/components/schemas/PlannedWorkoutSteps" metadata: description: Metadata for the workout plan type: object allOf: - $ref: "#/components/schemas/PlannedWorkoutMetadata" DataProcessingWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/ProcessingEvent.yaml" UserAuthWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/AuthSuccessEvent.yaml" UserAuthWebhookError: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/AuthErrorEvent.yaml" PermissionChangeWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/PermissionChangeEvent.yaml" UserReauthWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/UserReauthEvent.yaml" UserDeauthWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/DeauthEvent.yaml" AccessRevokedWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/AccessRevokedEvent.yaml" GoogleNoDataSourceWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/GoogleNoDatasourceEvent.yaml" ConnectionErrorWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/ConnectionErrorEvent.yaml" LargeRequestSendingWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/LargeRequestSendingEvent.yaml" LargeRequestProcessingResponse: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/LargeRequestProcessingEvent.yaml" AuthenticationFailedWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/AuthErrorEvent.yaml" HealthCheckWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/HealthcheckEvent.yaml" RateLimitHitWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/RateLimitHitEvent.yaml" S3UploadWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/S3PayloadEvent.yaml" ActivityWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/ActivityEvent.yaml" DailyWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/DailyEvent.yaml" NutritionWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/NutritionEvent.yaml" AthleteWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/AthleteEvent.yaml" SleepWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/SleepEvent.yaml" MenstruationWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/MenstruationEvent.yaml" BodyWebhook: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/BodyEvent.yaml" IntegrationsResponse: type: object properties: status: type: string description: Status of the API response example: "success" providers: type: array description: List of integration providers with their details items: $ref: "#/components/schemas/IntegrationProvider" IntegrationProvider: type: object properties: provider: type: string description: Identifier for the provider example: "MAPMYFITNESS" name: type: string description: Display name of the integration example: "MapMyFitness" icon: type: string description: URL for the provider's icon image example: "https://api.tryterra.co/v2/static/assets/img/app_icons/mapmyfitness.webp" setup: type: string description: Indicates how the integration is set up example: "API_KEYS_MANAGED" enabled: type: boolean description: Whether the integration is enabled example: true types: type: object description: Indicates the types of data available through the provider properties: activity: type: boolean example: true body: type: boolean example: false nutrition: type: boolean example: false daily: type: boolean example: false sleep: type: boolean example: false menstruation: type: boolean example: false WebhookEvents: $ref: "https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/schemas/WebhookEventType.yaml" webhooks: healthcheck: post: description: Healthcheck event sent periodically to verify your event is functional summary: Healthcheck webhook operationId: healthcheckWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/HealthCheckWebhook" responses: "200": description: Successful healthcheck response auth: post: description: Occurs when a user attempts to authenticate summary: User authentication webhook operationId: userAuthWebhook requestBody: content: application/json: schema: oneOf: - $ref: "#/components/schemas/UserAuthWebhook" - $ref: "#/components/schemas/UserAuthWebhookError" responses: "200": description: Successful authentication response deauth: post: description: Occurs when a user deauthenticates through the Terra summary: User deauthentication webhook operationId: userDeauthWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/UserDeauthWebhook" responses: "200": description: Successful deauthentication response user_reauth: post: description: Occurs when a user successfully authenticates for a second time, with the same account. You will receive a successful auth and a user_reauth payload summary: User reauthentication webhook operationId: userReauthWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/UserReauthWebhook" responses: "200": description: Successful reauthentication response access_revoked: post: description: Occurs when a user revokes Terra's access from the provider's end summary: Access revoked webhook operationId: accessRevokedWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/AccessRevokedWebhook" responses: "200": description: Successful access revocation response connection_error: post: description: Occurs when a request to a provider returns an HTTP response of 401, 403 or 412 summary: Connection error webhook operationId: connectionErrorWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/ConnectionErrorWebhook" responses: "200": description: Successful connection error response google_no_datasource: post: description: Occurs when a Google Fit user doesn't have a data source linked to their account. All data requests for the user will be empty unless they link a data source summary: Google no data source webhook operationId: googleNoDataSourceWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/GoogleNoDataSourceWebhook" responses: "200": description: Successful no data source response processing: post: description: Occurs when data is being fetched asynchronously from the provider. The data will be sent through automatically via your Destination, and you can also safely request for it after the time in the retry_after_seconds field. summary: Data processing webhook operationId: dataProcessingWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/DataProcessingWebhook" responses: "200": description: Successful processing response large_request_sending: post: description: Occurs when more than one month of data has been requested and all data has been successfully submitted summary: Large request sending webhook operationId: largeRequestSendingWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/LargeRequestSendingWebhook" responses: "200": description: Successful large request sending response large_request_processing: post: description: Occurs when more a request for over one month of data has been submitted to Terra. Data will be sent in chunks with the same reference field after this request. Each chunk will be at most 10 objects in the data field or 10 MB in size, whichever limit gets hit first summary: Large request processing webhook operationId: largeRequestProcessingWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/LargeRequestProcessingResponse" responses: "200": description: Successful large request processing response rate_limit_hit: post: description: Occurs when an asynchronous request has failed due to rate limiting and is going to be retried. summary: Rate limit hit webhook operationId: rateLimitHitWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/RateLimitHitWebhook" responses: "200": description: Successful rate limit hit response s3_upload: post: description: Data event sent as a download link. summary: S3 upload webhook operationId: s3UploadWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/S3UploadWebhook" responses: "200": description: Successful S3 upload response activity: post: description: "activity data event: activity updates when new activity is completed" summary: Activity webhook operationId: activityWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/ActivityWebhook" responses: "200": description: Successful activity response athlete: post: description: "athlete data event: Occurs throughout the day as users use their wearables." summary: Athlete webhook operationId: athleteWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/AthleteWebhook" responses: "200": description: Successful athlete response nutrition: post: description: "nutrition data event: occurs throughout the day as users use their wearables." summary: Nutrition webhook operationId: nutritionWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/NutritionWebhook" responses: "200": description: Successful nutrition response daily: post: description: "daily data event: occurs throughout the day as users use their wearables." summary: Daily webhook operationId: dailyWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/DailyWebhook" responses: "200": description: Successful daily response sleep: post: description: "sleep data event: occurs throughout the day as users use their wearables." summary: Sleep webhook operationId: sleepWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/SleepWebhook" responses: "200": description: Successful sleep response menstruation: post: description: "menstruation data event: occurs throughout the day as users use their wearables." summary: Menstruation webhook operationId: menstruationWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/MenstruationWebhook" responses: "200": description: Successful menstruation response body: post: description: "body data event: occurs throughout the day as users use their wearables." summary: Body webhook operationId: bodyWebhook requestBody: content: application/json: schema: $ref: "#/components/schemas/BodyWebhook" responses: "200": description: Successful body response sun-brightdesktopmoon --- # Websocket Reference | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/streaming-api/websocket-reference#identify-data-schema) Identify Data Schema ------------------------------------------------------------------------------------------------------------------------------ Field Name Type Description token String Authentication token generated from the [appropriate endpoint.](https://docs.tryterra.co/reference/streaming-api/api-endpoints) [type](https://docs.tryterra.co/reference/streaming-api/websocket-reference#identifytype-enum) Integer Connection type. Value from the IdentifyType enum. [hashtag](https://docs.tryterra.co/reference/streaming-api/websocket-reference#identify-type-enum) Identify Type Enum -------------------------------------------------------------------------------------------------------------------------- Name Value User (Producer) 0 Developer (Consumer) 1 [hashtag](https://docs.tryterra.co/reference/streaming-api/websocket-reference#payload-format) Payload Format ------------------------------------------------------------------------------------------------------------------ Field Name Type Description op Integer [Opcode](https://docs.tryterra.co/reference/streaming-api/websocket-reference#opcodes) for the payload. d? Object Event data. uid?\* String User ID that the event relates to. seq?\* Long Sequence number of the payload. Used when replaying missed payloads. t?\* String The [Data Type](https://docs.tryterra.co/reference/streaming-api/websocket-reference#data-types) for the payload. circle-info `? -> Optional field` `* -> Only send with payloads of the`[`DISPATCH`](https://docs.tryterra.co/reference/streaming-api/websocket-reference#opcodes) `opcode` ### [hashtag](https://docs.tryterra.co/reference/streaming-api/websocket-reference#example-payload) Example Payload Dispatch Payload Client Payload Heartbeat Copy { "op": 5, "d": { "ts": "2022-05-04T10:26:11.268507+01:00", "val": 95 }, "uid": "8e864e3a-979a-4d04-b4e9-b6d020f20ba0", "seq": 73, "t": "HEART_RATE" } Copy { "op": 6, "d": { "val": 95 }, "t": "HEART_RATE" } **Heartbeat** Upon opening a websocket connection to the server, you will immediately be sent an `Op 2 HELLO` payload containing the heartbeat interval (in milliseconds) that the client should use when sending heartbeat messages to the server. Copy { "op": 2, "d": { "heartbeat_interval": 40000 } } Heartbeat Acknowledged Copy {"op": 1} // Sent back to the client by the server every "heartbeat_interval" ms [hashtag](https://docs.tryterra.co/reference/streaming-api/websocket-reference#opcodes) Opcodes ---------------------------------------------------------------------------------------------------- Name Value Description Sent By HEARTBEAT 0 Fired periodically by the client to keep the connection alive. Client HEARTBEAT\_ACK 1 Sent by the server to acknowledge that a heartbeat has been received. Server HELLO 2 Sent by the server immediately after connecting. Contains the heartbeat interval for the client to use. Server IDENTIFY 3 Sent by the client to complete the handshake with the server. Contains authentication details. Client READY 4 Sent by the server once the handshake has been completed. The client will be able to receive/send payloads immediately after this is received. Server DISPATCH 5 An event dispatched by the server. Contains details about the event, as well as the data payload for the event. Server SUBMIT 6 Sent by the client to notify the server of new data which will then be routed to the correct consumer appropriately. Client (producer only) REPLAY 7 Request a replay of payloads after the given lower bound, and optionally before a given upper bound. Client (consumer only) [hashtag](https://docs.tryterra.co/reference/streaming-api/websocket-reference#data-types) Data Types ---------------------------------------------------------------------------------------------------------- Name Description HEART\_RATE `val` is the BPM of each reading STEPS `val` the amount of accumulated steps DISTANCE `val` the accumulated distance in meters FLOORS\_CLIMBED `val` the accumulated floors climbed STEPS\_CADENCE `val` the amount of steps per second taken by the user SPEED `val` the speed in meter per second of the user ACCELERATION `d` the acceleration data of the device. - `d[0]` -> acceleration in x direction - `d[1]` -> acceleration in y direction - `d[2]` -> acceleration in z direction GYROSCOPE `d` the rotation rate of the device. - `d[0]` -> rotation in x direction - `d[1]` -> rotation in y direction - `d[2]` -> rotation in z direction ### [hashtag](https://docs.tryterra.co/reference/streaming-api/websocket-reference#close-codes) Close Codes Code Reason 1001 Server is shutting down 1007 Invalid or unrecognised JSON data was provided 4000 IDENTIFY payload expected but was not received 4001 Improper token was passed for IDENTIFY 4002 Duplicate connection opened 4003 Multiple IDENTIFY payloads received 4004 Unrecognised opcode was received [PreviousCore Conceptschevron-left](https://docs.tryterra.co/reference/streaming-api/core-concepts) [NextMobile SDKchevron-right](https://docs.tryterra.co/reference/streaming-api/reference) Last updated 1 year ago Was this helpful? * [Identify Data Schema](https://docs.tryterra.co/reference/streaming-api/websocket-reference#identify-data-schema) * [Identify Type Enum](https://docs.tryterra.co/reference/streaming-api/websocket-reference#identify-type-enum) * [Payload Format](https://docs.tryterra.co/reference/streaming-api/websocket-reference#payload-format) * [Example Payload](https://docs.tryterra.co/reference/streaming-api/websocket-reference#example-payload) * [Opcodes](https://docs.tryterra.co/reference/streaming-api/websocket-reference#opcodes) * [Data Types](https://docs.tryterra.co/reference/streaming-api/websocket-reference#data-types) * [Close Codes](https://docs.tryterra.co/reference/streaming-api/websocket-reference#close-codes) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Supported Integrations | API Reference | Terra Docs Integration Name Enum Value Devices Getting credentials Vald VALD [ForceFramearrow-up-right](https://valdperformance.com/products/forceframe) (Isometric strength tester) [ForceDecksarrow-up-right](https://valdperformance.com/products/forcedecks) (Force plates) [DynamMoarrow-up-right](https://valdperformance.com/products/dynamo) (Dynamometer) [NordBordarrow-up-right](https://valdperformance.com/products/nordbord) (Hamstring testing) [https://support.vald.com/hc/en-au/articles/15973572185625-Integrate-your-PMS-AMS-with-VALD-Hub#client-idarrow-up-right](https://support.vald.com/hc/en-au/articles/15973572185625-Integrate-your-PMS-AMS-with-VALD-Hub#client-id) Catapult CATAPULT [Vectorarrow-up-right](https://www.catapult.com/solutions/vector-pro) (GPS tracker vests) [https://support.catapultsports.com/hc/en-us/articles/360002186896-API-Tokensarrow-up-right](https://support.catapultsports.com/hc/en-us/articles/360002186896-API-Tokens) Kinexon KINEXON [Player trackingarrow-up-right](https://kinexon-sports.com/technology/player-tracking/) (IMUs, LPS, GPS, Video tracking) Get in touch with your Product Success Manager at Kinexon GymAware GYMAWARE [GymAware RSarrow-up-right](https://gymaware.com/gymaware-rs/) (Velocity-Based Training device) [Flexarrow-up-right](https://gymaware.com/product/flex-barbell-tracker/) (Barbell tracker) [https://gymaware.com/gymaware-cloud-api-integration-guide/#tokensarrow-up-right](https://gymaware.com/gymaware-cloud-api-integration-guide/#tokens) SpartScience SPARTASCIENCE [Force platesarrow-up-right](https://spartascience.com/) [https://success.spartascience.com/en/knowledge/integrations-and-api-accessarrow-up-right](https://success.spartascience.com/en/knowledge/integrations-and-api-access) [PreviousReact Nativechevron-left](https://docs.tryterra.co/reference/streaming-api/reference/react-native) [NextCore Conceptschevron-right](https://docs.tryterra.co/reference/teams-api/core-concepts) Was this helpful? Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Android (Kotlin) | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#android-functions) Android Functions ----------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#initializer) Initializer Copy class TerraRT( private var devId: String, private var context: Context, private var referenceId: String?, completion: (Boolean) -> Unit, ) * `devId`: your [developer ID](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#developer-id-dev-id) * `referenceId`: the [reference\_id](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#reference-id) for the [end user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#end-user) * `context`: the \[android.app.Activity\] context which you initialise this class in * `referenceId`: the user ID associated to the user in your system * `completion`: a completion function depicting if the initialisation was successful or not ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#connection-setup) **Connection Setup** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#initconnection) initConnection Initialise a connection with Terra's backend for the device * `token`: An authentication token that should be generated from the backend. * `callback`: A function called when the initialization is complete with a boolean indicating success. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#getuserid) getUserId A synchronous function that returns the current device's Terra user ID. * Returns `String?`: The user ID. If none exists, returns `null`. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#disconnect) disconnect Disconnects from a connection. * `type`: Enum representing the connection type to disconnect. * * * ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#device-connection-management) **Device Connection Management** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#startdevicescan) startDeviceScan Starts a device scan and allows the user to connect to a device. * `type`: The connection type you're trying to connect to. * `useCache`: If `true`, uses previously connected devices (default is `false`). * `showWidgetIfCacheNotFound`: if true, shows the connection widget if cached device is not found * `callback`: Called with a boolean after the connection is established. * `deviceCallback`: callback function called with \[Device\] object whenever a device is found #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#getconnecteddevices) getConnectedDevices Returns a set of devices that are currently connected * Returns `Set`, the set of currently connected devices * * * ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#data-streaming) **Data Streaming** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#startrealtime) startRealtime Starts streaming data for a given connection type. * `type`: Enum representing the connection type. * `token`: The token used for verification to connect to Terra’s API. * `dataTypes`: Enum representing the data types to stream. * `connectionCallback`: Called when a websocket connection is either successful or not. * `updateHandler`: Called when new updates are available from the device. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#stoprealtime) stopRealtime Stops streaming for a given connection type. * `type`: Enum representing the connection type to stop streaming for. [PreviousiOS (Swift)chevron-left](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift) [NextFlutterchevron-right](https://docs.tryterra.co/reference/streaming-api/reference/flutter) Was this helpful? * [Android Functions](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#android-functions) * [Initializer](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#initializer) * [Connection Setup](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#connection-setup) * [Device Connection Management](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#device-connection-management) * [Data Streaming](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#data-streaming) Was this helpful? sun-brightdesktopmoon Copy fun initConnection(token: String, callback: (Boolean) -> Unit) Copy fun getUserId(): String? Copy fun disconnect(type: Connections) Copy fun startDeviceScan( type: Connections, useCache: Boolean = false, showWidgetIfCacheNotFound: Boolean = true, callback: (Boolean) -> Unit = {_ -> } ) // second possible signature fun startDeviceScan( type: Connections, deviceCallback: (Boolean) -> Unit = {_ -> } ) Copy fun getConnectedDevices(): Set Copy fun startRealtime( type: Connections, dataTypes: Set, token: String? = null, updateHandler: ((Update) -> Unit)? = null, connectionCallback: ((Boolean) -> Unit)? = {_ -> } ) // alternative signature, used for streaming data locally without // sending data to Terra Websocket API fun startRealtime( type: Connections, dataTypes: Set = setOf(), updateHandler: (Update) -> Unit ) Copy fun stopRealtime(type: Connections) sun-brightdesktopmoon --- # Samples | API Reference | Terra Docs ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#menstruationflowsample) MenstruationFlowSample Copy { "timestamp": String, "flow": MenstruationFlow } ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#dailypatternsample-beta-subject-to-change) DailyPatternSample (BETA - subject to change) Copy { "time_from_midnight": int, "percentile_5": Number, "percentile_25": Number, "percentile_50": Number, "percentile_75": Number, "percentile_95": Number } ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#drinksample) DrinkSample Copy { "timestamp": String, // required "drink_volume": Number, // numeric quantity "drink_unit": String, // e.g. "ml", "fl oz" "drink_name": String } ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#ketonesample) KetoneSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#torquesample) TorqueSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#ecgreading) ECGReading ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#glucosedatasample) GlucoseDataSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#heartratedatasample) HeartRateDataSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#lapsample) LapSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#heartratevariabilitydatasamplermssd) HeartRateVariabilityDataSampleRMSSD ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#heartratevariabilitydatasamplesdnn) HeartRateVariabilityDataSampleSDNN ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#heartratezonedata) HeartRateZoneData ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#floorsclimbedsample) FloorsClimbedSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#caloriesample) CalorieSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#distancesample) DistanceSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#stepsample) StepSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#elevationsample) ElevationSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#positionsample) PositionSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#powersample) PowerSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#speedsample) SpeedSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#cadencesample) CadenceSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#activitylevelsample) ActivityLevelSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#metsample) METSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#tsssample) TSSSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#sleephypnogramsample) SleepHypnogramSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#oxygensaturationsample) OxygenSaturationSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#breathsample) BreathSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#rawecgsample) RawECGSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#snoringsample) SnoringSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#stresssample) StressSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#bodybatterysample) BodyBatterySample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#bloodpressuresample) BloodPressureSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#measurementdatasample) MeasurementDataSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#temperaturesample) TemperatureSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#otherdevicedata) OtherDeviceData ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#hydrationlevelsample) HydrationlevelSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#hydrationmeasurementsample) HydrationMeasurementSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#vo2maxsample) Vo2MaxSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#pulsevelocitysample) PulseVelocitySample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#afibclassificationsample) AFibClassificationSample ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#meal) Meal ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#tagentry) TagEntry ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/samples#rrinterval) RRInterval [PreviousData modelschevron-left](https://docs.tryterra.co/reference/health-and-fitness-api/data-models) [NextCore conceptschevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts) Last updated 9 months ago Was this helpful? * [MenstruationFlowSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#menstruationflowsample) * [DailyPatternSample (BETA - subject to change)](https://docs.tryterra.co/reference/health-and-fitness-api/samples#dailypatternsample-beta-subject-to-change) * [DrinkSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#drinksample) * [KetoneSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#ketonesample) * [TorqueSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#torquesample) * [ECGReading](https://docs.tryterra.co/reference/health-and-fitness-api/samples#ecgreading) * [GlucoseDataSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#glucosedatasample) * [HeartRateDataSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#heartratedatasample) * [LapSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#lapsample) * [HeartRateVariabilityDataSampleRMSSD](https://docs.tryterra.co/reference/health-and-fitness-api/samples#heartratevariabilitydatasamplermssd) * [HeartRateVariabilityDataSampleSDNN](https://docs.tryterra.co/reference/health-and-fitness-api/samples#heartratevariabilitydatasamplesdnn) * [HeartRateZoneData](https://docs.tryterra.co/reference/health-and-fitness-api/samples#heartratezonedata) * [FloorsClimbedSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#floorsclimbedsample) * [CalorieSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#caloriesample) * [DistanceSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#distancesample) * [StepSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#stepsample) * [ElevationSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#elevationsample) * [PositionSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#positionsample) * [PowerSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#powersample) * [SpeedSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#speedsample) * [CadenceSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#cadencesample) * [ActivityLevelSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#activitylevelsample) * [METSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#metsample) * [TSSSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#tsssample) * [SleepHypnogramSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#sleephypnogramsample) * [OxygenSaturationSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#oxygensaturationsample) * [BreathSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#breathsample) * [RawECGSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#rawecgsample) * [SnoringSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#snoringsample) * [StressSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#stresssample) * [BodyBatterySample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#bodybatterysample) * [BloodPressureSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#bloodpressuresample) * [MeasurementDataSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#measurementdatasample) * [TemperatureSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#temperaturesample) * [OtherDeviceData](https://docs.tryterra.co/reference/health-and-fitness-api/samples#otherdevicedata) * [HydrationlevelSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#hydrationlevelsample) * [HydrationMeasurementSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#hydrationmeasurementsample) * [Vo2MaxSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#vo2maxsample) * [PulseVelocitySample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#pulsevelocitysample) * [AFibClassificationSample](https://docs.tryterra.co/reference/health-and-fitness-api/samples#afibclassificationsample) * [Meal](https://docs.tryterra.co/reference/health-and-fitness-api/samples#meal) * [TagEntry](https://docs.tryterra.co/reference/health-and-fitness-api/samples#tagentry) * [RRInterval](https://docs.tryterra.co/reference/health-and-fitness-api/samples#rrinterval) Was this helpful? sun-brightdesktopmoon Copy { "timestamp": String, // required "ketone_mg_per_dL": Number, // required "sample_type": Number // device‑specific enum } Copy { "timestamp": String, // required – ISO‑8601 "timer_duration_seconds": Number, "torque_newton_meters": Number } Copy { "start_timestamp": String, "avg_hr_bpm": Number, "afib_classification": AFibFlag, "raw_signal": Array } Copy { "timestamp": String, "blood_glucose_mg_per_dL": Number, "glucose_level_flag": Number, "trend_arrow": Number, } Copy { "timestamp": String, "bpm": Number, "timer_duration_seconds": Number, "context": HeartRateContext } Copy { "start_time": String, "end_time": String, "distance_meters": Number, "calories": Number, "total_strokes": Number, "stroke_type": StrokeType, "avg_speed_meters_per_second": Number } Copy { "timestamp": String, "hrv_rmssd": Number } Copy { "timestamp": String, "hrv_sdnn": Number } Copy { "zone": HeartRateZone, "start_percentage": Number, "end_percentage": Number, "name": String, "duration_seconds": Number } Copy { "timestamp": String, "floors_climbed": Number, "timer_duration_seconds": Number } Copy { "timestamp": String, "calories": Number, "timer_duration_seconds": Number } Copy { "timestamp": String, "distance_meters": Number, "timer_duration_seconds": Number } Copy { "timestamp": String, "steps": Number, "timer_duration_seconds": Number } Copy { "timestamp": String, "elev_meters": Number, "timer_duration_seconds": Number } Copy { "timestamp": String, "coords_lat_lng_deg": [Number, Number], "timer_duration_seconds": Number } Copy { "timestamp": String, "watts": Number, "timer_duration_seconds": Number } Copy { "timestamp": String, "speed_meters_per_second": Number, "timer_duration_seconds": Number } Copy { "timestamp": String, "cadence_rpm": Number, "timer_duration_seconds": Number } Copy { "timestamp": String, "level": ActivityLevel } Copy { "timestamp": String, "level": Number } Copy { "planned": Number, "actual": Number, "method": String, "intensity_factor_planned": Number, "intensity_factor_actual": Number, "normalized_power_watts": Number } Copy { "timestamp": String, "level": SleepLevel } Copy { "timestamp": String, "percentage": Number } Copy { "timestamp": String, "breaths_per_min": Number } Copy { "potential_uV": Number, "timestamp: String } Copy { "timestamp": String, "duration_seconds": Number } Copy { "timestamp": String, "level": Number } Copy { "timestamp": String, "level": Number } Copy { "timestamp": String, "diastolic_bp": Number, "systolic_bp": Number } Copy { "measurement_time": String, "BMI": Number, "BMR": Number, "RMR": Number, "estimated_fitness_age": Number, "skin_fold_mm": Number, "bodyfat_percentage": Number, "weight_kg": Number, "height_cm": Number, "bone_mass_g": Number, "muscle_mass_g": Number, "lean_mass_g": Number, "water_percentage": Number, "insulin_units": Number, "insulin_type": String, "urine_color": String, "user_notes": String } Copy { "timestamp": String, "temperature_celsius": Number } Copy { "name": String, "manufacturer": String, "serial_number": String, "software_version": String, "hardware_version": String, "last_upload_date": String, "data_provided": Array } Copy { "timestamp": String, "hydration_level": Number } Copy { "timestamp": String, "hydration_kg": Number } Copy { "timestamp": String, "vo2max_ml_per_min_per_kg": Number } Copy { "timestamp": String, "pulse_wave_velocity_meters_per_second": Number } Copy { "timestamp": String, "afib_classification": AfibFlag } Copy { "name": String, "id": String, "timestamp": String, "type": Number, "quantity": { "unit": NutritionUnits, "amount": Number }, "macros": { "calories": Number, "protein_g": Number, "carbohydrates_g": Number, "fat_g": Number, "sugar_g": Number, "cholesterol_mg": Number, "fiber_g": Number, "sodium_mg": Number, "alcohol_g": Number }, "micros": { "selenium_mg": Number, "niacin_mg": Number, "magnesium_mg": Number, "copper_mg": Number, "vitamin_B12_mg": Number, "vitamin_B6_mg": Number, "vitamin_C_mg": Number, "zinc_mg": Number, "vitamin_E_mg": Number, "manganese_mg": Number, "vitamin_D_mg": Number, "iodine_mg": Number, "chloride_mg": Number, "folate_mg": Number, "calcium_mg": Number, "molybdenum_mg": Number, "vitamin_A_mg": Number, "riboflavin_mg": Number, "folic_acid_mg": Number, "iron_mg": Number, "thiamin_mg": Number, "pantothenic_acid_mg": Number, "caffeine_mg": Number, "vitamin_K_mg": Number, "chromium_mg": Number, "potassium_mg": Number, "biotin_mg": Number, "phosphorus_mg": Number } } Copy { "timestamp": String, "tag_name": String, "notes": String } Copy { "timestamp": String, "rr_interval_ms": Number, "hr_bpm": Number } sun-brightdesktopmoon --- # Pricing | Terra Docs Terra’s Health & Fitness API uses transparent, usage-based pricing powered by credits. This page explains how it works. circle-check [hashtag](https://docs.tryterra.co/health-and-fitness-api/pricing#at-a-glance) At a glance ----------------------------------------------------------------------------------------------- ✅ 100,000 included credits that reset monthly 🪜 Tiered pricing + discounts that rewards user growth 💸 If your project blows-up over night, we’ll have your back 🧘 You're likely never paying extra until you're ready to scale, see details below * [How do credits work?](https://docs.tryterra.co/health-and-fitness-api/pricing#how-do-credits-work) * [How much does a credit cost?](https://docs.tryterra.co/health-and-fitness-api/pricing#terras-pricing-scales-with-your-business) * [How are credits consumed?](https://docs.tryterra.co/health-and-fitness-api/pricing#how-credits-are-consumed) * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/pricing#understanding-credits) Understanding credits ------------------------------------------------------------------------------------------------------------------- 1. **Monthly allowance:** Your subscription gives you 100,000 free credits each month. 2. **Usage:** Health & Fitness API usage consumes credits, based on connected users and events. 3. **Monthly reset:** Credits reset to 100,000 each billing period and do not roll over.x 4. **Scaling:** Only pay for credits beyond your 100,000 monthly allowance. Additional usage is billed monthly. 5. **Volume Discount:** The more credits you use, the cheaper each one gets (tiered pricing). * * * ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/pricing#terras-pricing-scales-with-your-business) Terra’s pricing scales with your business Your Terra subscription includes 100,000 monthly credits - covering the needs of most startups during their initial launch and growth phases. Tiered pricing applies beyond this: **Total Monthly Credits Consumed** **Cost per Additional Credit** 0 - 100,000 $0 (Included in subscription) 100,001 - 1,000,000 $0.005 1,000,001+ $0.003 circle-check [hashtag](https://docs.tryterra.co/health-and-fitness-api/pricing#unexpected-usage-spike-led-to-a-surprise-bill) Unexpected usage spike led to a surprise bill? -------------------------------------------------------------------------------------------------------------------------------------------------------------------- **Usage Spike Protection has your back.** * We understand that rapid growth (especially for startups) or testing errors can cause unforeseen costs. That's why our **Usage Spike Protection** is here to ensure you're not penalised. * If you receive an **unexpectedly large bill** in your **initial 6 months** due to a significant spike from rapid user growth or a testing/integration error, you may be eligible for a **one-time refund**. (Specific criteria apply, such as bill threshold or usage increase). * Simply reach out to our support team. We'll review your situation, work towards refunding the unexpected amount, and help you optimise future usage. * **We believe in growing** with our developers **for the long term**, and that means supporting you when things take off faster than planned, or when something simply goes wrong. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/pricing#how-credits-are-consumed) How credits are consumed ------------------------------------------------------------------------------------------------------------------------- Credits are consumed by usage of Terra's Health & Fitness API. The number of credits consumed monthly scales with your number of users (active authentications) and events. ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/pricing#unified-health-api-credits) Unified Health API credits About Active authentications Events **What it is** An active authentication represents an end-user's wearable, sensor, or fitness app that has been authenticated with Terra Data payloads and notifications sent by Terra to your backend. This includes: * _Data Sync Events:_ Health, activity, sleep, workout data, etc. * _Authentication Events:_ User authentication status or permission updates. **How it's measured** An active authentication represents a health data source that both: 1. Has been authenticated by an end user 2. Has not been deauthenticated Each individual event transmission is counted. * Example: A webhook sending a Daily payload for one end-user is one event * Free tier: 400 events per active authentication * _95% of customers are never charged for events_ **Cost** 200 credits per active authentication per month The first 400 events per active authentication are free. 0.5 credits per event beyond this. ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/pricing#blood-report-api-credits) Blood Report API credits About Biomarker **What it is** A biomarker represents a single standardized clinical measurement extracted, normalized, and structured from a lab report (e.g. LDL-C, HbA1c, CRP). Biomarkers may originate from different labs but are returned in a consistent, machine-readable format. **How it's measured** Each biomarker parsed counts toward usage. Multiple biomarkers can be extracted from a single lab report. **Cost** The first 3500 biomarkers are included. 30 credits per biomarker beyond this. [PreviousTroubleshootingchevron-left](https://docs.tryterra.co/health-and-fitness-api/debugging-faq) [NextHealth Scoreschevron-right](https://docs.tryterra.co/user-engagement/health-scores) Last updated 1 month ago Was this helpful? * [Understanding credits](https://docs.tryterra.co/health-and-fitness-api/pricing#understanding-credits) * [Terra’s pricing scales with your business](https://docs.tryterra.co/health-and-fitness-api/pricing#terras-pricing-scales-with-your-business) * [How credits are consumed](https://docs.tryterra.co/health-and-fitness-api/pricing#how-credits-are-consumed) * [Unified Health API credits](https://docs.tryterra.co/health-and-fitness-api/pricing#unified-health-api-credits) * [Blood Report API credits](https://docs.tryterra.co/health-and-fitness-api/pricing#blood-report-api-credits) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Core Concepts | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/teams-api/core-concepts#coach) Coach -------------------------------------------------------------------------------------- An entity or person who manages multiple athletes. This could represent a sports club, an actual coach, or a gym. [hashtag](https://docs.tryterra.co/reference/teams-api/core-concepts#athlete) Athlete ------------------------------------------------------------------------------------------ An individual who is tied back to a [Coach](https://docs.tryterra.co/reference/teams-api/core-concepts#coach) . An Athlete cannot exist without a coach it is attached to. [PreviousSupported Integrationschevron-left](https://docs.tryterra.co/reference/teams-api/supported-integrations) [NextAPI Endpointschevron-right](https://docs.tryterra.co/reference/teams-api/api-endpoints) Was this helpful? * [Coach](https://docs.tryterra.co/reference/teams-api/core-concepts#coach) * [Athlete](https://docs.tryterra.co/reference/teams-api/core-concepts#athlete) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Event types | API Reference | Terra Docs circle-info Every request made to Terra, and every event sent from Terra will contain a `terra-reference` header containing a unique identifier for the request or event. The `terra-reference` identifier uniquely ties together a request -> event pair, whenever a request for data leads to data being asynchronously sent to your server. This can be useful for keeping track of whether or not a data transfer request has been fulfilled, or is still pending transfer [hashtag](https://docs.tryterra.co/reference/teams-api/event-types#coach) Coach ------------------------------------------------------------------------------------ chevron-rightCoach registration[hashtag](https://docs.tryterra.co/reference/teams-api/event-types#coach-registration) **Slug:** coach.registered **Trigger:** A [Coach](https://docs.tryterra.co/reference/teams-api/core-concepts#coach) has authenticated under your developer ID **Recommended action:** **Save the** [**Coach**](https://docs.tryterra.co/reference/teams-api/core-concepts#coach) **to your database** **Format:** Copy { "data": Coach, "message": "Coach has successfully registered", "type": "coach.registered" } [hashtag](https://docs.tryterra.co/reference/teams-api/event-types#athlete) Athlete ---------------------------------------------------------------------------------------- chevron-rightAthlete creation[hashtag](https://docs.tryterra.co/reference/teams-api/event-types#athlete-creation) **Slug:** `athlete.registered` **Trigger:** One or more athletes have been registered under an associated coach **Recommended action:** Save the [athletes](https://docs.tryterra.co/reference/teams-api/core-concepts#athlete) to your database, and make a PATCH for each athlete to attach the appropriate reference ID to them **Format:** Copy { "data": Coach, "message": "One or more Athletes have been successfully registered", "type": "athlete.registered" } chevron-rightAthlete deletion[hashtag](https://docs.tryterra.co/reference/teams-api/event-types#athlete-deletion) **Slug:** `athlete.deleted` **Trigger:** One or more athletes have been deleted **Recommended action:** Remove the [athletes](https://docs.tryterra.co/reference/teams-api/core-concepts#athlete) ' information from your database as per your requirements, or acknowledge that these have been deleted on the providers' system **Format:** Copy { "data": [athlete], "message": "One or more Athletes have been deleted", "type": "athlete.deleted" } [hashtag](https://docs.tryterra.co/reference/teams-api/event-types#data-requests) Data requests ---------------------------------------------------------------------------------------------------- chevron-rightTests retrieved[hashtag](https://docs.tryterra.co/reference/teams-api/event-types#tests-retrieved) **Slug:** `test.retrieved` **Trigger:** One or more tests have been retrieved **Recommended action:** Save the tests' data as per your requirements, and update any existing tests based on the tests' unique IDs **Format:** chevron-rightActivities retrieved[hashtag](https://docs.tryterra.co/reference/teams-api/event-types#activities-retrieved) **Slug:** `activity.retrieved` **Trigger:** One or more activities have been retrieved **Recommended action:** Save the activities' data as per your requirements, and update any existing tests based on the activities' unique IDs **Format:** [PreviousAPI Endpointschevron-left](https://docs.tryterra.co/reference/teams-api/api-endpoints) Was this helpful? * [Coach](https://docs.tryterra.co/reference/teams-api/event-types#coach) * [Athlete](https://docs.tryterra.co/reference/teams-api/event-types#athlete) * [Data requests](https://docs.tryterra.co/reference/teams-api/event-types#data-requests) Was this helpful? sun-brightdesktopmoon Copy { "data": [Test], "coach": Coach, "type": "test.retrieved" } Copy { "data": [Activity], "coach": Coach, "type": "activity.retrieved" } sun-brightdesktopmoon --- # Destinations | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#webhook) Webhook ------------------------------------------------------------------------------------------------------ Webhooks are the most basic [Destination](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) to set up, and involve Terra making a POST request to a predefined callback URL you pass in when setting up the Webhook. They are automated messages sent from apps when something happens. Terra uses webhooks to notify you whenever new data is made available for any of your users. New data, such as activity, sleep, etc will be normalised and sent to your webhook endpoint URL where you can process it however you see fit. After a user authenticates with your service through Terra, you will automatically begin receiving webhook messages containing data from their wearable.. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#security) Security Exposing a URL on your server can pose a number of security risks, allowing a potential attacker to * **Launch denial of service (DoS) attacks** to overload your server. * **Tamper with data** by sending malicious payloads. * **Replay legitimate requests** to cause duplicated actions. among other exploits. In order to secure your URL, Terra offers two separate methods of securing your URL endpoint ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#payload-signing) Payload signing Every webhook sent by Terra will include HMAC-based signature header `terra-signature` , which will take the form: Copy t=1723808700,v1=a5ee9dba96b4f65aeff6c841aa50121b1f73ec7990d28d53b201523776d4eb00 In order to verify the payload, you may use one of Terra's SDKs as follows: circle-exclamation Terra requires the **raw, unaltered** body of the request to perform signature verification. If you’re using a framework, make sure it doesn’t manipulate the raw body (many frameworks do by default) **Any** manipulation to the raw body of the request causes the verification to fail. Python SDK Javascript SDK Java SDK Manual verification We recommend that you use our official libraries to verify webhook event signatures. You can however create a custom solution by following this section. The `terra-signature` header included in each signed event contains **a timestamp** and **one or more signatures** that you must verify. * the timestamp is prefixed by `t=` * each signature is prefixed by a _**scheme**_. Schemes start with `v`, followed by an integer. (e.g. `v1`) Terra generates signatures using a hash-based message authentication code ([HMACarrow-up-right](https://en.wikipedia.org/wiki/Hash-based_message_authentication_code) ) with [SHA-256arrow-up-right](https://en.wikipedia.org/wiki/SHA-2) . To prevent [downgrade attacksarrow-up-right](https://en.wikipedia.org/wiki/Downgrade_attack) , ignore all schemes that aren’t `v1` To create a manual solution for verifying signatures, you must complete the following steps: **Step 1: Extract the timestamp and signatures from the header** Split the header using the `,` character as the separator to get a list of elements. Then split each element using the `=` character as the separator to get a prefix and value pair. The value for the prefix `t` corresponds to the timestamp, and `v1` corresponds to the signature (or signatures). You can discard all other elements. **Step 2: Prepare the** `**signed_payload**`**string** The `signed_payload` string is created by concatenating: * The timestamp (as a string) * The character `.` * The actual JSON payload (that is, the request body) **Step 3: Determine the expected signature**![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Fb.stripecdn.com%2Fdocs-statics-srv%2Fassets%2Ffcc3a1c24df6fcffface6110ca4963de.svg&width=300&dpr=3&quality=100&sign=35dcfeaf&sv=2) Compute an HMAC with the SHA256 hash function. Use the endpoint’s signing secret as the key, and use the `signed_payload` string as the message. **Step 4: Compare the signatures**![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Fb.stripecdn.com%2Fdocs-statics-srv%2Fassets%2Ffcc3a1c24df6fcffface6110ca4963de.svg&width=300&dpr=3&quality=100&sign=35dcfeaf&sv=2) Compare the signature (or signatures) in the header to the expected signature. For an equality match, compute the difference between the current timestamp and the received timestamp, then decide if the difference is within your tolerance. To protect against timing attacks, use a constant-time-string comparison to compare the expected signature to each of the received signatures. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#ip-whitelisting) IP Whitelisting IP Whitelisting allows you to only allow requests from a preset list of allowed IPs. An attacker trying to reach your URL from an IP outside this list will have their request rejected. The IPs from which Terra may send a Webhook are: * **18.133.218.210** * **18.169.82.189** * **18.132.162.19** * **18.130.218.186** * **13.43.183.154** * **3.11.208.36** * **35.214.201.105** * **35.214.230.71** * **35.214.252.53** * **35.214.229.114** ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#retries) **Retries** If your server fails to respond with a 2XX code (either due to timing out, or responding with a 3XX, 4XX or 5XX HTTP code), requests to it will be retried with exponential backoff around 8 times over the course of just over a day. [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#sql-database) SQL Database ---------------------------------------------------------------------------------------------------------------- SQL databases are easy to set up and often the go-to choices for less abstracted storage solutions. Terra currently supports **Postgres & MySQL**. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#setup) Setup You will need to ensure your SQL database is **publicly accessible**. As a security measure, you may implement [IP whitelisting](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#security-ip-whitelisting) using the list of IPs above. Next, create a user with enough permissions to create tables & have read & write access within those tables. You can execute the scripts below based on your database Postgres MySQL ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#data-structure) Data Structure Data will be stored in tables within your SQL database following the structure below: ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Fcontent.gitbook.com%2Fcontent%2FeJJpVMsUARUJq9lYmL6t%2Fblobs%2FJpYM3irK3pkVvzxw2jfb%2Fimage.png&width=768&dpr=3&quality=100&sign=33472265&sv=2) [Users](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) will be created in the `terra_users` table, [data payloads](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#data-events) will be placed in the `terra_data_payloads`, and all other [payloads](https://docs.tryterra.co/reference/health-and-fitness-api/event-types) sent will be added to the `terra_other_payloads`. circle-info When using [SQL](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#sql-database) as a destination, Terra handles data storage for you. All [data payloads](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#data-events) will be stored in a Terra-owned S3 bucket, and the download link for each payload will be found under the `payload_url` column [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#supabase) Supabase -------------------------------------------------------------------------------------------------------- [Supabasearrow-up-right](https://supabase.com/) offers the best of both worlds in terms of allowing you to have both [storage **buckets**arrow-up-right](https://supabase.com/docs/guides/storage) and [Postgres SQL **tables**arrow-up-right](https://supabase.com/docs/guides/database/tables) **.** Both coexist within the same platform, making development a breeze. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#setup-1) Setup 1. [Create a storage bucketarrow-up-right](https://supabase.com/docs/guides/storage/buckets/creating-buckets) with an appropriate name (e.g. **terra-payloads**) in your project 2. [Create a tablearrow-up-right](https://supabase.com/docs/guides/database/tables#creating-tables) within your project. You do not need to add columns to it, Terra will handle that when connecting to it. 3. [Create an API keyarrow-up-right](https://supabase.com/docs/guides/api/api-keys#the-servicerole-key) for access to your supabase project. Terra will need read & write access to the previously created resources in steps 1 and 2. You'll then need to enter the above details (host, bucket name, and API key) into your Terra Dashboard when adding the Supabase destination ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#data-structure-1) Data Structure When using Supabase (since you get the best of SQL and S3 buckets 🎉) Terra stores the data in the same structure as for [SQL](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#data-structure) and for [S3 Buckets](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#data-structure-2) . Follow those sections for more detailed information on how that is stored! [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#aws-destinations) AWS Destinations ------------------------------------------------------------------------------------------------------------------------ All AWS-based destinations follow the same authentication setup. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#setup-2) Setup #### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#iam-user-access-key) IAM User Access Key The most basic way to allow Terra to write to your AWS resource is to [create an IAM userarrow-up-right](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html) with access limited to the resource you're trying to grant Terra access to. [Attach relevant policiesarrow-up-right](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_change-permissions.html) for access to the specific resource, (write access is generally the only one needed, unless specified otherwise) #### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#role-based-access) Role-based access In order to use role-based access, attach the following policy to your bucket: [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#gcp-destinations) GCP Destinations ------------------------------------------------------------------------------------------------------------------------ You'll need to create a service account, and generate credentials for it. See the guide [herearrow-up-right](https://developers.google.com/workspace/guides/create-credentials#service-account) for further details. once you have generated credentials, download the JSON file with the credentials you just created, and upload it in the corresponding section when setting up your GCP-based destination [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#buckets-aws-s3-gcp-gcs) Buckets: AWS S3/GCP GCS ------------------------------------------------------------------------------------------------------------------------------------- Terra allows you to connect an [S3 Bucketarrow-up-right](https://aws.amazon.com/s3/) as a destination, to get all data dumped directly into a bucket of your choice. Follow the [AWS Setup](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#setup-2) /GCP Setup section for setting up credentials for it ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#data-structure-2) Data Structure When data is sent to your [**S3 Bucket**arrow-up-right](https://aws.amazon.com/s3/) or [**GCS**arrow-up-right](https://cloud.google.com/storage) , it will be dumped using the following folder structure ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Fcontent.gitbook.com%2Fcontent%2FeJJpVMsUARUJq9lYmL6t%2Fblobs%2F5MqKqhPJZy7QYEAyY5JE%2Fimage.png&width=768&dpr=3&quality=100&sign=fac20daa&sv=2) Example for AWS S3 [Versioned](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#api-versions) objects will be placed under the appropriate [API version](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#api-versions) (in the screenshot above, this corresponds to `2022-03-16`. Non versioned objects (e.g. [authentication Events](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#authentication) ) will be placed in their appropriate event type folder, outside of the version folder In all, every event will have as a parent folder the [Event Type](https://docs.tryterra.co/reference/health-and-fitness-api/event-types) which it corresponds to, and will be saved with a unique name identifying it. As shown above, the name will either be a concatenation of one of the below: * For [Data Events](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#data-events) : the user ID & the start time of the period the event refers to * For all other [Event Types](https://docs.tryterra.co/reference/health-and-fitness-api/event-types) : the user ID & timestamp the event was generated at [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#aws-sqs-simple-queue-service) AWS SQS (Simple Queue Service) -------------------------------------------------------------------------------------------------------------------------------------------------- [AWS SQSarrow-up-right](https://aws.amazon.com/sqs/) is a managed queuing system allowing you to get messages delivered straight into your existing queue, minimizing the potential of disruptions and barriers that may occur when ingesting a request from Terra API to your server. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#data-structure-3) Data Structure Data sent to SQS can either take the type of `healthcheck` or `s3_payload`. See [Event Types](https://docs.tryterra.co/reference/health-and-fitness-api/event-types) for further details. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Fcontent.gitbook.com%2Fcontent%2FeJJpVMsUARUJq9lYmL6t%2Fblobs%2FuJoLlwdnUyuZqakWVLez%2Fimage.png&width=768&dpr=3&quality=100&sign=51a27102&sv=2) Each of these payloads will be a simple JSON payload formatted as in the diagram above. the `url` field in the data payload will be a download link from which you will need to download the data payload using a `GET` request. This is done to minimize the size of messages in your queue. The URL will be a [pre-signed linkarrow-up-right](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html) to an object stored in one of Terra's S3 buckets. circle-info **Note:** Terra offers the possibility of using your own S3 bucket in combination with the SQS destination. For setting this up, kindly contact Terra support. [PreviousCore conceptschevron-left](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts) [NextMobile SDKchevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references) Last updated 2 months ago Was this helpful? * [Webhook](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#webhook) * [Security](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#security) * [Payload signing](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#payload-signing) * [IP Whitelisting](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#ip-whitelisting) * [Retries](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#retries) * [SQL Database](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#sql-database) * [Setup](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#setup) * [Data Structure](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#data-structure) * [Supabase](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#supabase) * [Setup](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#setup-1) * [Data Structure](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#data-structure-1) * [AWS Destinations](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#aws-destinations) * [Setup](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#setup-2) * [GCP Destinations](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#gcp-destinations) * [Buckets: AWS S3/GCP GCS](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#buckets-aws-s3-gcp-gcs) * [Data Structure](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#data-structure-2) * [AWS SQS (Simple Queue Service)](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#aws-sqs-simple-queue-service) * [Data Structure](https://docs.tryterra.co/reference/health-and-fitness-api/destinations#data-structure-3) Was this helpful? sun-brightdesktopmoon Copy import os ​ from flask import Flask, jsonify, request from terra.utils.verify_signature import verify_terra_webhook_signature ​ app = Flask(__name__) ​ signing_secret = os.getenv('SIGNING_SECRET') # Your signing secret from Terra ​ ​ @app.route('/webhook', methods=['POST']) def handle_webhook(): signature = request.headers.get('terra-signature') body = request.get_data(as_text=True) ​ if signature is None: return jsonify({"error": "terra-signature header missing"}), 400 ​ try: is_valid = verify_terra_webhook_signature( payload=body, signature_header=signature, signing_secret=signing_secret ) if not is_valid: return jsonify({"error": "Invalid signature"}), 400 ​ # Process the webhook data here webhook_data = request.get_json() print(f"Received valid webhook data: {webhook_data}") ​ return jsonify({"message": "Webhook received successfully"}), 200 ​ except Exception as e: return jsonify({"error": str(e)}), 500 ​ ​ if __name__ == '__main__': app.run(port=8000) Copy const express = require("express"); const { verifyTerraWebhookSignature } = require("terra-api"); const app = express(); // Use the built-in Express middleware to parse raw JSON bodies. // This must be placed before the webhook endpoint. app.use( express.raw({ inflate: true, limit: "4000kb", // Set a limit appropriate for your use case type: "application/json", }) ); // Make the route handler function async app.post("/consumeTerraWebhook", async (req, res) => { try { const signature = req.headers["terra-signature"]; const secret = process.env.TERRA_SECRET; // First, verify the signature. The function will throw an error if verification fails. // The req.body is a Buffer, which is the expected format. await verifyTerraWebhookSignature(req.body, signature, secret); // If verification is successful, send a 200 OK response immediately. res.sendStatus(200); // Process the data *after* responding to prevent timeouts. const data = JSON.parse(req.body.toString("utf8")); console.log("Received & Verified Terra Webhook Data:"); console.log(JSON.stringify(data, null, 2)); } catch (error) { // If verifyTerraWebhookSignature throws an error, catch it here. console.error("Webhook verification failed:", error.message); return res.sendStatus(401); // Respond with Unauthorized } }); const port = process.env.PORT || 3000; app.listen(port, () => { console.log(`Server started on http://localhost:${port}`); }); Copy import co.tryterra.terraclient.TerraClientFactory; import co.tryterra.terraclient.api.TerraApiResponse; import co.tryterra.terraclient.api.TerraClientV2; import co.tryterra.terraclient.api.User; import co.tryterra.terraclient.exceptions.TerraRuntimeException; import co.tryterra.terraclient.models.Athlete; import co.tryterra.terraclient.WebhookHandlerUtility ``` // Using the Spark framework (http://sparkjava.com) public Object handle(Request request, Response response) { String payload = request.body(); String sigHeader = request.headers("terra-signature"); // Find your secret on https://dashboard.tryterra.co/dashboard/connections WebhookHandlerUtility handlerUtility = WebhookHandlerUtility("SIGNING_SECRET"); Bool validSignature = handlerUtility.verifySignature(sigHeader, payload); if (!validSignature) { // the signature is invalid response.status(401); return ""; } // Deserialize the object inside the event & handle the event // ... response.status(200); return ""; } Copy terra-signature: t=1492774577, v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd, v0=6ffbb59b2300aae63f272406069a9788598b792a944a07aba816edb039989a39 Copy CREATE USER terra_user WITH PASSWORD 'your_password'; GRANT CONNECT ON DATABASE your_database_name TO terra_user; GRANT USAGE ON SCHEMA public TO terra_user; GRANT CREATE ON SCHEMA public TO terra_user; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO terra_user; Copy CREATE USER 'terra_user'@'%' IDENTIFIED BY 'your_password'; GRANT CREATE, SELECT, INSERT, UPDATE, DELETE ON your_database_name.* TO 'terra_user'@'%'; REVOKE ALL PRIVILEGES ON your_database_name.existing_table FROM 'terra_user'@'%'; Copy { "Version": "2012-10-17", "Statement": [\ {\ "Effect": "Allow",\ "Principal": {\ "AWS": "arn:aws:iam::760292141147:role/EC2_Instance_Perms"\ },\ "Action": [\ "s3:GetObject",\ "s3:PutObject",\ "s3:DeleteObject"\ ],\ "Resource": "arn:aws:s3:::your-bucket-name/*"\ }\ ] } sun-brightdesktopmoon --- # React Native | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#terra-initialization) **Terra initialization** --------------------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#initterra) initTerra Copy function initTerra( devID: string, referenceId: string, ): Promise `devId: string` ➡ The dev-id provided to you when signing up with Terra [Developer Dashboardarrow-up-right](doc:developer-dashboard) `referenceId: string` ➡ A random string used to characterise a user on your server **returns** `Promise` [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#connection-setup-magement) **Connection setup/magement** ------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#initconnection) **initConnection** Copy function initConnection( connection: Connections, token: string, schedulerOn: boolean, customPermissions: CustomPermissions[] = [], startIntent: String | null = null ): Promise Initialise a device connection. This function needs to be called once only when first creating the connection. * `connection: Connections` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. (E.g. `Connections.APPLE_HEALTH`, `Connections.SAMSUNG` , `Connections.HEALTH_CONNECT`) * `token: string` ➡ A token used for authentication. Generate one here: [https://docs.tryterra.co/reference/generate-authentication-tokenarrow-up-right](https://docs.tryterra.co/reference/generate-authentication-token) * (Optional) `customPermissions: Set` ➡ This is defaulted as an empty `Set`. If you want to make a more granular permissions request, you may send us a set of `CustomPermissions` * `startIntent: String?` ➡ The path to the activity you wish to display when the user scans a freestylelibre from the background (i.e "co.tryterra.terra.example.MainActivity") **Only valid for Android** * `schedulerOn: Bool` ➡ A boolean dictating if you wish turn on background delivery. Defaults to true. Please see **Background Delivery** section for setup. **returns** * `Promise` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getuserid) getUserId * `connection: Connections` ➡ An ENUM from the Connections class signifying the connection get user\_id for. **returns** * `Promise` [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#data-retrieval) Data retrieval ----------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#datamessage) DataMessage ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getactivity) **getActivity** * `connection: Connections` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `startDate: Date` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: Long` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook. If false, `DataMessage` on the returned `Promise` will contain the data in the `data` field. **returns** * `Promise` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getdaily) **getDaily** * `connection: Connections` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `startDate: Date` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: Long` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook. If false, `DataMessage` on the returned `Promise` will contain the data in the `data` field. **returns** * `Promise` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getbody) **getBody** triangle-exclamation This function _**requires**_ toWebhook to be passed in as a keyword argument, and _not_ as a positional argument * `connection: Connections` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `startDate: Date` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: Long` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook. If false, `DataMessage` on the returned `Promise` will contain the data in the `data` field. **returns** * `Promise` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getsleep) getSleep * `connection: Connections` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `startDate: Date` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: Long` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook. If false, `DataMessage` on the returned `Promise` will contain the data in the `data` field. **returns** * `Promise` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getnutrition) **getNutrition** * `connection: Connections` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `startDate: Date` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: Long` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook. If false, `DataMessage` on the returned `Promise` will contain the data in the `data` field. **returns** * `Promise` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getathlete) getAthlete * `connection: Connections` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `toWebhook: Bool` ➡ Whether or not to send data to your webhook. If false, `DataMessage` on the returned `Promise` will contain the data in the `data` field. **returns** * `Promise` [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#writing-data) Writing data ------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#postactivity) postActivity Writes activity data into Apple Health * `connection: Connections`: The connection type (`Connections_`) for which to post the data. For example, `Connections_.APPLE` to write data to Apple Health. * `payload: TerraActivityPayload`: A `TerraActivityPayload` object that contains the activity data you wish to post. This can include details like activity type, heart rate, distance, calories, and other metrics. **returns** A `Promise` that resolves to a `SuccessMessage` object indicating the success of the operation or rejects with an error. [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#android-only-methods) Android-only methods ----------------------------------------------------------------------------------------------------------------------------------------------- Fetches permissions granted by Health connect ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#grantedpermissions) grantedPermissions \*\***returns**\*\* * \``Promise>`\` [PreviousAndroid (Kotlin)chevron-left](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin) [NextFlutterchevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter) Last updated 7 months ago Was this helpful? * [Terra initialization](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#terra-initialization) * [initTerra](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#initterra) * [Connection setup/magement](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#connection-setup-magement) * [initConnection](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#initconnection) * [getUserId](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getuserid) * [Data retrieval](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#data-retrieval) * [DataMessage](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#datamessage) * [getActivity](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getactivity) * [getDaily](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getdaily) * [getBody](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getbody) * [getSleep](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getsleep) * [getNutrition](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getnutrition) * [getAthlete](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#getathlete) * [Writing data](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#writing-data) * [postActivity](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#postactivity) * [Android-only methods](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#android-only-methods) * [grantedPermissions](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native#grantedpermissions) Was this helpful? sun-brightdesktopmoon Copy function getUserId(connection: Connections): Promise Copy type DataMessage = { success: Boolean; data: Object; error: String | null; }; Copy function getActivity( connection: Connections, startDate: Date, endDate: Date, toWebhook: Boolean = true ): Promise Copy function getDaily( connection: Connections, startDate: Date, endDate: Date, toWebhook: Boolean = true ): Promise Copy function getBody( connection: Connections, startDate: Date, endDate: Date, toWebhook: Boolean = true ): Promise Copy function getSleep( connection: Connections, startDate: Date, endDate: Date, toWebhook: Boolean = true ): Promise Copy function getNutrition( connection: Connections, startDate: Date, endDate: Date, toWebhook: Boolean = true ): Promise Copy function getAthlete( connection: Connections, toWebhook: Boolean = true ): Promise Copy /* @Only available on iOS */ function postActivity( connection: Connections, payload: TerraActivityPayload ): Promise Copy function grantedPermissions(): Promise> sun-brightdesktopmoon --- # Flutter | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#misc) Misc ---------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#successmessage) SuccessMessage Copy class SuccessMessage{ final bool? success; final String? error; } [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#terra-initialization) **Terra initialization** ---------------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#initterra) **initTerra** Copy static Future initTerra( String devID, String referenceID) async `String devId` ➡ The dev-id provided to you when signing up with Terra [Developer Dashboardarrow-up-right](doc:developer-dashboard) `String referenceID` ➡ A random string used to characterise a user on your server **returns** `Future` [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#connection-setup-management) **Connection setup/management** ------------------------------------------------------------------------------------------------------------------------------------------------------------ ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#initconnection) initConnection Initialise a device connection. This function needs to be called once only. * `Connection connection` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. (E.g. `Connection.appleHealth`, `Connection.samsung` , `Connection.healthConnect`) * `String token` ➡ A token used for authentication. Generate one here: [https://docs.tryterra.co/reference/generate-authentication-tokenarrow-up-right](https://docs.tryterra.co/reference/generate-authentication-token) * `List customPermissions` ➡ This is defaulted as an empty `Set`. If you want to make a more granular permissions request, you may send us a set of `CustomPermissions` * `bool schedulerOn` ➡ A boolean dictating if you wish turn on background delivery. Defaults to true. Please see **Background Delivery** section for setup. On iOS, follow [iOSarrow-up-right](doc:unified-api-manage-integrations-ios) . **returns** * `Future` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getuserid) getUserId Returns the user's User ID if the user exists, else returns null * `Connection connection` ➡ An ENUM from the Connection class signifying the connection you wish to retrieve user\_id from. **returns** * `Future` [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#data-retrieval) Data retrieval ------------------------------------------------------------------------------------------------------------------------------ ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#datamessage) DataMessage ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getactivity) **getActivity** * `Connection connection` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `DateTime startDate` ➡ The beginning of the request in either Date or Unix Timestamp * `DateTime endDate` ➡ The end of the request in either Date or Unix Timestamp * (Optional) `bool toWebhook` ➡ Whether or not to send data to your webhook. If false, `DataMessage` on the returned `Future` will contain the data in the `data` field. **returns** * `Future` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getdaily) **getDaily** * `Connection connection` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `DateTime startDate` ➡ The beginning of the request in either Date or Unix Timestamp * `DateTime endDate` ➡ The end of the request in either Date or Unix Timestamp * (Optional) `bool toWebhook` ➡ Whether or not to send data to your webhook. If false, `DataMessage` on the returned `Future` will contain the data in the `data` field. **returns** * `Future` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getsleep) getSleep * `Connection connection` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `DateTime startDate` ➡ The beginning of the request in either Date or Unix Timestamp * `DateTime endDate` ➡ The end of the request in either Date or Unix Timestamp * (Optional) `bool toWebhook` ➡ Whether or not to send data to your webhook. If false, `DataMessage` on the returned `Future` will contain the data in the `data` field. **returns** * `Future` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getnutrition) **getNutrition** * `Connection connection` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `DateTime startDate` ➡ The beginning of the request in either Date or Unix Timestamp * `DateTime endDate` ➡ The end of the request in either Date or Unix Timestamp * (Optional) `bool toWebhook` ➡ Whether or not to send data to your webhook. If false, `DataMessage` on the returned `Future` will contain the data in the `data` field. **returns** * `Future` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getmenstruation) getMenstruation * `Connection connection` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `DateTime startDate` ➡ The beginning of the request in either Date or Unix Timestamp * `DateTime endDate` ➡ The end of the request in either Date or Unix Timestamp * (Optional) `bool toWebhook` ➡ Whether or not to send data to your webhook. If false, `DataMessage` on the returned `Future` will contain the data in the `data` field. **returns** * `Future` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getathlete) getAthlete * `Connection connection` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * (Optional) `bool toWebhook` ➡ Whether or not to send data to your webhook. If false, `DataMessage` on the returned `Future` will contain the data in the `data` field. **returns** * `Future`: Returns a `SuccessMessage` object wrapped in a `Future`. This contains information about whether the request was successful or if there was an error. [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#writing-data) Writing data -------------------------------------------------------------------------------------------------------------------------- #### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#postplannedworkout) postPlannedWorkout * `Connection connection`: Specifies the connection type to which the planned workout data will be posted. * `payload` (`TerraPlannedWorkout`): The payload containing the details of the planned workout. This includes metadata such as the workout type, duration, and intensity, as well as a list of steps to complete the workout. **returns** * `Future`: Returns a `SuccessMessage` object wrapped in a `Future`. This contains information about whether the request was successful or if there was an error. * * * [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#android-only-methods) Android-only methods ------------------------------------------------------------------------------------------------------------------------------------------ Fetches permissions granted by Health connect ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#grantedpermissions) grantedPermissions \*\***returns**\*\* * \``Promise>`\` [PreviousReact Nativechevron-left](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native) [NextREST API Endpointschevron-right](https://docs.tryterra.co/reference/streaming-api/api-endpoints) Last updated 8 months ago Was this helpful? * [Misc](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#misc) * [SuccessMessage](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#successmessage) * [Terra initialization](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#terra-initialization) * [initTerra](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#initterra) * [Connection setup/management](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#connection-setup-management) * [initConnection](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#initconnection) * [getUserId](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getuserid) * [Data retrieval](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#data-retrieval) * [DataMessage](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#datamessage) * [getActivity](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getactivity) * [getDaily](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getdaily) * [getSleep](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getsleep) * [getNutrition](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getnutrition) * [getMenstruation](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getmenstruation) * [getAthlete](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#getathlete) * [Writing data](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#writing-data) * [Android-only methods](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#android-only-methods) * [grantedPermissions](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/flutter#grantedpermissions) Was this helpful? sun-brightdesktopmoon Copy static Future initConnection( Connection connection, String token, bool schedulerOn, List customPermissions) Copy static Future getUserId(Connection connection) async Copy class DataMessage{ final bool? success; final Map? data; final String? error; } Copy static Future getActivity( Connection connection, DateTime startDate, DateTime endDate, {bool toWebhook = true}) async Copy static Future getDaily( Connection connection, DateTime startDate, DateTime endDate, {bool toWebhook = true}) async Copy static Future getSleep( Connection connection, DateTime startDate, DateTime endDate, {bool toWebhook = true}) async Copy static Future getNutrition( Connection connection, DateTime startDate, DateTime endDate, {bool toWebhook = true}) async Copy static Future getMenstruation( Connection connection, DateTime startDate, DateTime endDate, {bool toWebhook = true}) async Copy static Future getAthlete( Connection connection, {bool toWebhook = true}) async Copy static Future postPlannedWorkout( Connection connection, TerraPlannedWorkout payload) async Copy function grantedPermissions(): Promise> sun-brightdesktopmoon --- # Account setup and API keys | Terra Docs 1 ### [hashtag](https://docs.tryterra.co/introduction/account-setup-and-api-keys#create-your-terra-api-account) Create your Terra API account * **Sign Up:** Create an account at the Terra API [Registration Pagearrow-up-right](https://dashboard.tryterra.co/user/signup) . * **Onboarding:** Follow the Terra the onboarding flow and fill in the required information (email, password, company details, etc.) when prompted. 2 ### [hashtag](https://docs.tryterra.co/introduction/account-setup-and-api-keys#select-plan) Select plan * **Setup:** During onboarding you'll be prompted to select your plan and enter billing details. Select the plan that best fits your requirements. * **Manage plan:** Once signed up, you can manage view your current plan and billing details within the _Terra Dashboard_ under _Settings._ Ensure your account and subscription are active to maintain uninterrupted API access. 3 ### [hashtag](https://docs.tryterra.co/introduction/account-setup-and-api-keys#obtain-api-keys) Obtain API keys * **Get keys from dashboard:** Once your account is setup, go to the [Terra Dashboardarrow-up-right](https://dashboard.tryterra.co/dashboard/) and click on _API Keys_ in the Navbar. Here you can copy your _Developer ID_ and _API Keys_. * **Credentials per environment:** Terra maintains separate credentials for _testing_, _staging_, and _production_ environments. There is a [user cap](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-terra-environments) on _testing_ and _staging_. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FVaBoW97WCFpvgUPqk4GA%252Fimage.png%3Falt%3Dmedia%26token%3D3fb51ccc-b859-43c8-9e41-6bc91d7fc700&width=768&dpr=3&quality=100&sign=6f58d8&sv=2) 4 ### [hashtag](https://docs.tryterra.co/introduction/account-setup-and-api-keys#start-using-terra-api) Start using Terra API! * **Follow API Docs**: You're now all set to use Terra API. We recommend that you start with the [**Health & Fitness API.**](https://docs.tryterra.co/health-and-fitness-api/getting-started) * **Keep secret:** Never share your x-api-key publicly or embed it directly in client-side code (e.g., mobile apps, frontend JavaScript). * **Backend Use:** API keys requiring this level of access (like your main x-api-key) should typically be used only from your secure backend server. [PreviousWhat is Terra API?chevron-left](https://docs.tryterra.co/) [NextCore conceptschevron-right](https://docs.tryterra.co/introduction/core-concepts) Last updated 8 months ago Was this helpful? * [Create your Terra API account](https://docs.tryterra.co/introduction/account-setup-and-api-keys#create-your-terra-api-account) * [Select plan](https://docs.tryterra.co/introduction/account-setup-and-api-keys#select-plan) * [Obtain API keys](https://docs.tryterra.co/introduction/account-setup-and-api-keys#obtain-api-keys) * [Start using Terra API!](https://docs.tryterra.co/introduction/account-setup-and-api-keys#start-using-terra-api) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # iOS (Swift) | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#initialization-of-terra-manager) **Initialization of Terra manager** ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#terra.instance) Terra.instance Copy Terra.instance(devId: String, referenceId: String?, completion: @escaping (TerraManager?, TerraError?) -> Void) * `devId: String` ➡ The developer identifier given to your after you signed up on [Terraarrow-up-right](https://dashboard.tryterra.co/) * `referenceId: String?` ➡ This is used by you to identify a user from your server to a terra user * `completion: @escaping (TerraManager?, TerraError?) -> Void` ➡ A callback function that is called when the TerraManager class is initialised. If an error has occurred in creation, then the completion will return a `TerraError` class. **Highly recommended to wait for this callback before proceeding** [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#terra-manager-instance-methods) **Terra manager Instance methods** -------------------------------------------------------------------------------------------------------------------------------------------------------------------- All methods below are used on the instance returned by `Terra.instance` above. [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#connection-setup-management) **Connection setup/management** -------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#initconnection) **initConnection** Initialises a connection for Apple Health * `type: Connections` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `token: String` ➡ A token used for authentication. Generate one here: [https://docs.tryterra.co/reference#post-auth-generateauthtokenarrow-up-right](https://docs.tryterra.co/reference#post-auth-generateauthtoken) * (Optional) `customReadTypes: Set` ➡ used to customize the permissions list shown in the Apple Health popup when calling [`initConnection`](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#initconnection) . When empty, it defaults to all available permissions. * `schedulerOn: Bool` ➡ A boolean dictating if you wish turn on background delivery. Defaults to true. Please see **Background Delivery** section for setup. * `completion: @escaping (Bool, TerraError?) -> Void` ➡ A callback with a boolean dictating if the initialisation succeeds. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#setupbackgrounddelivery) setUpBackgroundDelivery This function is expected to be run in your AppDelegate under `didFinishLaunchingWithOptions` function. Automatically sends data to Terra to be processed and to be to submitted to your [destination](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) . ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#getuserid) getUserId * `type: Connections` ➡ The connection to retrieve the userId for [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#data-retrieval) Data retrieval -------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#getactivity) **getActivity** * `type: Connections` ➡ The Connection to get data from * `startDate: Date` or `startDate: TimeInterval` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: TimeInterval` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook * `completion: (Bool, TerraDailyDataPayloadModel?, TerraError?) -> Void` ➡ callback function that runs after the request is completed. It has the following parameters: * `Bool` -> If the request was successful or not. If not, the `TerraError` parameter will be returned * `TerraDailyDataPayloadModel?` -> A payload for each data type. If `toWebhook` is set to true, this returns a class with a property `reference` referring to the payload reference sent to your webhook. If `toWebhook` is set to false, then this returns the entire Terra normalised payload. * `TerraError?` -> Returned if any error occurred while retrieving data ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#getdaily) **getDaily** * `type: Connections` ➡ The Connection to get data from * `startDate: Date` or `startDate: TimeInterval` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: TimeInterval` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook * `completion: (Bool, TerraDailyDataPayloadModel?, TerraError?) -> Void` ➡ callback function that runs after the request is completed. It has the following parameters: * `Bool` -> If the request was successful or not. If not, the `TerraError` parameter will be returned * `TerraDailyDataPayloadModel?` -> A payload for each data type. If `toWebhook` is set to true, this returns a class with a property `reference` referring to the payload reference sent to your webhook. If `toWebhook` is set to false, then this returns the entire Terra normalised payload. * `TerraError?` -> Returned if any error occurred while retrieving data ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#getsleep) getSleep * `type: Connections` ➡ The Connection to get data from * `startDate: Date` or `startDate: TimeInterval` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: TimeInterval` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook * `completion: (Bool, TerraDailyDataPayloadModel?, TerraError?) -> Void` ➡ callback function that runs after the request is completed. It has the following parameters: * `Bool` -> If the request was successful or not. If not, the `TerraError` parameter will be returned * `TerraDailyDataPayloadModel?` -> A payload for each data type. If `toWebhook` is set to true, this returns a class with a property `reference` referring to the payload reference sent to your webhook. If `toWebhook` is set to false, then this returns the entire Terra normalised payload. * `TerraError?` -> Returned if any error occurred while retrieving data ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#getmenstruation) getMenstruation * `type: Connections` ➡ The Connection to get data from * `startDate: Date` or `startDate: TimeInterval` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: TimeInterval` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook * \`completion: (Bool, TerraMenstruationDataPayloadModel?, TerraError?) -> Void ➡ callback function that runs after the request is completed. It has the following parameters: * `Bool` -> If the request was successful or not. If not, a TerraError instance will also be called * `TerraMenstruationDataPayloadModel?` -> A payload for each data type. If `toWebhook` is set to true, this returns a class with a property `reference` referring to the payload reference sent to your webhook. If `toWebhook` is set to false, then this returns the entire Terra normalised payload. * `TerraError?` -> Returned if any error occurred while retrieving data ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#getathlete) **getAthlete** * `type: Connections` ➡ The Connection to get data from * `toWebhook: Bool` ➡ Whether or not to send data to your webhook * \`completion: (Bool, TerraAthleteDataPayloadModel?, TerraError?) -> Void ➡ * `Bool` -> If the request was successful or not. If not, a TerraError instance will also be called * `TerraAthleteDataPayloadModel?` -> A payload for each data type. If `toWebhook` is set to true, this returns a class with a property `reference` referring to the payload reference sent to your webhook. If `toWebhook` is set to false, then this returns the entire Terra normalised payload. * `TerraError?` -> Returned if any error occurred while retrieving data ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#subscribe) **subscribe** You can subscribe for individual datatypes as follows (only needs to be done once). After you have confirmed a connection with Apple Health, you can pass us an update handler ideally in your app delegate's didFinishLaunchingWithOptions function, so it is set everytime the app launches. This can be done as such: After the call, your update handler will be called with the corresponding datatypes whenever new ones are available. This includes the next time you open your app. Scenario: You subscribed for steps data. You close your app and do not go back for 5 days. The next time you open it, your update handler will be called with all 5 days worth of steps, without you needing to query for it and would execute a lot faster as it is only steps. [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#writing-data) Writing data ---------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#postactivity) **postActivity** Write activity data into Apple Health or other supported connections. **Description**: This function allows you to write activity data into Apple Health. Internally uses [HKWorkoutarrow-up-right](https://developer.apple.com/documentation/healthkit/hkworkout) **Parameters**: * **type**: The connection type (`TerraiOS.Connections`) for which to post the data. For example, use `.APPLE_HEALTH` to write data to Apple Health. * **payload**: A `TerraiOS.TerraActivityData` object that contains the activity data you wish to post. This can include details such as activity type, heart rate, distance, calories, and other relevant activity metrics. * **completion**: A closure that returns a `Bool` indicating the success (`true`) or failure (`false`) of the post operation, along with an optional `TerraiOS.TerraError` to indicate any error that occurred. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#postnutrition) postNutrition Write nutrition data into Apple Health **Description**: This function allows you to **Parameters**: * `type`: The connection type (`TerraConnections`) for which to post the data. E.g., `Connections.APPLE`. * `payload`: A `TerraNutritionData` object that contains the nutrition data you wish to post. * `completion`: A closure that returns a `Bool` indicating the success or failure of the post operation. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#postbody) postBody Write body composition data into Apple Health * `type`: The connection type (`TerraConnections`) for which to post the data. E.g., `Connections.APPLE`. * `payload`: A `TerraBodyData` object that contains the body data (e.g., oxygen, glucose, heart rate) you wish to post. * `completion`: A closure that returns a `Bool` indicating whether the post operation was successful. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#postplannedworkout) postPlannedWorkout Write planned workouts to Apple Health, for syncing scheduled workouts to the Workout app on Apple Watch. **Parameters**: * `type`: The connection type (`TerraConnections`) for which to post the workout. E.g., `Connections.APPLE`. * `payload`: A `TerraPlannedWorkout` object containing the workout steps and metadata. * `completion`: A closure that returns a `Bool` indicating the success or failure of the post operation and an optional `TerraError` if applicable. [PreviousMobile SDKchevron-left](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references) [NextAndroid (Kotlin)chevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin) Last updated 4 months ago Was this helpful? * [Initialization of Terra manager](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#initialization-of-terra-manager) * [Terra.instance](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#terra.instance) * [Terra manager Instance methods](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#terra-manager-instance-methods) * [Connection setup/management](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#connection-setup-management) * [initConnection](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#initconnection) * [setUpBackgroundDelivery](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#setupbackgrounddelivery) * [getUserId](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#getuserid) * [Data retrieval](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#data-retrieval) * [getActivity](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#getactivity) * [getDaily](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#getdaily) * [getSleep](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#getsleep) * [getMenstruation](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#getmenstruation) * [getAthlete](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#getathlete) * [subscribe](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#subscribe) * [Writing data](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#writing-data) * [postActivity](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#postactivity) * [postNutrition](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#postnutrition) * [postBody](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#postbody) * [postPlannedWorkout](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift#postplannedworkout) Was this helpful? sun-brightdesktopmoon Copy func initConnection(type: Connections, token: String, customReadTypes: Set, schedulerOn: Bool, completion: @escaping (Bool, TerraError?) -> Void)) Copy func setUpBackgroundDelivery() -> Void Copy func getUserid(type: Connections) -> String? Copy func getActivity(type: Connections, startDate: Date, endDate: Date, toWebhook: Bool, completion: @escaping (Bool, TerraActivityDataPayloadModel?, TerraError?) -> Void) Copy func getDaily(type: Connections, startDate: Date, endDate: Date, toWebhook: Bool, completion: @escaping (Bool, TerraDailyDataPayloadModel?, TerraError?) -> Void) Copy func getSleep(type: Connections, startDate: Date, endDate: Date, toWebhook: Bool, completion: @escaping (Bool, TerraSleepDataPayloadModel?, TerraError?) -> Void) Copy func getMensturation(type: Connections, startDate: Date, endDate: Date, toWebhook: Bool, completion: @escaping (Bool, TerraMenstruationDataPayloadModel?, TerraError?) -> Void) Copy func getAthlete(type: Connections, toWebhook: Bool, completion: @escaping (Bool, TerraAthleteDataPayloadModel?, TerraError?) -> Void) Copy func subscribe(forDataTypes: Set, completion: @escaping(Bool, TerraError?) -> Void) Copy Terra.updateHandler = {type: DataTypes, update: Update -> Void in // process updates in here } Copy func postActivity( type: TerraiOS.Connections, payload: TerraiOS.TerraActivityData, completion: @escaping (Swift.Bool, TerraiOS.TerraError?) -> Swift.Void = { _, _ in } ) Copy func postNutrition( type: TerraiOS.Connections, payload: TerraiOS.TerraNutritionData, completion: @escaping (Swift.Bool) -> Swift.Void = { _ in } ) Copy final public func postBody( type: TerraiOS.Connections, payload: TerraiOS.TerraBodyData, completion: @escaping (Swift.Bool) -> Swift.Void = { _ in } ) Copy @available(iOS 17, *) final public func postPlannedWorkout( type: TerraiOS.Connections, payload: TerraiOS.TerraPlannedWorkout, completion: @escaping (Swift.Bool, TerraiOS.TerraError?) -> Swift.Void ) sun-brightdesktopmoon --- # Terra -> Your backend | Terra Docs This guide will walk you through the essential steps, from connecting and authenticating to managing heartbeats and receiving data. [hashtag](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#setting-up-a-consumer-connection) Setting up a Consumer Connection -------------------------------------------------------------------------------------------------------------------------------------------------------- Each developer ID is linked to a single data stream. To set up your consumer connection to the Terra WebSocket service, follow the steps below. For a complete Node.js example, refer to \[Setting up a WebSocket Consumer\]. * * * [hashtag](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#connecting-to-the-websocket) Connecting to the WebSocket ---------------------------------------------------------------------------------------------------------------------------------------------- Once you open a WebSocket connection to the server, you will immediately receive an `Op 2 HELLO` payload. This payload contains the `heartbeat_interval` value (in milliseconds), which the client will use to maintain the connection. Example payload: Copy { "op": 2, "d": { "heartbeat_interval": 40000 } } After receiving this payload, the client must start sending heartbeat messages, as described below. * * * [hashtag](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#heartbeating) Heartbeating ---------------------------------------------------------------------------------------------------------------- circle-info To keep the WebSocket connection alive, the client **needs** to send regular heartbeats . This lets the server knows the connection is still active and waiting for data To send a heartbeat, simply send the following payload in the broker: You'll always receive the following response (acknowledging your heartbeat) triangle-exclamation * The first heartbeat should be sent after `heartbeat_interval * jitter` milliseconds, where jitter is a random value between 0.1 and 1.0. * After the first heartbeat, continue sending heartbeats **at most** at the interval specified in the HELLO payload. * If no `HEARTBEAT_ACK` is received, the client should close the connection and establish a new one. * * * [hashtag](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#authenticating-the-connection) Authenticating the Connection -------------------------------------------------------------------------------------------------------------------------------------------------- Once heartbeating is set up, the client must authenticate the connection by sending an `IDENTIFY` payload containing a token. #### [hashtag](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#example-identify-payload) Example IDENTIFY payload: When authentication is successful, the server will respond with an `Op 4 READY` message. Example response: * * * [hashtag](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#listening-for-data-updates) Listening for Data Updates -------------------------------------------------------------------------------------------------------------------------------------------- Once the connection is established and authenticated, the broker will start sending data through your consumer connection. When new data is available, an `Op 5 DISPATCH` payload is sent, containing the relevant event data (e.g., heart rate values). Example DISPATCH payload: Each dispatch contains: * `uid`: The Terra user ID. * `t`: The type of event (e.g., heart rate). * `d`: The actual data, including timestamps and values. * * * [hashtag](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#requesting-missed-data) Requesting missed Data ------------------------------------------------------------------------------------------------------------------------------------ ### [hashtag](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#websocket-commands) WebSocket Commands There is only one relevant command you may want to send to the broker **REPLAY Command (Op 7)** Used by consumer connections to request missed data, based on sequence numbers. This is useful when a connection drops unexpectedly. Example REPLAY payload: [PreviousAndroidchevron-left](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/android) [NextLab Report API Documentationchevron-right](https://docs.tryterra.co/lab-reports/lab-report-api-documentation) Last updated 1 year ago Was this helpful? * [Setting up a Consumer Connection](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#setting-up-a-consumer-connection) * [Connecting to the WebSocket](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#connecting-to-the-websocket) * [Heartbeating](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#heartbeating) * [Authenticating the Connection](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#authenticating-the-connection) * [Listening for Data Updates](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#listening-for-data-updates) * [Requesting missed Data](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#requesting-missed-data) * [WebSocket Commands](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend#websocket-commands) Was this helpful? sun-brightdesktopmoon Copy { "op": 0 } Copy { "op": 1 } Copy { "op": 3, "d": { "token": "your_token_here", "type": 0 } } Copy { "op": 4 } Copy { "op": 5, "d": { "t": "2022-05-04T10:26:11.268507+01:00", "val": 95 }, "uid": "user_id_here", "seq": 73, "t": "HEART_RATE" } Copy { "op": 7, "d": { "after": 28, "before": 43 } sun-brightdesktopmoon --- # Wearable -> Your app | Terra Docs Learn how to use Terra's Real-Time (RT) SDKs (for iOS and Android) to connect to a user's wearable device and receive live biometric data streams directly within your mobile application. * [**iOS (Swift)**](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/ios-swift) * [**Android**](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android) [PreviousOverviewchevron-left](https://docs.tryterra.co/streaming-api/getting-started) [NextiOS (Swift)chevron-right](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/ios-swift) Last updated 8 months ago Was this helpful? Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Android (Kotlin) | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#utility-functions) **Utility functions** ----------------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#ishealthconnectavailable) isHealthConnectAvailable Checks if Health Connect is available in a given application/activity context Copy fun isHealthConnectAvailable(context: Context): Boolean * `context: Context` -> Activity context from android app to check if Health Connect is available for ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#openhealthconnect) openHealthConnect Opens a health connect activity to overlay the current one, effectively redirecting the user into the Health Connect app Copy fun openHealthConnect(context: Context): Unit * `context: Context`: Activity context from android app [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#initialization-of-terra-manager) **Initialization of Terra manager** --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#instance) instance Copy fun instance(devId: String, referenceId: String?, context: Context, completion: (TerraManager, TerraError?) -> Unit) * `devId: String` ➡ The developer identifier given to your after you signed up on [Terraarrow-up-right](https://dashboard.tryterra.co/) * `referenceId: String?` ➡ This is used by you to identify a user from your server to a terra user * `context: Context` ➡ The context from the activity you are instantiating from * `completion: @escaping (TerraManager, TerraError?) -> Void` ➡ A callback function that is called when the TerraManager class is initialised. If an error has occurred in creation, then the completion will return a `TerraError` class. **Highly recommended to wait for this callback before proceeding** [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#terra-manager-instance-methods) **Terra manager Instance methods** ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#connection-setup-management) **Connection setup/management** ------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#allgivenpermissions) allGivenPermissions Retrieves all given permissions granted by health connect * `completion (Set) -> Unit` -> A set of given permissions to Health Connect ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#initconnection) **initConnection** Initialises a connection for Samsung Health/Google Fit * `type: Connections` ➡ An ENUM from the Connections class signifying the connection you wish to initiate for. * `token: String` ➡ A token used for authentication. Generate one here: [https://docs.tryterra.co/reference/generate-authentication-tokenarrow-up-right](https://docs.tryterra.co/reference/generate-authentication-token) * (Optional) `customReadTypes: Set` ➡ This is defaulted as an empty `Set`. If you want to make a more granular permissions request, you may send us a set of `CustomPermissions` * `context: Context` ➡ The context from the activity you are instantiating from * `schedulerOn: Bool` ➡ A boolean dictating if you wish turn on the schduler. Defaults to true. * `startIntent: String?` ➡ The path to the activity you wish to display when the user scans a freestylelibre from the background (i.e "co.tryterra.terra.example.MainActivity") * `completion: @escaping (Bool, TerraError?) -> Void` ➡ A callback with a boolean dictating if the initialisation succeeds. ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#getuserid) getUserId * `type: Connections` ➡ The connection to retrieve the userId for [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#data-retrieval) Data Retrieval ------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#getactivity) **getActivity** * `type: Connections` ➡ The Connection to get data from * `startDate: Date` or `startDate: Long` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: Long` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook * \`completion: (Bool, TerraActivityDataPayload?, TerraError?) -> Void ➡ **Bool** -> If the request was successful or not. If not, a TerraError instance will also be called **TerraActivityDataPayload?** -> A payload for each data type. If `toWebhook` is set to true, this returns a class with a property `reference` referring to the payload reference sent to your webhook. If `toWebhook` is set to false, then this returns the entire Terra normalised payload. **TerraError?** -> Returned if any error occurred while retrieving data ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#getdaily) **getDaily** * `type: Connections` ➡ The Connection to get data from * `startDate: Date` or `startDate: Long` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: Long` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook * \`completion: (Bool, TerraDailyDataPayload?, TerraError?) -> Void ➡ **Bool** -> If the request was successful or not. If not, a TerraError instance will also be called **TerraDailyDataPayload?** -> A payload for each data type. If `toWebhook` is set to true, this returns a class with a property `reference` referring to the payload reference sent to your webhook. If `toWebhook` is set to false, then this returns the entire Terra normalised payload. **TerraError?** -> Returned if any error occurred while retrieving data ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#getsleep) getSleep * `type: Connections` ➡ The Connection to get data from * `startDate: Date` or `startDate: Long` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: Long` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook * \`completion: (Bool, TerraSleepDataPayload?, TerraError?) -> Void ➡ **Bool** -> If the request was successful or not. If not, a TerraError instance will also be called **TerraSleepDataPayload?** -> A payload for each data type. If `toWebhook` is set to true, this returns a class with a property `reference` referring to the payload reference sent to your webhook. If `toWebhook` is set to false, then this returns the entire Terra normalised payload. **TerraError?** -> Returned if any error occurred while retrieving data ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#getnutrition) **getNutrition** * `type: Connections` ➡ The Connection to get data from * `startDate: Date` or `startDate: Long` ➡ The beginning of the request in either Date or Unix Timestamp * `endDate: Date` or `endDate: Long` ➡ The end of the request in either Date or Unix Timestamp * `toWebhook: Bool` ➡ Whether or not to send data to your webhook * \`completion: (Bool, TerraNutritionDataPayload?, TerraError?) -> Void ➡ **Bool** -> If the request was successful or not. If not, a TerraError instance will also be called **TerraNutritionDataPayload?** -> A payload for each data type. If `toWebhook` is set to true, this returns a class with a property `reference` referring to the payload reference sent to your webhook. If `toWebhook` is set to false, then this returns the entire Terra normalised payload. **TerraError?** -> Returned if any error occurred while retrieving data [PreviousiOS (Swift)chevron-left](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/ios-swift) [NextReact Nativechevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/react-native) Was this helpful? * [Utility functions](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#utility-functions) * [isHealthConnectAvailable](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#ishealthconnectavailable) * [openHealthConnect](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#openhealthconnect) * [Initialization of Terra manager](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#initialization-of-terra-manager) * [instance](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#instance) * [Terra manager Instance methods](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#terra-manager-instance-methods) * [Connection setup/management](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#connection-setup-management) * [allGivenPermissions](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#allgivenpermissions) * [initConnection](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#initconnection) * [getUserId](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#getuserid) * [Data Retrieval](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#data-retrieval) * [getActivity](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#getactivity) * [getDaily](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#getdaily) * [getSleep](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#getsleep) * [getNutrition](https://docs.tryterra.co/reference/health-and-fitness-api/sdk-references/android-kotlin#getnutrition) Was this helpful? sun-brightdesktopmoon Copy fun allGivenPermissions(completion: (Set) -> Unit) Copy fun initConnection(connection: Connections, token: String, context: Context, customPermissions: Set = setOf(), schedulerOn: Boolean = true, startIntent: String? = null, completion: (Boolean, TerraError?) -> Unit = { _, _ -> }) Copy fun getUserId(type: Connections): String? Copy fun getActivity(type: Connections, startDate: Date, endDate: Date, toWebhook: Boolean = true, completion: (Boolean, TerraActivityDataPayload?, TerraError?) -> Unit = {_, _, _ ->}) Copy fun getDaily(type: Connections, startDate: Date, endDate: Date, toWebhook: Boolean = true, completion: (Boolean, TerraDailyDataPayload?, TerraError?) -> Unit = {_, _, _ ->}) Copy fun getSleep(type: Connections, startDate: Date, endDate: Date, toWebhook: Boolean = true, completion: (Boolean, TerraSleepDataPayload?, TerraError?) -> Unit = {_, _, _ ->}) Copy fun getNutrition(type: Connections, startDate: Date, endDate: Date, toWebhook: Boolean = true, completion: (Boolean, TerraNutritionDataPayload?, TerraError?) -> Unit = {_, _, _ ->}) sun-brightdesktopmoon --- # Flutter | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#flutter-functions) Flutter Functions ---------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#connection-setup) **Connection Setup** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#init) init Initializes a connection with the Terra backend for the device. Copy dartCopy codestatic Future init(String devId, String? referenceId) async * `devId`: The developer ID used for initialization. * `referenceId`: An optional reference ID. * **Returns**: A `Future` indicating if the initialization was successful or not. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#initconnection) initConnection Initializes a user session with Terra backend using an authentication token. Copy dartCopy codestatic Future initConnection(String token) async * `token`: The authentication token generated by the backend. * **Returns**: A `Future` indicating if the session was successfully initialized. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#getuserid) getUserId Retrieves the user ID for the current device. * **Returns**: A `Future` representing the user's Terra ID, or `null` if no ID is found. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#disconnect) disconnect Disconnects the device from a given connection. * `connection`: The connection object specifying which connection to disconnect. * **Returns**: A `Future` indicating if the disconnection was successful. * * * ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#device-scanning) **Device Scanning** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#startdevicescan) startDeviceScan Starts a device scan and allows connection to devices. * `connection`: The connection object specifying the type of connection to initiate. * `useCache`: A boolean flag to indicate if cached devices should be used (default: `false`). * **Returns**: A `Future` indicating if the device scan was successful. * * * ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#data-streaming) **Data Streaming** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#startrealtimetoserver) startRealtimeToServer Starts real-time data streaming from the device to the server. * `connection`: The connection object specifying which connection to stream from. * `types`: A list of `DataType` objects indicating which types of data to stream. * `token`: An authentication token for the streaming session. * **Returns**: A `Future` indicating if the real-time streaming was successfully started. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#startrealtimetoapp) startRealtimeToApp Starts real-time data streaming from the device to the app. * `connection`: The connection object specifying which connection to stream from. * `types`: A list of `DataType` objects indicating which types of data to stream. * `callback`: A function (`UpdateCallback`) that is called whenever new data is available. * **Returns**: A `Future` indicating if the real-time streaming was successfully started. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#stoprealtime) stopRealtime Stops real-time data streaming for a given connection. * `connection`: The connection object specifying which connection to stop streaming from. * **Returns**: A `Future` indicating if the streaming was successfully stopped. * * * ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#utility) **Utility** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#platformversion) platformVersion Retrieves the platform version for the current device. * **Returns**: A `Future` containing the platform version, or "UNKNOWN" if not available. [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/flutter#types) Types ---------------------------------------------------------------------------------------------- **Connection Enum** The `Connection` enum represents the different connection types available in the Terra Flutter SDK. Each connection type can be converted to a string using the `connectionString` property, which maps the enum values to their respective string representations (e.g., `Connection.ble` becomes `"BLE"`). **DataType Enum** The `DataType` enum represents the different types of data that can be streamed from a device. Each `DataType` can be converted to a string using the `datatypeString` property, which maps the enum values to their respective string representations (e.g., `DataType.heartRate` becomes `"HEART_RATE"`). **Update Class** The `Update` class represents a data update received from the device. You can create an `Update` object from a JSON map using the `Update.fromJson` constructor. [PreviousAndroid (Kotlin)chevron-left](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin) [NextReact Nativechevron-right](https://docs.tryterra.co/reference/streaming-api/reference/react-native) Was this helpful? * [Flutter Functions](https://docs.tryterra.co/reference/streaming-api/reference/flutter#flutter-functions) * [Connection Setup](https://docs.tryterra.co/reference/streaming-api/reference/flutter#connection-setup) * [Device Scanning](https://docs.tryterra.co/reference/streaming-api/reference/flutter#device-scanning) * [Data Streaming](https://docs.tryterra.co/reference/streaming-api/reference/flutter#data-streaming) * [Utility](https://docs.tryterra.co/reference/streaming-api/reference/flutter#utility) * [Types](https://docs.tryterra.co/reference/streaming-api/reference/flutter#types) Was this helpful? sun-brightdesktopmoon Copy dartCopy codestatic Future getUserId() async Copy dartCopy codestatic Future disconnect(Connection connection) async Copy dartCopy codestatic Future startDeviceScan(Connection connection, {bool useCache = false}) async Copy dartCopy codestatic Future startRealtimeToServer(Connection connection, List types, String token) async Copy dartCopy codestatic Future startRealtimeToApp(Connection connection, List types, UpdateCallback callback) async Copy dartCopy codestatic Future stopRealtime(Connection connection) async Copy dartCopy codestatic Future get platformVersion async Copy enum Connection { ble, apple, wearOs, android, ant, allDevices } Copy enum DataType { heartRate, ecg, steps, hrv, calories, location, speed, distance, stepsCadence, floorsClimbed, gyroscope, acceleration } Copy class Update { final String ts; // Timestamp of the update final DataType type; // Type of data (e.g., heart rate, steps) final double? val; // Single value for the data type (if applicable) final List? d; // List of values for complex data types (e.g., acceleration) } sun-brightdesktopmoon --- # iOS (Swift) | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#ios-functions) iOS Functions ---------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#initialization-of-terra-manager) **Initialization of Terra manager** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#terrart) TerraRT Initializes the TerraRT instance with the provided developer ID and an optional reference ID. Copy init(devId: Swift.String, referenceId: Swift.String?, completion: @escaping (Swift.Bool) -> Swift.Void) * `devId`: The developer ID used to authenticate and initialize TerraRT. * `referenceId`: An optional reference ID for the initialization. Can be `nil` if not needed. * `completion`: A closure that returns a `Bool`, indicating success (`true`) or failure (`false`) of the initialization. **Returns**: An instance of `TerraRT` and executes the completion handler with the result of the initialization (success/failure). ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#connection-setup) **Connection Setup** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#connectdevice) connectDevice Connects to a `Device`. Copy func connectDevice(_ device: Device, _ connectionCallback: @escaping(Bool) -> Void) * `device`: A device object returned from `startBluetoothScan`. * `connectionCallback`: A completion function called when the connection is completed. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#initconnection) initConnection Initialises a user with the Terra backend * `token`: An authentication token. * `completion`: A completion function called when the initialisation is complete. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#disconnect) disconnect Disconnects from a connection. * `type`: Enum representing the connection to disconnect from. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#startbluetoothscan) startBluetoothScan Starts a Bluetooth scan session ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#data-streaming) **Data Streaming** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#startrealtime) startRealtime Starts streaming data for a given Connection type * `type`: Enum representing the connection to make. * `dataType`: Enum set of the data types to stream. * `token`: A user token for authentication. * `callback`: A callback for data reception. * `connectionCallback`: A callback for connection success. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#stoprealtime) stopRealtime Stops streaming for a given connection type * * * [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#ios-greater-than-watchos-functions) iOS -> WatchOS Functions ------------------------------------------------------------------------------------------------------------------------------------------------ circle-info The functions outlined in this section are only to be used in conjunction with an app running on watchOS, which uses the [WatchOS Functions](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#watchos-functions) ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#connection-management) Connection management #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#connectwithwatchos) connectWithWatchOS Initialise a connection with an Apple Watch **throws** `TerraError.FeatureNotSupported` #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#setwatchosconnectionstatelistener) setWatchOSConnectionStateListener Sets a listener for changes in ConnectionState * `listener`: A listener function called depending on the state of the watch connection. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#setwatchstatechangelisteners) setWatchStateChangeListeners Set watch state change listeners (for isPaired, isWatchAppInstalled, and isComplicationEnabled fields) * `isPairedListener`: callback function for `isPaired` state changes. * `isAppInstalledListener`: callback function for `isWatchAppInstalled` state changes. * `isComplicationEnabledListener`: callback function for `isComplicationEnabled` state changes. ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#recording-session-management) Recording session management circle-info The functions below are to be used to manage sessions started on the WatchOS app, using [startExercise](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#startexercise-watchos) #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#resumewatchosworkout) resumeWatchOSWorkout Resume a workout if it is going on #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#pausewatchosworkout) pauseWatchOSWorkout Pauses a workout if it is going on #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#stopwatchosworkout) stopWatchOSWorkout Stops a workout if it is going on ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#messaging) **Messaging** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#setmessagehandler) setMessageHandler Set a message handler to handle the custom message sent from `sendMessage` function #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#sendmessage) sendMessage Send a message to the iOS Companion App * `data`: A dictionary of data to send to iOS Companion app. * * * [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#watchos-functions) WatchOS Functions ------------------------------------------------------------------------------------------------------------------------ ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#initialization) Initialization circle-info All functions below are to be called on an instance of the `Terra` class after it has been initialized (no input parameters) ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#connection-setup-1) **Connection Setup** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#sharingdataauthorised) sharingDataAuthorised Returns `Bool` depicting if user has granted writing Workout information to HealthKit. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#connect) connect Connect to iOS companion app #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#setwatchosconnectionstatelistener-1) setWatchOSConnectionStateListener Set a listener for changes in ConnectionState * `listener`: A listener function called depending on the state of the watch connection. ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#data-streaming-1) **Data Streaming** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#startstream) startStream Start observing for different data types and stream it to the iOS companion app * `dTypes`: A set of all the types to start observing for. * `completion`: Completion function indicating if the stream started successfully. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#stopstream) stopStream Stop streaming to the iOS Companion app #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#setupdatehandler-watchos) setUpdateHandler (WatchOS) Set an update handler to receive data on the Watch App. Will only be triggered if [startStream](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#startstream) has been called ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#recording-session-management-1) **Recording Session Management** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#startexercise) startExercise Starts an exercise (HKWorkout) and streams to iOS Companion * `workoutType`: The workout type Enum to start exercise for. * `completion`: Completion function indicating if the exercise started correctly. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#pauseexercise) pauseExercise Pause the current running exercise session #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#resumeexercise) resumeExercise Resumes a paused exercise session #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#stopexercise) stopExercise Stop the exercise (if one has been started) #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#setworkoutstatelistener) setWorkoutStateListener Set an update handler to receive updates on the state of the workout. Useful when workout is paused/managed from the iOS app side * * * ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#messaging-1) **Messaging** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#setmessagehandler-watchos) setMessageHandler (WatchOS) Set a message handler to handle the custom message sent from `sendMessage` function #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#sendmessage-watchos) sendMessage (WatchOS) Send a message to the iOS Companion App * `data`: A dictionary of data to send to iOS Companion app. [PreviousMobile SDKchevron-left](https://docs.tryterra.co/reference/streaming-api/reference) [NextAndroid (Kotlin)chevron-right](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin) Was this helpful? * [iOS Functions](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#ios-functions) * [Initialization of Terra manager](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#initialization-of-terra-manager) * [Connection Setup](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#connection-setup) * [Data Streaming](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#data-streaming) * [iOS -> WatchOS Functions](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#ios-greater-than-watchos-functions) * [Connection management](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#connection-management) * [Recording session management](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#recording-session-management) * [Messaging](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#messaging) * [WatchOS Functions](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#watchos-functions) * [Initialization](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#initialization) * [Connection Setup](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#connection-setup-1) * [Data Streaming](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#data-streaming-1) * [Recording Session Management](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#recording-session-management-1) * [Messaging](https://docs.tryterra.co/reference/streaming-api/reference/ios-swift#messaging-1) Was this helpful? sun-brightdesktopmoon Copy func initConnection(token: String, completion: @escaping (Bool) -> Void = {(success) -> Void in}) Copy func disconnect(type: Connections) Copy func startBluetoothScan(type: Connections, deviceCallback: @escaping (Device) -> Void) Copy func startRealtime( type: Connections, dataType: Set, token: String, callback: @escaping(Update) -> Void, connectionCallback: @escaping(Bool) -> Void ) // alternative signature, used for streaming data locally without // sending data to Terra Websocket API func startRealtime( type: Connections, dataType: Set, callback: @escaping (Update) -> Swift.Void ) Copy func stopRealtime(type: Connections) Copy func connectWithWatchOS() throws Copy func setWatchOSConnectionStateListener(listener: @escaping (ConnectionState) -> Void) Copy public func setWatchStateChangeListeners(isPairedListener: ((Bool) -> Void)?, isAppInstalledListener: ((Bool) -> Void)?, isComplicationEnabledListener: ((Bool) -> Void)?) Copy public func resumeWatchOSWorkout(completion: @escaping (Bool) -> Void) Copy public func pauseWatchOSWorkout(completion: @escaping (Bool) -> Void) Copy public func stopWatchOSWorkout(completion: @escaping (Bool) -> Void) Copy public func setMessageHandler(_ messageHandler: @escaping([String: Any]) -> Void) Copy public func sendMessage(_ data: [String: Any]) Copy Terra() Copy func sharingDataAuthorised() -> Bool Copy func connect() Copy func setWatchOSConnectionStateListener(listener: @escaping (ConnectionState) -> Void) Copy func startStream(forDataTypes dTypes: Set, completion: @escaping(Bool, TerraWatchOSError?) -> Void) Copy func stopStream() Copy func setUpdateHandler(_ updateHandler: @escaping(Update) -> Void) Copy func startExercise(forType workoutType: WorkoutTypes, completion: @escaping(Bool, TerraWatchOSError?) -> Void) Copy func pauseExercise() Copy func resumeExercise() Copy func stopExercise(completion: @escaping(Bool, TerraWatchOSError?) -> Void) Copy func setWorkoutStateListener(_ workoutStateListener: @escaping(WorkoutStates) -> Void) Copy func setMessageHandler(_ messageHandler: @escaping([String: Any]) -> Void) Copy func sendMessage(_ data: [String: Any]) sun-brightdesktopmoon --- # Core concepts | Terra Docs [hashtag](https://docs.tryterra.co/introduction/core-concepts#terra-credentials) Terra credentials ------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#developer-id) Developer ID * **What it is:** Your Developer ID `dev-id` is your unique identifier as a developer on the Terra platform. Think of it like your username. * **Its role:** Terra uses this to identify you and associate connected [Users](https://docs.tryterra.co/introduction/core-concepts#user) and their data back to your account. * **Security:** Not sensitive; can be publicly available. * **Where to find it:** [Credentials section](https://docs.tryterra.co/introduction/account-setup-and-api-keys) of your Terra Dashboard. circle-info Think of your dev ID like your username It does not constitute sensitive information. Making it publicly available is not a security concern. ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#api-key) API Key * **What is is:** Your API key is your secret access token for the API. Think of it like your password. * **Its role:** Authenticates your application's requests, verifying you're the legitimate developer behind the `dev-id`. * **Security:** Highly sensitive; treat it like a password and never expose it publicly or in client-side code. * **Where to find it:** [Credentials section](https://docs.tryterra.co/introduction/account-setup-and-api-keys) of your Terra Dashboard. circle-info Think of your API Key like your **password** It constitutes sensitive information. Making it publicly available is a big security risk * * * [hashtag](https://docs.tryterra.co/introduction/core-concepts#data-flow-and-connections) Data flow & Connections --------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#source-provider-integration) Source (Provider/Integration) * **What it is:** A **Source** (also referred to as a **Provider,** or **Integration**) is the origin of health and fitness data (e.g., Fitbit, Garmin, Apple Health). * **Management:** You can enable or disable Sources via your [Terra Dashboardarrow-up-right](https://dashboard.tryterra.co/dashboard/connections) , controlling the flow of data. * **List of sources:** You can view a list of all available health data sources [here](https://docs.tryterra.co/reference/health-and-fitness-api/supported-integrations#integrations-list) . ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#destination) Destination * **What it is:** Where Terra sends the processed data (e.g., your server via Webhook, SQL database, Azure Blob storage, Amazon SQS queue). * **Customisation:** Configure your active Destination in the [Terra Dashboardarrow-up-right](https://dashboard.tryterra.co/dashboard/connections) . * **List of destinations:** You can view a list of all available destinations [here](https://docs.tryterra.co/reference/health-and-fitness-api/destinations) . ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#user-terra-user) User (Terra user) * **What it is:** Represents a connection made through Terra to a specific fitness wearable account (e.g., one Fitbit account, one Garmin account). * **Key point:** A single [End User](https://docs.tryterra.co/introduction/core-concepts#end-user-the-person) (a real person) might have multiple Terra Users if they connect different wearable accounts (e.g., both their Fitbit and their Garmin). Each connection creates a new Terra User ID. * **For reference:** Throughout this documentation, a connection made to one fitness wearable account (e.g. one Fitbit account, or one Garmin account) will be referred to as "one User". ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#end-user-the-person) End User (The person) * **What it is:** The actual individual who owns the wearable devices and whose data is being accessed. An End User can be associated with multiple [Terra Users](https://docs.tryterra.co/introduction/core-concepts#user-terra-user) . ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#reference-id) Reference ID * **What it is:** An identifier you provide to link a [Terra User](https://docs.tryterra.co/introduction/core-concepts#user-terra-user) back to an [End User](https://docs.tryterra.co/introduction/core-concepts#end-user-the-person) in your own system. * **Purpose:** The `reference_id` should be the identifier of the End User on your systems. This could be the End User's username, their email address, or any way in which you identify them. * **How you use it:** When creating a User, you will have the option of passing in a `reference_id` to conveniently link it back to an End User * * * [hashtag](https://docs.tryterra.co/introduction/core-concepts#data-and-events) Data & events ------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#event) Event * **What it is:** A piece of data, typically a JSON object, sent to your [Destination](https://docs.tryterra.co/introduction/core-concepts#destination) . * **Types:** Can be specific [Data Types](https://docs.tryterra.co/introduction/core-concepts#data-types) (like an activity or sleep session) or a metadata event (e.g., authentication success). ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#data-types) Data types * **Concept:** Categories of health and fitness information Terra processes. Each has a defined structure. * **Examples:** * **Activity:** A completed workout session (not currently active or planned) by the user, with a **defined start and end time**. For example, this corresponds to when a user would press "start workout" on their Garmin smartwatch, go for a run, then press "end workout". * **Sleep:** A sleep session completed by the [user](https://docs.tryterra.co/introduction/core-concepts#end-user-the-person) . The start time and end time can be representative of the time that the user got in bed instead of the time that they fell asleep at, if tracked by the wearable device - potentially including time in bed vs. time asleep. * **Daily:** A summary of the total activity completed by a user for a given 24 hour period, defined by the start and end time of the payload. * These payloads will be sent multiple times throughout a given day, as a user moves around, and will be a total of their activity up until that point in the day. * When ingesting Daily events, always overwrite data for a given date with the latest one sent to your Destination. * **Body:** This represents the various Body metrics for a user for a given 24 hour period, defined by the start and end time of the payload. * These payloads will be sent multiple times throughout a given day, as a user generates more body-related metrics (weigh-ins, blood glucose measurements etc), and will be a total up until that point in the day. * When ingesting Body events, always overwrite data for a given date with the latest one sent to your Destination. * **Menstruation:** This represents a day in the user's menstrual cycle, and includes information about that day within the context of their overall monthly cycle, such as current phase, and any metadata associated with that day (bleeding level, feelings of nausea, etc). * **Nutrition:** This represents the various food logged by a user for a given 24 hour period, defined by the start and end time of the payload. * This will be data logged in Food Diary apps such as MyFitnessPal, Fitbit or MacrosFirst. Each meal represents a given food item logged within that day. ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#large-request) Large Request * **What it is:** A [data](https://docs.tryterra.co/introduction/core-concepts#data-types) request spanning more than 28 days (unless defined otherwise). * **Processing:** This type of request will **always** be processed asynchronously, and sent to your [destinations](https://docs.tryterra.co/introduction/core-concepts#destinations) in chunks. The chunks sent to you will each be of either: * At most 10MB * At most 10 objects within the `data` array * Whichever limit of the two gets hit first will determine the chunk's size * * * [hashtag](https://docs.tryterra.co/introduction/core-concepts#integration-mechanisms) Integration mechanisms ----------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#event-driven-integrations) Event-driven integrations * **How it works:** Integrations that are **Event-Driven** allow for the fastest data retrieval speeds. As soon as new data is synced from the user's wearable's app (e.g. the Fitbit app) to the [Provider's](https://docs.tryterra.co/introduction/core-concepts#source-provider-integration) cloud, a notification (or **event**) gets sent to Terra with the newest data, following which Terra sends you a [payload](https://docs.tryterra.co/introduction/core-concepts#payload) to your [Destination](https://docs.tryterra.co/introduction/core-concepts#destinations) with the latest available data. ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#polled-integrations) Polled integrations * **How it works:** Integrations that are **Polled** do not have an event-sending system, and require Terra to periodically check for data updates by **polling** their servers. This will be done as often as **every 5 minutes**. * * * [hashtag](https://docs.tryterra.co/introduction/core-concepts#api-versions) API Versions --------------------------------------------------------------------------------------------- Terra API is versioned to manage changes and improvements. ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#major-api-versions) Major API versions * **Indication:** Significant architectural changes to API endpoints and infrastructure. These API versions are **very infrequent**. * **Identification:** You will identify these with the base URL (i.e. `api.tryterra.co/v2`**,** `api.tryterra.co/v1`, and `access.tryterra.co` are 3 separate major versions) ### [hashtag](https://docs.tryterra.co/introduction/core-concepts#minor-api-versions) Minor API versions * **Indication:** Smaller updates, often non-breaking. * **Identification:** You can identify these by the `version` included in every payload you receive from Terra, and will be versioned by date. * For example, at the time of writing, the latest API version is `2022-03-16`. The version prior to it was `2022-03-02`. * Only breaking changes to the API are versioned. Any non breaking changes will be continuously developed, tested, and deployed. [PreviousAccount setup and API keyschevron-left](https://docs.tryterra.co/introduction/account-setup-and-api-keys) [NextOverviewchevron-right](https://docs.tryterra.co/health-and-fitness-api/getting-started) Last updated 19 days ago Was this helpful? * [Terra credentials](https://docs.tryterra.co/introduction/core-concepts#terra-credentials) * [Developer ID](https://docs.tryterra.co/introduction/core-concepts#developer-id) * [API Key](https://docs.tryterra.co/introduction/core-concepts#api-key) * [Data flow & Connections](https://docs.tryterra.co/introduction/core-concepts#data-flow-and-connections) * [Source (Provider/Integration)](https://docs.tryterra.co/introduction/core-concepts#source-provider-integration) * [Destination](https://docs.tryterra.co/introduction/core-concepts#destination) * [User (Terra user)](https://docs.tryterra.co/introduction/core-concepts#user-terra-user) * [End User (The person)](https://docs.tryterra.co/introduction/core-concepts#end-user-the-person) * [Reference ID](https://docs.tryterra.co/introduction/core-concepts#reference-id) * [Data & events](https://docs.tryterra.co/introduction/core-concepts#data-and-events) * [Event](https://docs.tryterra.co/introduction/core-concepts#event) * [Data types](https://docs.tryterra.co/introduction/core-concepts#data-types) * [Large Request](https://docs.tryterra.co/introduction/core-concepts#large-request) * [Integration mechanisms](https://docs.tryterra.co/introduction/core-concepts#integration-mechanisms) * [Event-driven integrations](https://docs.tryterra.co/introduction/core-concepts#event-driven-integrations) * [Polled integrations](https://docs.tryterra.co/introduction/core-concepts#polled-integrations) * [API Versions](https://docs.tryterra.co/introduction/core-concepts#api-versions) * [Major API versions](https://docs.tryterra.co/introduction/core-concepts#major-api-versions) * [Minor API versions](https://docs.tryterra.co/introduction/core-concepts#minor-api-versions) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # React Native | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#react-native-functions) React Native Functions ------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#connection-setup) **Connection Setup** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#initterra) initTerra Initializes Terra for the given developer ID and optional reference ID. Copy tsxCopy codeexport function initTerra(devId: String, referenceId?: String): Promise * `devId`: The developer ID used for initialization. * `referenceId`: An optional reference ID. * **Returns**: A `Promise` indicating whether the initialization was successful. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#initconnection) initConnection Initializes a connection using the provided authentication token. Copy tsxCopy codeexport function initConnection(token: String): Promise * `token`: The authentication token generated by your backend. * **Returns**: A `Promise` indicating whether the connection initialization was successful. **Disconnection** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#disconnect) disconnect Disconnects from the specified connection types. * `connections`: The connection types to disconnect from. * **Returns**: A `Promise` indicating whether the disconnection was successful. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#getuserid) getUserId Retrieves the user ID associated with the device. * **Returns**: A `Promise` containing the user ID and success status. * * * ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#device-scanning) **Device Scanning** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#startdevicescan) startDeviceScan Starts a device scan for the specified connection types. * `connections`: The connection types (e.g., `BLE`, `WATCH_OS`) for which to scan. * `useCache`: Whether to use cached devices if available (default: `false`). * `showWidgetIfCacheNotFound`: Whether to show a widget if no cached devices are found (default: `false`). * **Returns**: A `Promise` indicating whether the scan was successful. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#startdevicescanwithcallback) startDeviceScanWithCallback Starts a device scan with a callback specific to the platform (iOS or Android). * `connections`: The connection types to scan for. * **Returns**: A `Promise` indicating whether the scan was successful. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#connectdevice) connectDevice Connects to a specific device by its ID. * `device`: The device to connect to, which includes an ID and name. * **Returns**: A `Promise` indicating whether the connection was successful. * * * ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#data-streaming) **Data Streaming** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#startrealtime) startRealtime Starts real-time data streaming for the specified connections and data types. * `connections`: The connection types from which to stream data. * `dataTypes`: The data types to stream (e.g., heart rate, steps). * `token`: An optional token for authentication (default: `null`). * **Returns**: A `Promise` indicating whether real-time data streaming was successfully started. #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#stoprealtime) stopRealtime Stops real-time data streaming for the specified connections. * `connections`: The connection types to stop streaming from. * **Returns**: A `Promise` indicating whether the real-time streaming was successfully stopped. * * * ### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#watchos-integration) **WatchOS Integration** #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#connectwithwatchos) connectWithWatchOS Establishes a connection with WatchOS. * **Returns**: A `Promise` indicating whether the connection to WatchOS was successful. * * * [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#types) Types --------------------------------------------------------------------------------------------------- **SuccessMessage** Represents a success response from various operations. * `success`: A boolean indicating whether the operation was successful. * `error`: A nullable string containing error details, if any. **GetUserId** Represents the response from retrieving the user ID. * `success`: A boolean indicating whether the user ID was successfully retrieved. * `userId`: The user ID, or `null` if it was not found. **Update** Represents an update received from a device. * `ts`: The timestamp of the update. * `val`: The value associated with the update (e.g., heart rate). * `type`: The data type (e.g., heart rate, steps). * `d`: An array of values for complex data types (e.g., acceleration). **Device** Represents a device that can be connected to. * `id`: The ID of the device. * `name`: The name of the device. * `type`: The type of the device (e.g., BLE, WatchOS). * * * #### [hashtag](https://docs.tryterra.co/reference/streaming-api/reference/react-native#enums) Enums **Connections** The `Connections` enum represents the different connection types available in the Terra SDK. **DataTypes** The `DataTypes` enum represents the different data types that can be streamed from a device. [PreviousFlutterchevron-left](https://docs.tryterra.co/reference/streaming-api/reference/flutter) [NextSupported Integrationschevron-right](https://docs.tryterra.co/reference/teams-api/supported-integrations) Was this helpful? * [React Native Functions](https://docs.tryterra.co/reference/streaming-api/reference/react-native#react-native-functions) * [Connection Setup](https://docs.tryterra.co/reference/streaming-api/reference/react-native#connection-setup) * [Device Scanning](https://docs.tryterra.co/reference/streaming-api/reference/react-native#device-scanning) * [Data Streaming](https://docs.tryterra.co/reference/streaming-api/reference/react-native#data-streaming) * [WatchOS Integration](https://docs.tryterra.co/reference/streaming-api/reference/react-native#watchos-integration) * [Types](https://docs.tryterra.co/reference/streaming-api/reference/react-native#types) Was this helpful? sun-brightdesktopmoon Copy tsxCopy codeexport function disconnect(connections: Connections): Promise Copy tsxCopy codeexport function getUserId(): Promise Copy tsxCopy codeexport function startDeviceScan( connections: Connections, useCache: Boolean = false, showWidgetIfCacheNotFound: Boolean = false ): Promise Copy tsxCopy codeexport function startDeviceScanWithCallback(connections: Connections): Promise Copy tsxCopy codeexport function connectDevice(device: Device): Promise Copy tsxCopy codeexport function startRealtime( connections: Connections, dataTypes: Array, token: String | null = null ): Promise Copy tsxCopy codeexport function stopRealtime(connections: Connections): Promise Copy tsxCopy codeexport function connectWithWatchOS(): Promise Copy tsxCopy codeexport type SuccessMessage = { success: Boolean; error: String | null; }; Copy tsxCopy codeexport type GetUserId = { success: Boolean; userId: String | null; }; Copy tsxCopy codeexport type Update = { ts: String | null; val: number | null; type: String | null; d: Array | null; }; Copy tsxCopy codeexport type Device = { id: String | null; name: String | null; type: String; }; Copy tsxCopy codeexport enum Connections { ANT = 'ANT', BLE = 'BLE', WEAR_OS = 'WEAR_OS', WATCH_OS = 'WATCH_OS', ANDROID = 'ANDROID', ALL_DEVICES = 'ALL_DEVICES', APPLE = 'APPLE', } Copy tsxCopy codeexport enum DataTypes { HEART_RATE = 'HEART_RATE', ECG = 'ECG', STEPS = 'STEPS', HRV = 'HRV', CALORIES = 'CALORIES', LOCATION = 'LOCATION', DISTANCE = 'DISTANCE', ACTIVITY = 'ACTIVITY', ACCELERATION = 'ACCELERATION', GYROSCOPE = 'GYROSCOPE', FLOORS_CLIMBED = 'FLOORS_CLIMBED', STEPS_CADENCE = 'STEPS_CADENCE', SPEED = 'SPEED', POWER = 'POWER', BIKE_CADENCE = 'BIKE_CADENCE', MET = 'MET', RR_INTERVAL = 'RR_INTERVAL', } sun-brightdesktopmoon --- # Overview | Terra Docs [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#what-is-health-and-fitness-api) What is Health & Fitness API? -------------------------------------------------------------------------------------------------------------------------------------------- Terra's Health & Fitness API is your primary gateway to accessing comprehensive health data in your app from your users' wearables, devices, health apps, and medical devices. * It **standardises** endpoints for authentication, requests, and data models across 500+ data sources. * It's **event-based**: user health and fitness data is automatically pushed to your destination (e.g., webhook) after authentication. API requests are therefore only needed for historical data. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Ffiles.readme.io%2Ff6a8853-web_api_cropped.png&width=768&dpr=3&quality=100&sign=381d2a5c&sv=2) Diagram showing the flow of data through Terra's Health & Fitness API * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#key-features) Key features --------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#automatic-payloads-for-new-data-via-webhook) 🎣 Automatic payloads for new data (via Webhook) * **Mechanism:** Receive automated, near real-time data updates via HTTP POST requests (Webhooks) to your specified Destination endpoint. * **Trigger:** Webhooks are typically triggered when new data is synced from a user's wearable or app to the provider's cloud service and subsequently processed by Terra. * **Content:** Payloads include standardised JSON representing new or updated user data (e.g., a completed workout, daily summary, new sleep session). * **Use Case:** Keep your application's data for users current without needing to poll for changes. Ideal for timely insights and responsive features. **Example payload:** Garmin example [herearrow-up-right](https://tryterra.co/integrations/garmin) . ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#historical-data-retrieval-via-get-requests) 🗄️ Historical data retrieval (via GET requests) * **Mechanism:** Make synchronous or asynchronous `GET` requests to specific Terra API endpoints to fetch data for a user over a defined date range. * **Scope:** Access data from the point a user first connected their account to Terra, subject to provider limitations. * **Use Case:** Populate user profiles, establish baselines, perform trend analysis, or backfill data. * **Considerations:** For large data ranges (e.g., >28 days), requests are often processed asynchronously, with data delivered in chunks via Webhooks or to a specified data store. ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#user-authentication) 🔑 User authentication * **Mechanism:** Terra provides tools (e.g., Terra Widget, or APIs to build your own UI) to facilitate the user authentication process, where users grant your application permission to access their health data via Terra. * **User Identity:** Terra manages user connections and provides unique identifiers for each connected data source account. ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#standardised-data-model) 🧩 Standardised data model * **Mechanism:** All data retrieved from various providers is transformed by Terra into consistent, predefined JSON schemas. * **Benefit:** Simplifies integration by providing a uniform data structure, regardless of the original source's format. You code against one set of models. * **Scope:** Applies to all data types (Activity, Sleep, Body, Daily, Nutrition, etc.). Detailed schemas are available in the [Data Models](https://docs.tryterra.co/reference/health-and-fitness-api/data-models) . ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#writing-data) ✏️ Writing data * **Mechanism:** Send data from your application to Terra via specific POST API endpoints, which then attempts to write this data to the connected user's account on the source provider's platform. * **Supported Operations (Examples):** * **Planned Workouts:** Upload structured workout plans that users can access and follow on their wearable devices. * **Provider Dependency:** Only certain providers are supported - this depends on the features supported by the end provider's API. Not all data types or providers support write operations. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#how-terra-accesses-data-cloud-apis-vs-mobile-sdks) How Terra Accesses Data: Cloud APIs vs Mobile SDKs ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Understanding how Terra connects to different data sources is crucial. Type of data source Integrations Integration Platform Web-based source * Garmin * Fitbit * Oura * Strava _500+ other sources_ Backend Server (using the Health & Fitness API) Mobile-only source * Apple Health * Samsung Health * Google Fit * Health Connect _No other sources_ Mobile App (using the Terra Mobile SDK) ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#web-based-sources) Web-based sources **The majority of Terra integrations are web-based providers (e.g., Garmin, Fitbit, Oura, Strava)** * For most providers, Terra integrates directly with their Web APIs. * Whether you are building a web app or mobile app, you should integrate the API in your backend. * Once a user authenticates via the API, Terra can fetch data and send **payloads** (e.g. to a webhook endpoint). ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#mobile-only-sources) Mobile-only **sources** **The only mobile-only sources are: Apple Health, Samsung Health, and Health Connect.** * These sources do not offer Web APIs for third-party developer access. * They require a **mobile app** with a **Terra's** **Mobile SDK** on the user's device to fetch the data. * Your mobile app, equipped with Terra's Mobile SDK, will facilitate the connection to the on-device health data store (e.g., HealthKit on iOS, Health Connect on Android). * The Mobile SDK then securely transmits this data to Terra for processing and delivery of **payloads** to your configured Destination (e.g. to a webhook endpoints). triangle-exclamation [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#only-use-the-mobile-sdk-if-you-need-to) Only use the Mobile SDK if you need to ------------------------------------------------------------------------------------------------------------------------------------------------------------- The **vast majority** of Health & Fitness API **work via Terra's Web API** (e.g., Garmin, Fitbit, Oura, Strava)**.** **You do** _**NOT**_ **need** to use the **Mobile SDK for them.** * * * **Only use the** [**Mobile SDK**](https://docs.tryterra.co/health-and-fitness-api/mobile-only-sources) if you want to integrate **with the following providers:** ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FDH2JWDtg632mUQlEdrLH%252F4p3k173m8ihe71872bi9r0292q-0af5626e815091005bacb793985c1870.png%3Falt%3Dmedia%26token%3D062c917e-02fe-4029-9809-fc881cf09de3&width=40&dpr=3&quality=100&sign=efd2f029&sv=2) **Apple Health** ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252F0lTv9KpldVVjBdg3JJQs%252Fimgbin_samsung-galaxy-samsung-health-samsung-electronics-android-png.png%3Falt%3Dmedia%26token%3Db58f3118-a2e1-4b09-9d30-4f862253adb6&width=40&dpr=3&quality=100&sign=39e1314b&sv=2) **Samsung Health** ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FmotL0wnZKiEWOKt46zOU%252Fvecteezy_google-fit-icon-logo-symbol_22484515.png%3Falt%3Dmedia%26token%3Da2d0ae73-5116-49fd-8ce1-0f7b5e6f716b&width=40&dpr=3&quality=100&sign=e5ed166f&sv=2) **Health Connect** ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#rate-limits) Rate Limits * Terra **never** imposes any rate limits. Downstream providers often have their own rate limits (for example Fitbit limits developers to 150 requests/hour per user), but Terra manages everything for you, including retries with appropriate backoffs, to ensure you always get consistent data. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#next-steps) Next steps ----------------------------------------------------------------------------------------------------- 1 ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#quickstart) [Quickstart](https://docs.tryterra.co/health-and-fitness-api/quickstart) Get health data from your first user via a web-based source (e.g., Garmin, Fitbit, Oura). 2 ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#integration-setup) [Integration setup](https://docs.tryterra.co/health-and-fitness-api/integration-setup) Learn how to setup and configure the Health & Fitness API to receive your users' data to your preferred destination (e.g. webhook, DB, etc). This includes enabling data sources, setting up data destinations, managing API access, and understanding environments. 3 ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#user-authentication-1) [User authentication](https://docs.tryterra.co/health-and-fitness-api/user-authentication) Learn how to securely authenticate your users' health data sources (e.g., Fitbit, Garmin) to your application via Terra, including handling authentication flows and user IDs. 4 ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#accessing-and-managing-user-health-data) [**Accessing & Managing User Health Data**](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data) Learn how to receive automatic data updates as events, request historical information, and write data (like planned workouts) back to users' connected services. 5 ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/getting-started#using-sdks-for-mobile-only-sources) [Using SDKs for mobile-only sources](https://docs.tryterra.co/health-and-fitness-api/mobile-only-sources) Essential reading if you need to integrate Apple Health, Samsung Health, or Google Fit/Health Connect. [PreviousCore conceptschevron-left](https://docs.tryterra.co/introduction/core-concepts) [NextQuickstartchevron-right](https://docs.tryterra.co/health-and-fitness-api/quickstart) Last updated 12 days ago Was this helpful? * [What is Health & Fitness API?](https://docs.tryterra.co/health-and-fitness-api/getting-started#what-is-health-and-fitness-api) * [Key features](https://docs.tryterra.co/health-and-fitness-api/getting-started#key-features) * [🎣 Automatic payloads for new data (via Webhook)](https://docs.tryterra.co/health-and-fitness-api/getting-started#automatic-payloads-for-new-data-via-webhook) * [🗄️ Historical data retrieval (via GET requests)](https://docs.tryterra.co/health-and-fitness-api/getting-started#historical-data-retrieval-via-get-requests) * [🔑 User authentication](https://docs.tryterra.co/health-and-fitness-api/getting-started#user-authentication) * [🧩 Standardised data model](https://docs.tryterra.co/health-and-fitness-api/getting-started#standardised-data-model) * [✏️ Writing data](https://docs.tryterra.co/health-and-fitness-api/getting-started#writing-data) * [How Terra Accesses Data: Cloud APIs vs Mobile SDKs](https://docs.tryterra.co/health-and-fitness-api/getting-started#how-terra-accesses-data-cloud-apis-vs-mobile-sdks) * [Web-based sources](https://docs.tryterra.co/health-and-fitness-api/getting-started#web-based-sources) * [Mobile-only sources](https://docs.tryterra.co/health-and-fitness-api/getting-started#mobile-only-sources) * [Rate Limits](https://docs.tryterra.co/health-and-fitness-api/getting-started#rate-limits) * [Next steps](https://docs.tryterra.co/health-and-fitness-api/getting-started#next-steps) * [Quickstart](https://docs.tryterra.co/health-and-fitness-api/getting-started#quickstart) * [Integration setup](https://docs.tryterra.co/health-and-fitness-api/getting-started#integration-setup) * [User authentication](https://docs.tryterra.co/health-and-fitness-api/getting-started#user-authentication-1) * [Accessing & Managing User Health Data](https://docs.tryterra.co/health-and-fitness-api/getting-started#accessing-and-managing-user-health-data) * [Using SDKs for mobile-only sources](https://docs.tryterra.co/health-and-fitness-api/getting-started#using-sdks-for-mobile-only-sources) Was this helpful? sun-brightdesktopmoon Copy Activity Payload (JSON) { "metadata": { "timestamp_localization": 1, "start_time": "2026-01-19T10:48:51", "name": "Softball", "summary_id": 45209947591, "type": 93, "upload_type": 5, "end_time": "2026-01-19T12:01:51" }, "position_data": { "start_pos_lat_lng_deg": ["..."], "position_samples": ["..."], "center_pos_lat_lng_deg": ["..."], "end_pos_lat_lng_deg": ["..."] }, "distance_data": { "summary": { "...": "..." }, "detailed": { "...": "..." } }, "heart_rate_data": { "summary": { "...": "..." }, "detailed": { "...": "..." } }, "calories_data": { "total_burned_calories": 1285.6, "net_activity_calories": 189.95 }, "movement_data": { "speed_samples": ["..."], "max_speed_meters_per_second": 8.72, "avg_speed_meters_per_second": 9.05, "max_cadence_rpm": 35.74, "avg_cadence_rpm": 37.74 }, "device_data": { "manufacturer": "Terra", "name": "Random device name", "serial_number": 547901 }, "power_data": { "avg_watts": 14.21, "power_samples": ["..."], "max_watts": 24.86 }, "active_durations_data": { "activity_seconds": 981.86 } } chevron-downShow all 50 lines sun-brightdesktopmoon --- # Integration setup | Terra Docs This section guides you through the essential configurations required to connect Terra to your application, define data sources, specify data destinations, and manage your integration settings. Proper setup is crucial for receiving user data effectively. Navigate through the guides below to configure each aspect of your Terra integration. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup#implementation-guides) Implementation guides ----------------------------------------------------------------------------------------------------------------------------- 1 [**Understanding sources and destinations**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-sources-and-destinations) Understand the fundamental concepts of how Terra ingests data from providers and delivers it to your system. 2 [**Setting up data sources**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-sources) Learn how to select and activate the health platforms (e.g., Garmin, Fitbit) your users can connect 3 [**Setting up data destinations**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations) Detailed instructions for setting up where Terra will send processed user data (Webhooks, databases, cloud storage, etc.). * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup#configuration) Configuration ------------------------------------------------------------------------------------------------------------- [**Customising data types**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/customising-data-types) * Customise the specific health and fitness metrics and permission scopes for your integration. [**Dedicated data source API keys**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys) * Instructions for configuring dedicated API keys for specific data providers. [**Understanding Terra environments**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-terra-environments) * Learn about Terra's testing, staging, and production environments and their respective limits. [PreviousQuickstartchevron-left](https://docs.tryterra.co/health-and-fitness-api/quickstart) [NextUnderstanding sources and destinationschevron-right](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-sources-and-destinations) Last updated 19 days ago Was this helpful? * [Implementation guides](https://docs.tryterra.co/health-and-fitness-api/integration-setup#implementation-guides) * [Configuration](https://docs.tryterra.co/health-and-fitness-api/integration-setup#configuration) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Data models | API Reference | Terra Docs > 📘 Note > > All fields in all models are nullable unless explicitly stated otherwise. > 🚧 Uniquely identifying payloads > > ### > > [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#activity-and-sleep) > > Activity & Sleep > > Activity & Sleep payloads can be uniquely identified by their `summary_id` field under `metadata`. If an activity comes in a second time, with the same summary ID, you should update the previous entries with the new data corresponding to that `summary_id` > > ### > > [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#body-daily-nutrition) > > Body, Daily, Nutrition > > Body, Daily, Nutrition payloads can be uniquely identified by the combination of their `start_time` and `end_time` fields under `metadata`. If one of these payloads comes in again, with the same `start_time` and `end_time`, you should update the previous entries with the new data. > > For example, the `Daily` payload can come in multiple times in one day, with updated `steps` field every time > 🚧 Schema parser > > When building a parser for the models below, please take into account that more fields may be added down the line (but no field name should ever change within a given version) > > Also note that this version is equivalent to `2022_03_16` circle-info Our OpenAPI models are available [herearrow-up-right](https://github.com/tryterra/openapi/blob/master/v5-bundled.yaml) ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#terrauser) TerraUser Copy { "user_id": String, // not nullable "provider": String, // not nullable "last_webhook_update": String, "scopes": String, "reference_id": String } [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#core-data-types) Core data types --------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#activity) Activity ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#athlete) Athlete ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#body) Body ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#daily) Daily ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#menstruation) Menstruation ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#nutrition) Nutrition ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#sleep) Sleep [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#enums) Enums ------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#devicedatatype) DeviceDataType Represents data types that a certain device contributed to Name Value Steps STEPS Active minutes ACTIVE\_MINUTES BMR BMR Calories CALORIES Distance DISTANCE Heart Rate HEART\_RATE Oxygen Saturation (SpO2) OXYGEN\_SATURATION Sleep type classification SLEEP\_TYPE Speed SPEED Cadence CADENCE ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#afibflag) AFibFlag Name Value Negative (AFib not present) 0 Positive (AFib present) 1 Inconclusive 2 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#activitytype) ActivityType Name Value In Vehicle 0 Biking 1 Still 3 Unknown 4 Tilting 5 Walking 7 Running 8 Aerobics 9 Badminton 10 Baseball 11 Basketball 12 Biathlon 13 Handbiking 14 Mountain Biking 15 Road Biking 16 Spinning 17 Stationary Biking 18 Utility Biking 19 Boxing 20 Calisthenics 21 Circuit Training 22 Cricket 23 Dancing 24 Elliptical 25 Fencing 26 American Football 27 Australian Football 28 English Football 29 Frisbee 30 Gardening 31 Golf 32 Gymnastics 33 Handball 34 Hiking 35 Hockey 36 Horseback Riding 37 Housework 38 Jumping Rope 39 Kayaking 40 Kettlebell Training 41 Kickboxing 42 Kitesurfing 43 Martial Arts 44 Meditation 45 Mixed Martial Arts 46 P90X Exercises 47 Paragliding 48 Pilates 49 Polo 50 Racquetball 51 Rock Climbing 52 Rowing 53 Rowing Machine 54 Rugby 55 Jogging 56 Running On Sand 57 Treadmill Running 58 Sailing 59 Scuba Diving 60 Skateboarding 61 Skating 62 Cross Skating 63 Indoor Rollerblading 64 Skiing 65 Back Country Skiing 66 Cross Country Skiing 67 Downhill Skiing 68 Kite Skiing 69 Roller Skiing 70 Sledding 71 Snowboarding 73 Snowmobile 74 Snowshoeing 75 Squash 76 Stair Climbing 77 Stair Climbing Machine 78 Stand Up Paddleboarding 79 Strength Training 80 Surfing 81 Swimming 82 Swimming In Pool 83 Open Water Swimming 84 Table Tennis 85 Team Sport 86 Tennis 87 Treadmill 88 Volleyball 89 Beach Volleyball 90 Indoor Volleyball 91 Wakeboarding 92 Walking Fitness 93 Nording Walking 94 Walking Treadmill 95 Waterpolo 96 Weightlifting 97 Wheelchair 98 Windsurfing 99 Yoga 100 Zumba 101 Diving 102 Ergometer 103 Ice Skating 104 Indoor Skating 105 Curling 106 Other 108 Crossfit 113 HIIT 114 Interval Training 115 Walkin Stroller 116 Elevator 117 Escalator 118 Archery 119 Softball 120 Guided Breathing 122 Cardio Training 123 Lacrosse 124 Stretching 125 Triathlon 126 INLINE\_SKATING 127 SKY\_DIVING 128 PADDLING 129 MOUNTAINEERING 130 FISHING 131 WATER\_SKIING 132 INDOOR\_RUNNING 133 PADEL\_TENNIS 134 DRIVING 135 OFF\_ROAD\_DRIVING 136 MOTORBIKING 137 MOTOR\_RACING 138 ENDURO 139 CANOEING 140 ORIENTEERING 141 HANG\_GLIDING 142 FLYING 143 HOT\_AIR\_BALLOONING 144 JET\_SKIING 145 POWER\_BOATING 146 GAELIC\_FOOTBALL 147 HURLING 148 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#activitylevel) ActivityLevel Name Value Unknown 0 Rest 1 Inactive 2 Low Intensity 3 Medium Intensity 4 High Intensity 5 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#heartratezone) HeartRateZone Name Value Zone 0 0 Zone 1 1 Zone 2 2 Zone 3 3 Zone 4 4 Zone 5 5 Other/custom classification 6 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#sleeplevel) SleepLevel Name Value Unknown 0 Awake 1 Sleeping 2 Out of Bed 3 Light 4 Deep 5 REM 6 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#uploadtype) UploadType Name Value Unknown 0 Automatic 1 Manual 2 Update 3 Delete 4 Pending 5 Third party upload 6 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#sleepuploadtype) SleepUploadType Name Value Unknown 0 Manual 1 Automatic 2 Tentative 3 Indeterminate 4 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#stroketype) StrokeType Name Value OTHER other FREESTYLE freestyle BACKSTROKE backstroke BREASTSTROKE breaststroke BUTTERFLY butterfly ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#glucoseflag) GlucoseFlag Name Value Normal 0 High 1 Low 2 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#nutritionunits) NutritionUnits Name Value Unknown 0 Gram 1 Teaspoon 2 Tablespoon 3 Cup 4 Medium 5 Large 6 Small 7 Milliliter 8 Ounce 9 Count 10 Scoop 11 Fluid Ounce 12 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#recoverylevel) RecoveryLevel Name Value Unknown 0 Very Poor 1 Poor 2 Compromised 3 Ok 4 Good 5 Very Good 6 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#trendarrow) TrendArrow Name Value UNKNOWN 0 FALLING\_QUICKLY 1 FALLING 2 FLAT 3 RISING 4 RISING\_QUICKLY 5 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#timezone-localization) Timezone Localization Name Value UTC 0 LOCAL 1 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#menstruationflow) MenstruationFlow Name Value UNKNOWN 0 NONE 1 LIGHT 2 MEDIUM 3 HEAVY 4 HAD 5 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#mealtype) MealType Name Value UNKNOWN 0 BREAKFAST 1 MORNING\_SNACK 2 LUNCH 3 AFTERNOON\_SNACK 4 DINNER 5 SNACK 6 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#stresslevel) StressLevel Name Value NOT\_ENOUGH\_DATA 0 REST 1 LOW 2 MEDIUM 3 HIGH 4 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#heartratecontext) HeartRateContext Name Value NOT\_SET 0 ACTIVE 1 NOT\_ACTIVE 2 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#menstrualphase) MenstrualPhase Name Value MENSTRUAL menstrual FOLLICULAR follicular OVULATION ovulation LUTEAL luteal PMS pms FERTILE fertile FIRST\_TRIMESTER first\_trimester SECOND\_TRIMESTER second\_trimester THIRD\_TRIMESTER third\_trimester UNKNOWN unknown [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#plannedworkout) PlannedWorkout ------------------------------------------------------------------------------------------------------------------- The Workout Types follow the same numbering as the Activity Types that can be found in [https://docs.tryterra.co/reference/enums#activitytypearrow-up-right](https://docs.tryterra.co/reference/enums#activitytype) ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#plannedworkoutstep) PlannedWorkoutStep Step Intensity Name Step Intensity Number Value REST 0 WARMUP 1 COOLDOWN 2 RECOVERY 3 INTERVAL 4 ACTIVE 5 ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#plannedworkoutrepeatstep) PlannedWorkoutRepeatStep ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#plannedworkoutsteptarget) PlannedWorkoutStepTarget Step Target Type Model SPEED `{ "target_type": 0, "speed_meters_per_second": Number, "speed_meters_per_second_low": Number, "speed_meters_per_second_high": Number }` HEART\_RATE `{ "target_type": 1, "hr_bpm_high": Number, "hr_bpm_low": Number }` OPEN `{ "target_type": 2 }` CADENCE `{ "target_type": 3, "cadence": Number, "cadence_high": Number, "cadence_low" : Number }` POWER `{ "target_type": 4, "power_watt_high": Number, "power_watt_low": Number, "power_watt": Number }` SWIM\_STROKE `{ "target_type": 8, "swim_strokes": Number }` PACE `{ "target_type": 11, "speed_meters_per_second": Number, "speed_meters_per_second_low": Number, "speed_meters_per_second_high": Number }` HEART\_RATE\_THRESHOLD\_PERCENTAGE `{ "target_type": 12, "hr_percentage": Number, "hr_percentage_low": Number, "hr_percentage_high": Number }` HEART\_RATE\_MAX\_PERCENTAGE `{ "target_type": 13, "hr_percentage": Number, "hr_percentage_low": Number, "hr_percentage_high": Number }` SPEED\_PERCENTAGE `{ "target_type": 14, "speed_percentage": Number, "speed_percentage_low": Number, "speed_percentage_high": Number }` POWER\_PERCENTAGE `{ "target_type": 15, "power_percentage": Number, "power_percentage_low": Number, "power_percentage_high": Number }` REPETITION `{ "target_type": 16, "repetitions": Number }` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#plannedworkoutstepduration) PlannedWorkoutStepDuration Step Duration Type Model TIME `{ "duration_type": 0, "seconds": Number }` DISTANCE\_METERS `{ "duration_type": 1, "distance_meters": Number }` HR\_LESS\_THAN `{ "duration_type": 2, "hr_below_bpm": Number }` HR\_GREATER\_THAN `{ "duration_type": 3, "hr_above_bpm": Number }` CALORIES `{ "duration_type": 4, "calories": 2.0 }` OPEN `{ "duration_type": 5 }` POWER\_LESS\_THAN `{ "duration_type": 6, "power_below_watts": Number }` POWER\_GREATER\_THAN `{ "duration_type": 7, "power_above_watts": Number }` REPS `{ "duration_type": 9, "reps": Number }` FIXED\_REST `{ "duration_type": 10, "rest_seconds": Number }` STEPS `{ "duration_type": 12, "steps": Number }` ### [hashtag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#enums-1) Enums Stroke Type Value BACKSTROKE 0 BREASTSTROKE 1 DRILL 2 BUTTERFLY 3 FREESTYLE 4 MIXED 5 IM 6 Equipement Type Value NONE 0 SWIM\_FINS 1 SWIM\_KICKBOARD 2 SWIM\_PADDLES 3 SWIM\_PULL\_BUOY 4 SWIM\_SNORKEL 5 Exercice Type Value UNKNOWN 0 BENCH\_PRESS 1 CALF\_RAISE 2 CARDIO 3 CARRY 4 CHOP 5 CORE 6 CRUNCH 7 CURL 8 DEADLIFT 9 FLYE 10 HIP\_RAISE 11 HIP\_STABILITY 12 HIP\_SWING 13 HYPEREXTENSION 14 LATERAL\_RAISE 15 LEG\_CURL 16 LEG\_RAISE 17 LUNGE 18 OLYMPIC\_LIFT 19 PLANK 20 PLYO 21 PULL\_UP 22 PUSH\_UP 23 ROW 24 SHOULDER\_PRESS 25 SHOULDER\_STABILITY 26 SHRUG 27 SIT\_UP 28 SQUAT 29 TOTAL\_BODY 30 TRICEPS\_EXTENSION 31 WARM\_UP 32 RUN 33 BIKE 34 CARDIO\_SENSORS 35 [PreviousEvent Typeschevron-left](https://docs.tryterra.co/reference/health-and-fitness-api/event-types) [NextSampleschevron-right](https://docs.tryterra.co/reference/health-and-fitness-api/samples) Last updated 2 days ago Was this helpful? * [TerraUser](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#terrauser) * [Core data types](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#core-data-types) * [Activity](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#activity) * [Athlete](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#athlete) * [Body](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#body) * [Daily](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#daily) * [Menstruation](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#menstruation) * [Nutrition](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#nutrition) * [Sleep](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#sleep) * [Enums](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#enums) * [DeviceDataType](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#devicedatatype) * [AFibFlag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#afibflag) * [ActivityType](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#activitytype) * [ActivityLevel](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#activitylevel) * [HeartRateZone](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#heartratezone) * [SleepLevel](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#sleeplevel) * [UploadType](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#uploadtype) * [SleepUploadType](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#sleepuploadtype) * [StrokeType](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#stroketype) * [GlucoseFlag](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#glucoseflag) * [NutritionUnits](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#nutritionunits) * [RecoveryLevel](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#recoverylevel) * [TrendArrow](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#trendarrow) * [Timezone Localization](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#timezone-localization) * [MenstruationFlow](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#menstruationflow) * [MealType](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#mealtype) * [StressLevel](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#stresslevel) * [HeartRateContext](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#heartratecontext) * [MenstrualPhase](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#menstrualphase) * [PlannedWorkout](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#plannedworkout) * [PlannedWorkoutStep](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#plannedworkoutstep) * [PlannedWorkoutRepeatStep](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#plannedworkoutrepeatstep) * [PlannedWorkoutStepTarget](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#plannedworkoutsteptarget) * [PlannedWorkoutStepDuration](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#plannedworkoutstepduration) * [Enums](https://docs.tryterra.co/reference/health-and-fitness-api/data-models#enums-1) Was this helpful? sun-brightdesktopmoon Copy { // NOTE ──────────────────────────────────────────────────── // ❶ Unless a property is explicitly documented as // “required / non‑null”, **it may be `null`.** // ❷ Date‑time strings are ISO‑8601. // ❸ Top‑level keys are listed alphabetically for clarity. // ───────────────────────────────────────────────────────── "active_durations_data": { "activity_levels_samples": Array, "activity_seconds": Number, "inactivity_seconds": Number, "low_intensity_seconds": Number, "moderate_intensity_seconds": Number, "num_continuous_inactive_periods": Number, "rest_seconds": Number, "standing_hours_count": Number, "standing_seconds": Number, "vigorous_intensity_seconds": Number }, "calories_data": { "BMR_calories": Number, "calorie_samples": Array, "net_activity_calories": Number, "net_intake_calories": Number, "total_burned_calories": Number }, "cheat_detection": CheatDetection, "data_enrichment": { "stress_score": Number }, "device_data": { "activation_timestamp": String, "data_provided": Array, "hardware_version": String, "last_upload_date": String, "manufacturer": String, "name": String, "other_devices": Array, "serial_number": String, "software_version": String }, /* schema for each element of other_devices */ "OtherDeviceData": { "activation_timestamp": String, "data_provided": Array, "hardware_version": String, "last_upload_date": String, "manufacturer": String, "name": String, "serial_number": String, "software_version": String }, "distance_data": { "detailed": { "distance_samples": Array, "elevation_samples": Array, "floors_climbed_samples": Array, "step_samples": Array }, "summary": { "distance_meters": Number, "elevation": { "avg_meters": Number, "gain_actual_meters": Number, "gain_planned_meters": Number, "loss_actual_meters": Number, "max_meters": Number, "min_meters": Number }, "floors_climbed": Number, "steps": Number, "swimming": { "num_laps": Number, "num_strokes": Number, "pool_length_meters": Number } } }, "energy_data": { "energy_kilojoules": Number, "energy_planned_kilojoules": Number }, "heart_rate_data": { "detailed": { "hr_samples": Array, "hrv_samples_rmssd": Array, "hrv_samples_sdnn": Array }, "summary": { "avg_hr_bpm": Number, "avg_hrv_rmssd": Number, "avg_hrv_sdnn": Number, "hr_zone_data": Array, "max_hr_bpm": Number, "min_hr_bpm": Number, "resting_hr_bpm": Number, "user_max_hr_bpm": Number } }, "lap_data": { "laps": Array }, "MET_data": { "MET_samples": Array, "avg_level": Number, "num_high_intensity_minutes": Number, "num_inactive_minutes": Number, "num_low_intensity_minutes": Number, "num_moderate_intensity_minutes": Number }, "metadata": { "city": String, "country": String, "end_time": String, // required "name": String, "start_time": String, // required "state": String, "summary_id": String, // required "timestamp_localization": Number, "type": ActivityType, // required "upload_type": UploadType // required }, "movement_data": { "adjusted_max_speed_meters_per_second": Number, "avg_cadence_rpm": Number, "avg_pace_minutes_per_kilometer": Number, "avg_speed_meters_per_second": Number, "avg_torque_newton_meters": Number, "avg_velocity_meters_per_second": Number, "cadence_samples": Array, "max_cadence_rpm": Number, "max_pace_minutes_per_kilometer": Number, "max_speed_meters_per_second": Number, "max_torque_newton_meters": Number, "max_velocity_meters_per_second": Number, "normalized_speed_meters_per_second": Number, "speed_samples": Array, "torque_samples": Array }, "oxygen_data": { "avg_saturation_percentage": Number, "saturation_samples": Array, "vo2_samples": Array, "vo2max_ml_per_min_per_kg": Number }, "polyline_map_data": { "summary_polyline": String }, "position_data": { "center_pos_lat_lng_deg": [Number, Number], "end_pos_lat_lng_deg": [Number, Number], "position_samples": Array, "start_pos_lat_lng_deg": [Number, Number] }, "power_data": { "avg_watts": Number, "max_watts": Number, "power_samples": Array }, "strain_data": { "strain_level": Number }, "TSS_data": { "TSS_samples": Array }, "work_data": { "work_kilojoules": Number } } Copy { "age": Number, "country": String, "bio": String, "state": String, "last_name": String, "sex": String, "city": String, "email": String, "date_of_birth": String, "first_name": String, "gender": String, "joined_provider": String, "devices": Array } Copy { "blood_pressure_data": { "blood_pressure_samples": Array }, "device_data": { "activation_timestamp": String, "hardware_version": String, "software_version": String, "serial_number": String, "manufacturer": String, "name": String, "sensor_state": String, "other_devices": Array, "data_provided": Array, "last_upload_date": String }, "heart_data": { "afib_classification_samples": Array, "ecg_signal": Array, "heart_rate_data": { "detailed": { "hr_samples": Array, "hrv_samples_rmssd": Array, "hrv_samples_sdnn": Array }, "summary": { "avg_hr_bpm": Number, "avg_hrv_rmssd": Number, "avg_hrv_sdnn": Number, "hr_zone_data": Array, "max_hr_bpm": Number, "min_hr_bpm": Number, "resting_hr_bpm": Number, "user_max_hr_bpm": Number } }, "pulse_wave_velocity_samples": Array, "rr_interval_samples": Array }, "hydration_data": { "day_total_water_consumption_ml": Number, "hydration_amount_samples": Array }, "ketone_data": { "ketone_samples": Array }, "measurements_data": { "measurements": Array }, "metadata": { "start_time": String, // required (ISO-8601) "end_time": String, // required (ISO-8601) "timestamp_localization": Number // 0 = UTC, 1 = local-time, etc. }, "oxygen_data": { "avg_saturation_percentage": Number, "saturation_samples": Array, "vo2_samples": Array, "vo2max_ml_per_min_per_kg": Number }, "temperature_data": { "ambient_temperature_samples": Array, "body_temperature_samples": Array, "skin_temperature_samples": Array }, "glucose_data": { "blood_glucose_samples": Array, "detailed_blood_glucose_samples": Array, "daily_patterns": Array, "sensor_usage": Number, "day_avg_blood_glucose_mg_per_dL": Number, "time_in_range": Number, "gmi": Number } } Copy { "active_durations_data": { "activity_levels_samples": Array, "activity_seconds": Number, "inactivity_seconds": Number, "low_intensity_seconds": Number, "moderate_intensity_seconds": Number, "num_continuous_inactive_periods": Number, "rest_seconds": Number, "standing_hours_count": Number, "standing_seconds": Number, "vigorous_intensity_seconds": Number }, "calories_data": { "BMR_calories": Number, "calorie_samples": Array, "net_activity_calories": Number, "net_intake_calories": Number, "total_burned_calories": Number }, "data_enrichment": { "cardiovascular_contributors": Array, "cardiovascular_score": Number, "immune_contributors": Array, "immune_index": Number, "readiness_contributors": Array, "readiness_score": Number, "respiratory_contributors": Array, "respiratory_score": Number, "start_time": String, "stress_contributors": Array, "total_stress_score": Number }, "device_data": { "activation_timestamp": String, "data_provided": Array, "hardware_version": String, "last_upload_date": String, "manufacturer": String, "name": String, "other_devices": Array, "serial_number": String, "software_version": String }, "distance_data": { "detailed": { "distance_samples": Array, "elevation_samples": Array, "floors_climbed_samples": Array, "step_samples": Array }, "distance_meters": Number, "elevation": { "avg_meters": Number, "gain_actual_meters": Number, "gain_planned_meters": Number, "loss_actual_meters": Number, "max_meters": Number, "min_meters": Number }, "floors_climbed": Number, "steps": Number, "swimming": { "num_laps": Number, "num_strokes": Number, "pool_length_meters": Number } }, "heart_rate_data": { "detailed": { "hr_samples": Array, "hrv_samples_rmssd": Array, "hrv_samples_sdnn": Array }, "summary": { "avg_hr_bpm": Number, "avg_hrv_rmssd": Number, "avg_hrv_sdnn": Number, "hr_zone_data": Array, "max_hr_bpm": Number, "min_hr_bpm": Number, "resting_hr_bpm": Number, "user_max_hr_bpm": Number } }, "MET_data": { "MET_samples": Array, "avg_level": Number, "num_high_intensity_minutes": Number, "num_inactive_minutes": Number, "num_low_intensity_minutes": Number, "num_moderate_intensity_minutes": Number }, "metadata": { "end_time": String, // required "start_time": String, // required "timestamp_localization": Number, "upload_type": UploadType // required }, "oxygen_data": { "avg_saturation_percentage": Number, "saturation_samples": Array, "vo2_samples": Array, "vo2max_ml_per_min_per_kg": Number }, "scores": { "activity": Number, "recovery": Number, "sleep": Number }, "strain_data": { "strain_level": Number }, "stress_data": { "activity_stress_duration_seconds": Number, "avg_stress_level": Number, "body_battery_samples": Array, "high_stress_duration_seconds": Number, "low_stress_duration_seconds": Number, "max_stress_level": Number, "medium_stress_duration_seconds": Number, "rest_stress_duration_seconds": Number, "samples": Array, "stress_duration_seconds": Number, "stress_rating": Number }, "tag_data": { "tags": Array } } Copy { "metadata": { "end_time": String, "start_time": String, "timestamp_localization": Number }, "menstruation_data": { "menstruation_flow": Array, "intervals": Array, "period_length_days": Number, "fertility_window_start": String, "fertility_window_end": String, "predicted_cycle_length_days": Number, "last_updated_time": String, "day_in_cycle": Number, "length_of_current_phase_days": Number, "period_start_date": String, "cycle_length_days": Number, "ovulation_day": String, "current_phase": MenstrualPhase, "is_predicted_cycle": Boolean, "days_until_next_phase": Number } } Copy { "drink_samples": Array, "meals": Array, "metadata": { "end_time": String, // required – ISO‑8601 "start_time": String, // required – ISO‑8601 "timestamp_localization": Number }, "summary": { "macros": { "alcohol_g": Number, "calories": Number, "carbohydrates_g": Number, "cholesterol_mg": Number, "fat_g": Number, "fiber_g": Number, "net_carbohydrates_g": Number, "protein_g": Number, "saturated_fat_g": Number, "sodium_mg": Number, "sugar_g": Number, "trans_fat_g": Number }, "micros": { "biotin_mg": Number, "caffeine_mg": Number, "calcium_mg": Number, "chloride_mg": Number, "chromium_mg": Number, "copper_mg": Number, "folate_mg": Number, "folic_acid_mg": Number, "iodine_mg": Number, "iron_mg": Number, "magnesium_mg": Number, "manganese_mg": Number, "molybdenum_mg": Number, "niacin_mg": Number, "pantothenic_acid_mg": Number, "phosphorus_mg": Number, "potassium_mg": Number, "riboflavin_mg": Number, "selenium_mg": Number, "thiamin_mg": Number, "vitamin_A_mg": Number, "vitamin_B12_mg": Number, "vitamin_B6_mg": Number, "vitamin_C_mg": Number, "vitamin_D_mg": Number, "vitamin_D2_mg": Number, "vitamin_D3_mg": Number, "vitamin_E_mg": Number, "vitamin_K_mg": Number, "zinc_mg": Number, /* amino‑acids & related */ "cystine_g": Number, "histidine_g": Number, "isoleucine_g": Number, "leucine_g": Number, "lysine_g": Number, "methionine_g": Number, "phenylalanine_g": Number, "threonine_g": Number, "tryptophan_g": Number, "tyrosine_g": Number, "valine_g": Number, /* fats & fatty‑acids */ "monounsaturated_fat_g": Number, "polyunsaturated_fat_g": Number, "omega3_g": Number, "omega6_g": Number, /* carbohydrates */ "starch_g": Number }, "water_ml": Number, "drink_ml": Number } } Copy { "data_enrichment": { "sleep_contributors": Array, "sleep_score": Number }, "device_data": { "activation_timestamp": String, "data_provided": Array, "hardware_version": String, "last_upload_date": String, "manufacturer": String, "name": String, "other_devices": Array, "serial_number": String, "software_version": String }, "heart_rate_data": { "detailed": { "hr_samples": Array, "hrv_samples_rmssd": Array, "hrv_samples_sdnn": Array }, "summary": { "avg_hr_bpm": Number, "avg_hrv_rmssd": Number, "avg_hrv_sdnn": Number, "hr_zone_data": Array, "max_hr_bpm": Number, "min_hr_bpm": Number, "resting_hr_bpm": Number, "user_max_hr_bpm": Number } }, "metadata": { "end_time": String, // required – ISO‑8601 "start_time": String, // required – ISO‑8601 "is_nap": Boolean, "summary_id": String, "timestamp_localization": Number, "upload_type": SleepUploadType // required }, "readiness_data": { "readiness": Number, "recovery_level": RecoveryLevel }, "respiration_data": { "breaths_data": { "avg_breaths_per_min": Number, "end_time": String, "max_breaths_per_min": Number, "min_breaths_per_min": Number, "on_demand_reading": Boolean, "samples": Array, "start_time": String }, "oxygen_saturation_data": { "avg_saturation_percentage": Number, "end_time": String, "samples": Array, "start_time": String }, "snoring_data": { "end_time": String, "num_snoring_events": Number, "samples": Array, "start_time": String, "total_snoring_duration_seconds": Number } }, "scores": { "sleep": Number }, "sleep_durations_data": { "asleep": { "duration_asleep_state_seconds": Number, "duration_deep_sleep_state_seconds": Number, "duration_light_sleep_state_seconds": Number, "duration_REM_sleep_state_seconds": Number, "num_REM_events": Number }, "awake": { "duration_awake_state_seconds": Number, "duration_long_interruption_seconds": Number, "duration_short_interruption_seconds": Number, "num_out_of_bed_events": Number, "num_wakeup_events": Number, "sleep_latency_seconds": Number, "wake_up_latency_seconds": Number }, "hypnogram_samples": Array, "other": { "duration_in_bed_seconds": Number, "duration_unmeasurable_sleep_seconds": Number }, "sleep_efficiency": Number }, "temperature_data": { "delta": Number } } Copy { "steps": Array, "metadata": { "id": String, "estimated_if": Number, "provider": String, "estimated_distance_meters": Number, "estimated_elevation_gain_meters": Number, "estimated_energy_kj": Number, "estimated_speed_meters_per_second": Number, "planned_date": ISO-Date-String, "created_date": ISO-Date-String, "estimated_tss": Number, "type": WorkoutTypeNumber, "name": String, "description": String, "pool_length_meters": Number, "estimated_calories": Number, "estimated_duration_seconds": Number } } Copy { "description": String, "order": Number, "intensity": Number, "durations": Array "type": 0, "targets": Array, "stroke_type": StrokeType, //for Swimming Workouts "equipement_type": EquipementType, //for Swimming Workouts "exercice_category" : ExerciseType, //for Strength and Cardio workouts "exercice_name": String, //for Strength and Cardio workouts "weight_kg": Number, //for Strength workouts } Copy { "description": String, "order": Number, "intensity": Number, "durations": Array "type": 1, "targets": Array, "steps" : Array } sun-brightdesktopmoon --- # Understanding sources and destinations | Terra Docs To integrate with Terra, you must define **Data Sources** where user data originates (e.g. Fitbit, Garmin, etc.) and **Data Destinations** where Terra sends this data (e.g. Webhook, MongoDB, etc.) Once that is done, Terra’s Health & Fitness API pushes all user health payloads via **events** directly to your **data** **destination** (e.g. webhook). This removes the need to request data via the API. [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-sources-and-destinations#data-sources) Data sources -------------------------------------------------------------------------------------------------------------------------------------------------- Data Sources are the external health and fitness platforms your users authorize to share data with Terra. These include wearables (e.g., Fitbit, Garmin, Oura), fitness applications, and medical devices. Terra standardises data from these diverse sources into a uniform format. Refer to [**Setting up data sources**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-sources) for setup instructions. [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-sources-and-destinations#data-destinations) Data Destinations ------------------------------------------------------------------------------------------------------------------------------------------------------------ Data Destinations specify where Terra should deliver processed user data. Supported destinations include Webhooks, SQL databases (PostgreSQL, MySQL), cloud storage (AWS S3, GCP GCS, Azure Blob), and message queuing services (AWS SQS, Kafka). Refer to [**Setting up data destinations**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations) for setup instructions. [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-sources-and-destinations#automatic-data-delivery) Automatic data delivery ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Terra's Health & Fitness API operates on an event-driven model. Once Data Sources are enabled, a Data Destination is configured, and a user successfully authenticates: 1. New data becomes available from the user's connected Data Source. 2. Terra retrieves and processes this data, creating a standardised event payload. 3. This payload is **automatically pushed** to your configured Data Destination. This automatic push mechanism means you receive new data as it becomes available, without needing to poll the API. For example, if using a Webhook destination, Terra will send an HTTP POST request to your server with the new data payload. [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-sources-and-destinations#summary-of-steps) Summary of steps ---------------------------------------------------------------------------------------------------------------------------------------------------------- The typical process for setting up your integrations involves: 1. Add data [**sources**](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#source-provider-integration) with one click (e.g. Fitbit, Oura, Garmin) 2. Add a data [**destination**](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#destinations) of choice (e.g. Webhook, MongoDB, PostgreSQL, AWS S3, etc.) spinner [PreviousIntegration setupchevron-left](https://docs.tryterra.co/health-and-fitness-api/integration-setup) [NextSetting up data sourceschevron-right](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-sources) Last updated 8 months ago Was this helpful? * [Data sources](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-sources-and-destinations#data-sources) * [Data Destinations](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-sources-and-destinations#data-destinations) * [Automatic data delivery](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-sources-and-destinations#automatic-data-delivery) * [Summary of steps](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-sources-and-destinations#summary-of-steps) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Overview | Terra Docs circle-info The Terra Streaming API enables real-time data streaming to metrics such as * Steps * Heart Rate * Distance covered * etc... on a ~per second basis. For longer span data, such as **workouts, sleep, daily totals & more**, please refer to the [Wearable API](https://docs.tryterra.co/health-and-fitness-api/getting-started) The **Streaming API** gives access to all wearables that broadcast data through BLE, ANT+, or certain custom bluetooth protocols as well as phone sensors * Heart rate straps (Polar H10, Garmin HRM Pro, Wahoo TICKR FIT...) * Certain smartwatches (Apple Watch, [Garmin Fenix 6 & uparrow-up-right](https://support.garmin.com/en-US/?faq=Zj1947s6pqAHzBCAhLhrC9) , Xiaomi Mi Band 5 & 6...) * etc.. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Ffiles.readme.io%2F51e8eaf-image.png&width=768&dpr=3&quality=100&sign=ca0e3b6a&sv=2) Data flow diagram for data streaming * * * [hashtag](https://docs.tryterra.co/streaming-api/getting-started#how-it-works) How It Works ------------------------------------------------------------------------------------------------ 4 components need to all be working together for the streaming API to deliver data to you 1. **Wearable Device** 2. **Producer (your mobile app, running the Terra RT SDK)** 3. **Terra WebSocket Broker (Terra's server)** 4. **Consumer (your server backend)** Here's a simplified overview of the process: 1. **Device Connection**: The user connects their wearable device to your mobile app via Bluetooth Low Energy or ANT+, using one of Terra's real-time streaming SDKs. 2. **Producer Setup**: Your mobile app establishes a Terra Streaming Producer connection with the Terra WebSocket Service, utilizing the real-time streaming SDK. 3. **Consumer Setup**: To access the data stream on your server backend, you create a Terra Streaming Consumer connection with the Terra WebSocket Service. Once connected, the wearable data will begin streaming to your server in real time. * * * [hashtag](https://docs.tryterra.co/streaming-api/getting-started#next-steps) Next steps -------------------------------------------------------------------------------------------- [PreviousHealth Rewardschevron-left](https://docs.tryterra.co/health-rewards) [NextWearable -> Your appchevron-right](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk) Last updated 5 days ago Was this helpful? * [How It Works](https://docs.tryterra.co/streaming-api/getting-started#how-it-works) * [Next steps](https://docs.tryterra.co/streaming-api/getting-started#next-steps) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Health Rewards | Terra Docs [hashtag](https://docs.tryterra.co/health-rewards#health-rewards) Health Rewards ------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/health-rewards#overview) Overview The **Terra Health Rewards** product lets you turn the raw activity, sleep and physiological data you already receive through the Terra API into **actionable, gamified points** that drive user engagement. * **Science‑based & adaptive** – Points are calculated from evidence‑backed metrics (sleep duration, HRV, steps, floors climbed and more) and automatically adjust to each individual’s baseline. * **Real‑time** – Rewards are generated on demand * **Configurable** – Limits, category weights and streak bonuses can be tweaked in **Dashboard → Health Rewards** (see screenshots below). * **Monetisable** – Combine earned points with in‑app currency, coupons or badge systems to incentivise healthier habits. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FgFFeVRtmruj80LrAiBOj%252Fimage.png%3Falt%3Dmedia%26token%3D5151fcc2-2556-421c-8757-a64bdc8f3cb7&width=768&dpr=3&quality=100&sign=f4645377&sv=2) * * * ### [hashtag](https://docs.tryterra.co/health-rewards#how-it-works) How It Works 1. **Enable Rewards** _Open the dashboard, navigate to_ _**Health Rewards**_ _and toggle the product to “Enabled”._ Here you can: * assign **daily point caps** (overall or per category), * choose **weights** for each goal (e.g. “Hours Slept = 3 pts”, “Steps = 1 pt”), * add **streak bonuses** (e.g. “≥10 pts 2 days in a row → +1 pt”). All changes apply instantly to new calculations. 2. **Request points** Call the Rewards endpoints (see below) providing the _user\_id_ and a _start\_date_ (and optionally _end\_date_). Terra fetches the necessary `daily`, `sleep`, `activity`, data, runs the algorithm in real time, then returns a **total** plus a **human‑readable breakdown** for every day. * * * ### [hashtag](https://docs.tryterra.co/health-rewards#endpoints) Endpoints > Base URL `https://api.tryterra.co/v2` All calls require the standard `dev-id` & `x-api-key` headers. Method Path Purpose `GET` `/rewards/points` Calculate points for a period `POST` `/rewards/points/spent` Deduct points (e.g. when a user redeems a voucher) `GET` `/rewards/points/spent/history` Retrieve a chronological list of redeemed points #### [hashtag](https://docs.tryterra.co/health-rewards#id-1-get-points) 1 Get points **Query parameters** Name Type Required Description `user_id` string ✓ Terra user identifier `start_date` `YYYY‑MM‑DD` ✓ First date (inclusive) `end_date` `YYYY‑MM‑DD` Last date (exclusive). Defaults to start\_date + 1. chevron-right**Successful response (200)**[hashtag](https://docs.tryterra.co/health-rewards#successful-response-200) Key fields: Field Description `total` All‑time points earned (including streak bonuses, minus redemptions). `daily[*].raw_total` Points _before_ streak bonuses that day. `daily[*].breakdown` Per‑category goals (activity, sleep, movement, health\_data) with **goal**, **achieved**, **points** and **max**. `daily[*].streak_total` Points awarded from streak goals for that day. #### [hashtag](https://docs.tryterra.co/health-rewards#id-2-spend-points) 2 Spend points _Deducts 50 points from the user’s balance. A 400 error is returned if the user has insufficient points._ #### [hashtag](https://docs.tryterra.co/health-rewards#id-3-redemption-history) 3 Redemption history Returns an ordered array `[ [points, timestamp] ]`. * * * ### [hashtag](https://docs.tryterra.co/health-rewards#response-object-anatomy) Response Object Anatomy Below is a trimmed version of the example response highlighting the structure you will typically work with: > **Tip – Parsing points quickly** If you only need the numeric score, read `daily[*].raw_total + daily[*].streak_total`. If you want to visualise goals, iterate over `breakdown` and use the `goal` / `achieved` strings to populate the UI. * * * ### [hashtag](https://docs.tryterra.co/health-rewards#dashboard-configuration) Dashboard Configuration The Health Rewards UI (see screenshots) is laid out by **category**: Category Example Goals **Activity** Minutes of moderate / vigorous activity **Movement** Steps & floors climbed **Sleep** Hours in bed, bedtime consistency, efficiency, quality **Health Data** HRV, resting heart‑rate consistency & improvement Use **Limits & Streaks** to: * Set an **overall cap** (e.g., 30 pts / day) * Add **global streaks** (e.g., ≥20 pts for 5 days → +3 pts) * Define **per‑category streaks** (e.g., Movement ≥5 pts for 3 days → +1 pt) All configuration is stored in Terra and read by the API at calculation time. * * * ### [hashtag](https://docs.tryterra.co/health-rewards#example-use-case-weekly-wellness-challenge) Example Use Case – “Weekly Wellness Challenge” 1. **Configure Goals** * Dashboard → Health Rewards * Overall daily limit = 30 pts * Activity proportional = max 5, target = 5, extra = 2 * Movement steps = 1, proportional = 2 * Sleep hours/efficiency/quality = 2 each * Add streak: ≥20 pts for 7 days → +5 bonus 2. **Frontend Implementation** * Show a progress bar that calls **GET /rewards/points** every morning for yesterday’s date. * Display breakdown tool‑tips using the `goal` and `achieved` strings. 3. **Redemption Flow** * When a user taps “Redeem 100 pts for free shipping”, call **POST /rewards/points/spent**. * Show the new balance (`total` field) returned in the 200 response. 4. **Leaderboard** * Aggregate `raw_total + streak_total` per user over the week to show top performers. * * * ### [hashtag](https://docs.tryterra.co/health-rewards#best-practices) Best Practices * **Sync ahead of time** – Make sure wearable data is pulled **before** you calculate rewards for a day. * **Store on server‑side** – Use `store=true` (default) so that the canonical balance lives with Terra and cannot be tampered with client‑side. * **Handle nulls gracefully** – If a metric is missing (e.g., HRV), its goal will remain but `points` might be `0`. * **Rate limits** – Reward endpoints share the same rate limits as other `v2` calls (60 req/min default). Aggregate user calls where possible. * * * ### [hashtag](https://docs.tryterra.co/health-rewards#faq) FAQ Question Answer **Can I backfill rewards?** Yes. Provide a historical `start_date`/`end_date`; Terra will fetch past data and compute points retro‑actively. **What time zone are dates evaluated in?** All dates are interpreted in **local time**. **Can I override an individual user’s goal?** Not yet. Goals are global per developer account. **Why are my users getting 0 points?** Check that the necessary data (sleep, daily summary) exists and that rewards are enabled for your dev ID. * * * Need help? Reach out via a dashboard support ticket. [PreviousHealth Scoreschevron-left](https://docs.tryterra.co/user-engagement/health-scores) [NextOverviewchevron-right](https://docs.tryterra.co/streaming-api/getting-started) Last updated 26 days ago Was this helpful? * [Health Rewards](https://docs.tryterra.co/health-rewards#health-rewards) * [Overview](https://docs.tryterra.co/health-rewards#overview) * [How It Works](https://docs.tryterra.co/health-rewards#how-it-works) * [Endpoints](https://docs.tryterra.co/health-rewards#endpoints) * [Response Object Anatomy](https://docs.tryterra.co/health-rewards#response-object-anatomy) * [Dashboard Configuration](https://docs.tryterra.co/health-rewards#dashboard-configuration) * [Example Use Case – “Weekly Wellness Challenge”](https://docs.tryterra.co/health-rewards#example-use-case-weekly-wellness-challenge) * [Best Practices](https://docs.tryterra.co/health-rewards#best-practices) * [FAQ](https://docs.tryterra.co/health-rewards#faq) Was this helpful? sun-brightdesktopmoon Copy GET /rewards/points?user_id=USER123&start_date=2024‑08‑01&end_date=2024‑08‑07&store=true dev-id: YOUR_DEV_ID Copy { "status": "success", "total": 147, "daily": [\ {\ "date": "2024-08-06",\ "raw_total": 12,\ "breakdown": {\ "sleep": {\ "streaks": [\ {\ "achieved": true,\ "goal": "Achieve 3 sleep points or more for at least 2 consecutive days",\ "points": 1,\ "max": 1\ }\ ],\ "raw_total": 4,\ "hours": {\ "achieved": 8,\ "goal": "Achieve 7.0-9.0 hours in bed",\ "points": 3,\ "max": 3\ },\ "bedtime": {\ "achieved": "11:00 PM",\ "goal": "Go to bed between 10:10 PM and 11:10 PM",\ "points": 2,\ "max": 2\ },\ "efficiency": {\ "achieved": 95,\ "goal": "Achieve a sleep efficiency of 88% or higher",\ "points": 2,\ "max": 2\ },\ "quality": {\ "achieved": 69,\ "goal": "Achieve a sleep quality of 77% or higher",\ "points": 0,\ "max": 2\ },\ "max": 4\ },\ "movement": {\ "floors": {\ "achieved": 0,\ "goal": "Achieve 3 floors climbed",\ "points": 0,\ "max": 1\ },\ "steps_proportional": {\ "achieved": 7266,\ "goal": "Achieve up to 10000 steps",\ "points": 1,\ "max": 2\ },\ "streaks": [\ {\ "achieved": false,\ "goal": "Achieve 2 movement points or more for at least 2 consecutive days",\ "points": 0,\ "max": 1\ }\ ],\ "raw_total": 1,\ "steps": {\ "achieved": 7266,\ "goal": "Achieve 10000 steps",\ "points": 0,\ "max": 1\ },\ "floors_proportional": {\ "achieved": 0,\ "goal": "Achieve up to 3 floors climbed",\ "points": 0,\ "max": 1\ },\ "max": 2\ },\ "streaks": [\ {\ "achieved": true,\ "goal": "Achieve 10 points or more for at least 2 consecutive days",\ "points": 1,\ "max": 1\ }\ ],\ "health_data": {\ "resting_heart_rate": {\ "consistency": {\ "achieved": 74,\ "goal": "Achieve a resting heart rate of 81 or lower",\ "points": 1,\ "max": 1\ },\ "improvement": {\ "achieved": 74,\ "goal": "Achieve a resting heart rate of 66 or lower",\ "points": 0,\ "max": 1\ }\ },\ "streaks": [\ {\ "achieved": true,\ "goal": "Achieve 1 health data points or more for at least 2 consecutive days",\ "points": 1,\ "max": 1\ }\ ],\ "raw_total": 1,\ "max": 1,\ "hrv": {\ "consistency": {\ "achieved": 22,\ "goal": "Achieve an HRV of 23 or higher",\ "points": 0,\ "max": 1\ },\ "improvement": {\ "achieved": 22,\ "goal": "Achieve an HRV of 28 or higher",\ "points": 0,\ "max": 1\ }\ }\ },\ "activity": {\ "streaks": [\ {\ "achieved": true,\ "goal": "Achieve 3 activity points or more for at least 2 consecutive days",\ "points": 1,\ "max": 1\ }\ ],\ "raw_total": 8,\ "target": {\ "achieved": {\ "moderate": 22,\ "vigorous": 44\ },\ "goal": "Achieve 30 minutes of moderate or 15 minutes of vigorous activity",\ "points": 5,\ "max": 5\ },\ "max": 8,\ "extra": {\ "achieved": {\ "moderate": 22,\ "vigorous": 44\ },\ "goal": "Achieve up to 15 extra minutes of moderate or 8 extra minutes of vigorous activity",\ "points": 2,\ "max": 2\ },\ "proportional": {\ "achieved": {\ "moderate": 22,\ "vigorous": 44\ },\ "goal": "Achieve up to 30 minutes of moderate or 15 minutes of vigorous activity",\ "points": 5,\ "max": 5\ }\ }\ },\ "streak_total": 4,\ "max": 12\ }\ ] } Copy POST /rewards/points/spent?user_id=USER123 dev-id: YOUR_DEV_ID Content-Type: application/json { "points": 50 } Copy GET /rewards/points/spent/history?user_id=USER123&start_date=2024‑01‑01&end_date=2024‑12‑31 dev-id: YOUR_DEV_ID Copy { "daily": [\ {\ "date": "2024‑08‑06",\ "breakdown": {\ "activity": {\ "proportional": { "goal": "Up to 30 mins", "achieved": {...}, "points": 5, "max": 5 },\ "target": { "goal": "30 mins", "points": 5 },\ "extra": { "goal": "Extra 15 mins", "points": 2 },\ "streaks": [ { "goal": "≥3 activity pts for 2 days", "points": 1 } ],\ "raw_total": 8,\ "max": 8\ },\ "sleep": { … },\ "movement":{ … },\ "health_data": { … }\ },\ "raw_total": 12,\ "streak_total": 4,\ "max": 12\ }\ ], "total": 147 } sun-brightdesktopmoon --- # Your app -> Terra | Terra Docs Configure your mobile application (the "Producer") to forward the real-time data received from the wearable to Terra's WebSocket Broker using our RT SDKs. * [**iOS (Swift)**](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/ios-swift) * [**Android**](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/android) [PreviousAndroidchevron-left](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android) [NextiOS (Swift)chevron-right](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/ios-swift) Last updated 8 months ago Was this helpful? Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Health Scores | Terra Docs [hashtag](https://docs.tryterra.co/user-engagement/health-scores#overview) Overview ---------------------------------------------------------------------------------------- The **Terra Health Scores** product provides four proprietary, science-backed scores designed to give your users a deeper understanding of their health: * **Immunity Index** * **Respiratory Health** * **Sleep Score** * **Training Stress** * **Strain Score** Each score is powered by Terra’s propriety models and interprets complex physiological data into a science-backed health score. The scores are: * **Device agnostic:** They work across all supported wearable sources as long as basic metrics such as HRV, sleep, respiratory rate amongst others are collected. * **Turnkey:** No additional backend setup is needed. * **Continuously generated:** Once a user is connected, scores appear automatically in the `daily summary` or `sleep` payloads. * * * [hashtag](https://docs.tryterra.co/user-engagement/health-scores#how-it-works) How It Works ------------------------------------------------------------------------------------------------ As soon as your users connect their wearables and data begins syncing, Terra will enrich your payloads with the following scores under the data field `data enrichment` : Score Type Payload Location Frequency Source Data Needed 🛡️ **Immunity Index** Daily Summary With every new daily payload HRV, respiratory rate, body temperature 🫁 **Respiratory Health** Daily Summary With every new daily payload Oxygen saturation, respiratory rate, training 🏋️‍♀️ **Training Stress** Daily Summary With every new daily payload Deep sleep, light sleep, REM, total sleep, body temperature, HRV, RHR, Oxygen Saturation 💤 **Sleep Score** Sleep Payload With every new sleep payload Sleep stages, HR, HRV 💪🏻 **Strain Score** Daily Summary With every new daily payload HRV, RHR > **Note**: Terra scores appear under the `data_enrichment` field inside the relevant payloads. RHR, HRV and body temperature metrics are provided by most wearables if worn over night during sleep. * * * [hashtag](https://docs.tryterra.co/user-engagement/health-scores#how-to-enable-health-scores) How to Enable Health Scores ------------------------------------------------------------------------------------------------------------------------------ Sleep score must be toggled on manually in the dashboard: 1. Log into your Terra Dashboard 2. Go to the **Health Scores** tab 3. Toggle **Health Scores** to “Enabled” 4. Save settings Sleep scores will now appear in the `sleep` payload for users with eligible data. * * * [hashtag](https://docs.tryterra.co/user-engagement/health-scores#how-to-receive-health-scores) How to Receive Health Scores -------------------------------------------------------------------------------------------------------------------------------- You do **not** need to implement separate API calls, database logic, or webhook triggers to receive health scores. To receive Terra’s Sleep Score, the following conditions must be met: 1. **Active connection:** Your users have authorized their wearable (via Terra API). See Connect a User for specifics. 2. **Wearables sync necessary metrics:** The necessary metrics (e.g., HRV, respiratory rate, sleep) are available, see **Score Eligibility Criteria.** 3. **The user wears the device (over night):** Metrics like HRV, resting HR, sleep etc. are subject to the user wearing the wearable during sleep. 4. **Baseline values are available:** The user has to wear their device for at least 4 days initially for our propriety score to calibrate and generate a baseline value. 5. **Sufficient data is available:** After the baseline for the user is established, the user has to wear their device at least once in the last 2 weeks. If users are disconnected, you will not receive new data or scores. * * * [hashtag](https://docs.tryterra.co/user-engagement/health-scores#score-eligibility-criteria) Score Eligibility Criteria ---------------------------------------------------------------------------------------------------------------------------- Terra’s health scores are automatically calculated only if sufficient data is available. The following input signals are required to ensure each score is accurate and meaningful. If any of the **must-have metrics** are missing for a user on a given day, that score will not be generated or may return as `null`. ### [hashtag](https://docs.tryterra.co/user-engagement/health-scores#requirements-per-score) Requirements Per Score #### [hashtag](https://docs.tryterra.co/user-engagement/health-scores#sleep-score) **💤 Sleep Score** Requirement Details **Any sleep metric** REM, deep sleep, light sleep, total duration **Optional** HRV, resting heart rate, SpO₂, body temperature enhance score precision > At minimum, a valid sleep session with at least one stage or duration is required. #### [hashtag](https://docs.tryterra.co/user-engagement/health-scores#respiratory-health) **🫁 Respiratory Health** Requirement Details **SpO₂ and respiratory rate** Blood oxygen saturation and respiratory rate measured in breaths per minute **Optional** Training activity to adjust score sensitivity post exercise > If SpO₂ or respiratory rate are missing, the respiratory health score will be null. #### [hashtag](https://docs.tryterra.co/user-engagement/health-scores#training-stress) **🏋️‍♂️ Training Stress** Requirement Details **HRV and sleep** Required daily HRV (e.g., RMSSD or SDNN) and sleep metrics Optional Steps, HR, training activities help refine intensity detection and training load calibration. > If sleep data or HRV is missing, the strain score will be null. #### [hashtag](https://docs.tryterra.co/user-engagement/health-scores#immunity-index) **🛡️ Immunity Index** Requirement Details **HRV and respiratory rate** Required daily HRV (e.g., RMSSD or SDNN) and respiratory rate. **Optional** Body temperature enhances score precision > If HRV or respiratory rate data is missing, the immunity index will be null. #### [hashtag](https://docs.tryterra.co/user-engagement/health-scores#strain-score) 💪🏻 **Strain Score** Requirement Details **HRV and RHR** Required daily HRV (e.g., RMSSD or SDNN) and RHR > If HRV or RHR data is missing, the strain score will be null. * * * [hashtag](https://docs.tryterra.co/user-engagement/health-scores#understanding-health-score-outputs) Understanding Health Score Outputs -------------------------------------------------------------------------------------------------------------------------------------------- Each health score is generated using multiple physiological signals (e.g., HRV, sleep stages, respiration), which are transformed and combined using Terra’s proprietary models. ### [hashtag](https://docs.tryterra.co/user-engagement/health-scores#score-ranges) 🔢 Score Ranges Score Range Interpretation Sleep Score 0–100 Higher = better sleep quality Training Stress 0–100 Higher = higher signs of stress Respiratory Health 0–100 Higher = better respiratory health Immunity Index 0–5 Higher = weakened immunity Strain Score \-1–1 Higher = more recovery, lower = higher physiological strain ### [hashtag](https://docs.tryterra.co/user-engagement/health-scores#how-to-read-contributor-values) How to Read Contributor Values Each score has contributors, the underlying physiological metrics that influenced the score. These **do not reflect raw sensor values** (like BPM or °C). Instead, each contributor is: * Normalized and scaled based on its contribution to the final score * Weighted according to the model's proprietary algorithm, and adaptive to each individual’s baseline * Transformed for interpretability and sensitivity This allows a uniform scoring system across diverse devices and users. #### [hashtag](https://docs.tryterra.co/user-engagement/health-scores#sleep-score-example) Sleep Score Example **Explanation:** * `sleep_score`: Final normalized score (0–100) * `sleep_contributors`: Each value is a transformed signal indicating how much that metric supports healthy sleep. 100 = strong positive influence. > Note: If a contributor is null, the data was missing or not provided by the device. #### [hashtag](https://docs.tryterra.co/user-engagement/health-scores#immunity-index-example) Immunity Index Example **Explanation:** * `immune_index`: Value from **0 to 5** * `0` = No sign of immune system weakening * `5` = Strong signal of weakened immunity * Contributor values like `hrv: 200` are **not raw HRV values**, but transformed indicators used by Terra’s model. > A higher immune index means there are stronger biomarkers of physiological strain that may reflect a stressed or weakened immune system. #### [hashtag](https://docs.tryterra.co/user-engagement/health-scores#strain-score-example) Strain Score Example **Explanation:** * `strain_index`: Value from -**1 to 1** * `+1` = Strong signs of recovery and parasympathetic dominance * `0` = Stable, baseline physiological state * `-1` = Strong signs of physiological strain and sympathetic activation * `momentum`**:** 7-day trend of HRV vs HR * `z_slow`**:** Deviation from 28-day baseline * `zcv`**:** Stability or instability of HRV variability * `acute`**:** Short-term (24h) HRV change > A higher strain\_index indicates recovery and reduced stress load, while a lower (negative) strain\_index indicates accumulating physiological strain. > > The strain\_traffic\_light tag (“GREEN”, “AMBER”, “RED”) provides an easy-to-interpret summary based on these values. * * * [hashtag](https://docs.tryterra.co/user-engagement/health-scores#provider-vs-terra-scores) Provider vs Terra Scores ------------------------------------------------------------------------------------------------------------------------ Several wearables (e.g., Oura, Fitbit) offer their own native scores. To avoid confusion: * **Terra Scores** live under `data_enrichment` in the payload. * **Provider Scores** (like "Stress" or "Sleep" scores) appear under the `scores` section but are **not generated by Terra**. Location Score Source `data_enrichment` Terra `scores` Native device/app * * * [hashtag](https://docs.tryterra.co/user-engagement/health-scores#adjusting-the-model) Adjusting the Model -------------------------------------------------------------------------------------------------------------- Each health score is powered by a proprietary Terra model. However, if you’d like to customize the weight or logic behind specific score components: * Visit the **Terra Dashboard** * Navigate to the **Health Scores section** * Modify parameters such as HRV sensitivity, activity thresholds, or sleep weightings These changes apply **in real time** and update future score outputs. * * * [hashtag](https://docs.tryterra.co/user-engagement/health-scores#questions) Questions? ------------------------------------------------------------------------------------------- If you’re unsure whether your data includes scores or if you’re not seeing expected results, check: * The `data_enrichment` object in your latest payload - daily or sleep payload * That the user’s wearable is actively syncing data * That the user has at least 4 days of relevant baseline data * That the user has worn the wearable to sleep * Your user has had generated the necessary underlying metrics in the past 2 weeks [PreviousPricingchevron-left](https://docs.tryterra.co/health-and-fitness-api/pricing) [NextHealth Rewardschevron-right](https://docs.tryterra.co/health-rewards) Last updated 2 months ago Was this helpful? * [Overview](https://docs.tryterra.co/user-engagement/health-scores#overview) * [How It Works](https://docs.tryterra.co/user-engagement/health-scores#how-it-works) * [How to Enable Health Scores](https://docs.tryterra.co/user-engagement/health-scores#how-to-enable-health-scores) * [How to Receive Health Scores](https://docs.tryterra.co/user-engagement/health-scores#how-to-receive-health-scores) * [Score Eligibility Criteria](https://docs.tryterra.co/user-engagement/health-scores#score-eligibility-criteria) * [Requirements Per Score](https://docs.tryterra.co/user-engagement/health-scores#requirements-per-score) * [Understanding Health Score Outputs](https://docs.tryterra.co/user-engagement/health-scores#understanding-health-score-outputs) * [🔢 Score Ranges](https://docs.tryterra.co/user-engagement/health-scores#score-ranges) * [How to Read Contributor Values](https://docs.tryterra.co/user-engagement/health-scores#how-to-read-contributor-values) * [Provider vs Terra Scores](https://docs.tryterra.co/user-engagement/health-scores#provider-vs-terra-scores) * [Adjusting the Model](https://docs.tryterra.co/user-engagement/health-scores#adjusting-the-model) * [Questions?](https://docs.tryterra.co/user-engagement/health-scores#questions) Was this helpful? sun-brightdesktopmoon Copy "data_enrichment": { "sleep_contributors": { "rem": 40.34, "light": 100, "deep": 44.77, "total": 96.17, "rhr": 100, "hrv": 100, "temp": 100, "oxy": null}, "sleep_score": 79.13 } Copy "data_enrichment": { "start_time": "2025-05-20T00:00:00.000000+01:00", "immune_contributors": { "hrv": 200, "respiration": 0, "temp": 0 }, "immune_index": 0.67 } Copy "data_enrichment": { "start_time": "2025-05-20T00:00:00.000000+01:00", "strain_contributors": { "acute": 0.5, "momentum": -0.2, "z_slow": 1.3, "zcv": -0.8 }, "strain_index": 0.35, "strain_traffic_light": "GREEN" } sun-brightdesktopmoon --- # Understanding Terra environments | Terra Docs You have access to three environments: * **Testing**: you'll have access to 50 [usersarrow-up-right](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) * **Staging**: you'll have access to 50 [usersarrow-up-right](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) * **Production**: unlimited You can configure each environment separately on your [Terra Dashboard.arrow-up-right](https://dashboard.tryterra.co/) circle-info #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-terra-environments#user-limits) User limits Note that for testing & staging, there is a user limit of 50 users on each environment. These are additional test users provided by Terra that are part of any plan! If you reach the user limit, you should deregister the testing accounts you no longer need using the [REST API Endpoints](https://docs.tryterra.co/reference#auth-deauthenticateuser) endpoint. circle-info [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-terra-environments#rate-limits) Rate limits ------------------------------------------------------------------------------------------------------------------------------------------ Terra _**does not impose any rate limits**_ on the REST API. Note that API requests are generally not necessary unless backfilling historical data [PreviousDedicated data source API keyschevron-left](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys) [NextUser authenticationchevron-right](https://docs.tryterra.co/health-and-fitness-api/user-authentication) Last updated 8 months ago Was this helpful? Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Authentication flow | Terra Docs [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/authentication-flow#overview) Overview ------------------------------------------------------------------------------------------------------------------------- Authenticating a user via Terra is the **first** and **most** **essential** **step** to begin receiving their health and fitness data from their wearable or fitness platform. A **user authentication** is the process of allowing your end-user to connect their health data (e.g., Fitbit, Garmin, Oura) to you via Terra API. Once authenticated, Terra will start automatically pushing health data **events** from that user's account to your chosen data destination, with no polling or manual requests required. circle-check [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/authentication-flow#prerequisites) **Prerequisites** --------------------------------------------------------------------------------------------------------------------------------------- To connect a [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) , you need to have completed the following steps: 1. [**API Key & dev-id:**arrow-up-right](https://dashboard.tryterra.co/) Obtain your **API** **Key** and **dev-id** from your Terra Dashboard 2. [**Destination Configured:**](https://docs.tryterra.co/health-and-fitness-api/integration-setup#set-up-your-data-sources-and-destinations) Set up a Data Destination where Terra will send **events** and **data** **updates**. 3. [**Data Sources Activated**:](https://docs.tryterra.co/health-and-fitness-api/integration-setup#set-up-your-data-sources-and-destinations) Enable the data **sources** (e.g. oura). * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/authentication-flow#the-authentication-flow) The Authentication Flow ------------------------------------------------------------------------------------------------------------------------------------------------------- The ideal authentication flow for your end-users: * User clicks "Connect Device" in your mobile app or web app. * Your frontend requests your backend for a widget URL. * Your backend generates a widget URL by calling the `/auth/generateWidgetSession` endpoint. * Redirect the user to the widget URL in your frontend (or open in-app browser for mobile apps). * User authenticates their data source. * Widget redirects to your success/failure URL with the `user_id` and `reference_id`. The health and fitness data of your end-users will be sent to your destination automatically thereafter! You **don't** **need** to manage **auth** **tokens** or **refresh** **tokens**; we manage this on our end on your behalf. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/authentication-flow#test-the-authentication) Test the Authentication ------------------------------------------------------------------------------------------------------------------------------------------------------- For internal demonstration purposes, if this is your first time authenticating a [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) , you may connect your own data source using the [Terra Dashboardarrow-up-right](https://dashboard.tryterra.co/) as below. Your end-users won't use this pathway to connect their wearables; to connect live users you need to use the API. However, this will help you understand the auth flow without making any API calls yourself! spinner [PreviousUser authenticationchevron-left](https://docs.tryterra.co/health-and-fitness-api/user-authentication) [NextImplementation (Terra widget)chevron-right](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-terra-widget) Last updated 8 months ago Was this helpful? * [Overview](https://docs.tryterra.co/health-and-fitness-api/user-authentication/authentication-flow#overview) * [The Authentication Flow](https://docs.tryterra.co/health-and-fitness-api/user-authentication/authentication-flow#the-authentication-flow) * [Test the Authentication](https://docs.tryterra.co/health-and-fitness-api/user-authentication/authentication-flow#test-the-authentication) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Customising authentication redirects | Terra Docs [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/customising-authentication-redirects#overview) Overview ------------------------------------------------------------------------------------------------------------------------------------------ After the end-user completes the authentication flow, they will be redirected to a **default** **final** **url** that's either a **success** or **failure** **screen** before they go back to your app. These urls can be customized when you're calling one of the `/auth` endpoints. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/customising-authentication-redirects#authentication-flow-final-url) Authentication Flow Final URL ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ When the user authenticates a health account (e.g. Oura), before they go back to your app, they see a final URL (screen) of the authentication flow is either a success or failure screen. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252F7PxwtMisS2aHpOWMy1YE%252FCapture%2520d%25E2%2580%2599e%25CC%2581cran%25202025-03-28%2520a%25CC%2580%252021.17.40.png%3Falt%3Dmedia%26token%3D49efdbb8-3e40-42dd-b8aa-81a65162aeea&width=768&dpr=3&quality=100&sign=e356fd3b&sv=2) Default **Success** Redirect URL ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FpkmkdnwCVib23TkG4obF%252FCapture%2520d%25E2%2580%2599e%25CC%2581cran%25202025-03-28%2520a%25CC%2580%252021.13.32.png%3Falt%3Dmedia%26token%3Db7609718-69d7-43ee-b97c-c59340f225a2&width=768&dpr=3&quality=100&sign=e12a1f8&sv=2) Default **Failure** Redirect URL The final url will append the following parameters: * `user_id` (not Null) * `resource` (not Null) * `reference_id` (can be Null - if you did not pass it in the auth endpoint). * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/customising-authentication-redirects#how-to-customize-the-redirect-urls) **How to Customize the Redirect URLs?** --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Terra provides these urls by default, and they can also be customized in the `/auth` endpoints. They can be specified in the **body** of the authentication request as: * `auth_success_redirect_url` * `auth_failure_redirect_url` * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/customising-authentication-redirects#different-ways-to-customize-the-auth-result-url) **Different ways to Customize the Auth Result URL** ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- You can redirect to a: * **Web Page:** A specific page on your web application, including any useful query parameters. * Example: `https://somereallycoolcompany.com?terra_auth_success=true` * **Deep Link:** A **deep** **link** into your mobile application. * Example: `reallycoolapp://success` circle-exclamation [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/customising-authentication-redirects#mobile-based-integrations) Mobile-based integrations ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * When using the widget, when the user selects one of the [Mobile SDK-based integrations](https://docs.tryterra.co/health-and-fitness-api/mobile-only-sources) (e.g. Apple Health, Samsung Health, Health Connect), they will by default be redirected to the `auth_success_redirect_url` with a **null** `user_id` . * This Redirect URL can be used to redirect your end-user to your mobile app instead so that they complete the connection flow to the Mobile-only integrations using **Deep Links.** [PreviousHandling authentication eventschevron-left](https://docs.tryterra.co/health-and-fitness-api/user-authentication/handling-authentication-events) [NextManaging user health datachevron-right](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data) Last updated 8 months ago Was this helpful? * [Overview](https://docs.tryterra.co/health-and-fitness-api/user-authentication/customising-authentication-redirects#overview) * [Authentication Flow Final URL](https://docs.tryterra.co/health-and-fitness-api/user-authentication/customising-authentication-redirects#authentication-flow-final-url) * [How to Customize the Redirect URLs?](https://docs.tryterra.co/health-and-fitness-api/user-authentication/customising-authentication-redirects#how-to-customize-the-redirect-urls) * [Different ways to Customize the Auth Result URL](https://docs.tryterra.co/health-and-fitness-api/user-authentication/customising-authentication-redirects#different-ways-to-customize-the-auth-result-url) Was this helpful? sun-brightdesktopmoon Success Auth URL (Example) Copy https://widget.tryterra.co/session/demo/success?user_id=bc205b50-dabe-4680-9d35-38517b915dc1&resource=GOOGLE&reference_id=null sun-brightdesktopmoon --- # Customising data types | Terra Docs [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/customising-data-types#overview) Overview -------------------------------------------------------------------------------------------------------------------------- When a [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) authenticates via Terra, you'll start receiving data like activity, sleep, and daily metrics. You can customize settings to receive only the data you need. You can configure this via [your Terra Dashboardarrow-up-right](https://dashboard.tryterra.co/dashboard) : 1. Across all data sources 2. For selected data sources only * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/customising-data-types#id-1.-across-all-data-sources) **1\.** Across all data sources ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Choose the Data Types you wish to receive to your **Destination**. 1. **🏃🏽‍♀️ Activity** 2. **👷🏼 Daily** 3. **🩺 Body** 4. **💤 Sleep** 5. **🍱 Nutrition** 6. 📆 **Menstruation** Including **Samples** will provide granular data (a list of readings at specific timestamps). ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FxTbuKHrPa6de9Fp1ohf8%252FCapture%2520d%25E2%2580%2599e%25CC%2581cran%25202025-03-28%2520a%25CC%2580%252015.01.44.png%3Falt%3Dmedia%26token%3D10a533d3-484a-465e-8131-05bf0df91c0c&width=768&dpr=3&quality=100&sign=2f7b4f41&sv=2) Without "Samples" ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FVsvnPsbic0xptdKpG4ja%252FCapture%2520d%25E2%2580%2599e%25CC%2581cran%25202025-03-28%2520a%25CC%2580%252014.56.39.png%3Falt%3Dmedia%26token%3Dd75c7d63-e1f0-482d-831e-007424415aba&width=768&dpr=3&quality=100&sign=f943ba20&sv=2) With "Samples" [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/customising-data-types#id-2.-for-selected-data-sources-only) **2\.** For selected data sources only ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Some data sources allow you to restrict the data scopes that you want to request from your end-user. You can configure scopes for each [Data Source](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#source-provider-integration) (integration) as follows: 1. Go to your Terra Dashboard account > Connections 2. Select the Data Source you wish to edit 3. Choose the "Edit" option 4. Click on the "Edit Permissions" tab and choose your scopes. spinner [PreviousQueuing services (SQS, Kafka)chevron-left](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/queuing-services-sqs-kafka) [NextDedicated data source API keyschevron-right](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys) Last updated 8 months ago Was this helpful? * [Overview](https://docs.tryterra.co/health-and-fitness-api/integration-setup/customising-data-types#overview) * [1\. Across all data sources](https://docs.tryterra.co/health-and-fitness-api/integration-setup/customising-data-types#id-1.-across-all-data-sources) * [2\. For selected data sources only](https://docs.tryterra.co/health-and-fitness-api/integration-setup/customising-data-types#id-2.-for-selected-data-sources-only) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Handling authentication events | Terra Docs [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/handling-authentication-events#id-1.-handle-authentication-events) 1\. Handle authentication events -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Terra pushes a [Authentication Events arrow-up-right](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#authentication) to your data destination (e.g. Webhook) any time a user has **connected**, **disconnected**, **failed** to **connect**, **reconnected**, or their **access** **was** **revoked**. These event payloads contain important details such as: `user_id` , auth `status` , and `message`. Here is an example of a successful `auth` event: auth\_success Copy { "type": "auth", "status": "success", "widget_session_id": "a9a0c7a4-c05e-4550-a973-f87a31a7c558", "user": { "scopes": "COURSE_IMPORT,WORKOUT_IMPORT,ACTIVITY_EXPORT,HEALTH_EXPORT", "active": true, "last_webhook_update": null, "created_at": "2024-10-07T03:45:00.000000+00:00", "user_id": "4735eac4-31a2-47ef-8b11-51e98d84c680", "reference_id": "tony_stark", "provider": "GARMIN" }, "reference_id": "tony_stark", "message": "User has successfully authenticated", "version": "2022-03-16" } To correctly parse the payloads, review the full list of event formats under [Reference Page > Event Types > Authenticationarrow-up-right](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#authentication) . You can find **all your received events (payloads)** in: * Your [Terra Dashboard > Payload Historyarrow-up-right](https://dashboard.tryterra.co/dashboard/debug) . * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/handling-authentication-events#id-2.-retrieve-user-id) 2\. Retrieve User ID -------------------------------------------------------------------------------------------------------------------------------------------------------------- Once your end-user has authenticated their data source, you will receive an [Authentication Eventarrow-up-right](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#authentication) . Your goal is to obtain a `user_id` from the [Authentication Eventarrow-up-right](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#authentication) in order to map incoming health data to the correct user in your system. You should save this retrieved `user_id` in your **Database.** Without this step, you won't be able to associate data events (like activity or sleep) with the right user. circle-info The `user_id` will also be in query parameters the final URL of the authentication flow. The final redirection URL will take the form: **\`{auth\_success\_redirect\_url}?user\_id=...&reference\_id=...&resource=...\`** circle-info [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/handling-authentication-events#does-user_id-change-after-a-re-auth) Does `user_id` change after a re-auth? --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Yes. Connecting an account (i.e. [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) ) a second time on the same `dev_id` will delete the previous `user` record for that account, and yield a new `user_id` [PreviousImplementation (Custom UI)chevron-left](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui) [NextCustomising authentication redirectschevron-right](https://docs.tryterra.co/health-and-fitness-api/user-authentication/customising-authentication-redirects) Last updated 8 months ago Was this helpful? * [1\. Handle authentication events](https://docs.tryterra.co/health-and-fitness-api/user-authentication/handling-authentication-events#id-1.-handle-authentication-events) * [2\. Retrieve User ID](https://docs.tryterra.co/health-and-fitness-api/user-authentication/handling-authentication-events#id-2.-retrieve-user-id) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # iOS (Swift) | Terra Docs Once you've started receiving data from a device into your app, you can start sending this data to Terra's websocket server (the broker). This will later allow you to receive it on your backend, and process it as per your requirements. circle-info ### [hashtag](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/ios-swift#prerequisite) Prerequisite Before following the steps below, make sure you've followed the guide to [stream data from a wearable device to your app](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/ios-swift) [hashtag](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/ios-swift#setting-up-a-connection) Setting up a connection -------------------------------------------------------------------------------------------------------------------------------------------- You'll have previously set up a stream between a wearable device and your app [using the startRealTime function](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/ios-swift#streaming-real-time-data) . In order to to send this data back to the broker, you'll simply use a variant of the startRealTime function Copy import TerraRT // Example function to start real-time data streaming, stop it, and disconnect func manageRealtimeData() { let connectionType: TerraRTiOS.Connections = .BLE // Replace with your connection type (e.g., BLE) let dataTypes: Set = [.heartRate, .steps] // Replace with desired data types to stream let token = "yourAuthToken" // Replace with your actual token, fetched from your backend // Start real-time data streaming terraRT.startRealtime(type: connectionType, dataType: dataTypes, token: token, callback: { update in handleUpdate(update: update) }, connectionCallback: { success in if success { print("Real-time connection successfully established") } else { print("Failed to establish real-time connection") } }) // Stop the real-time streaming after some action or condition // Example: stopping after a delay (5 seconds here, for demonstration) DispatchQueue.main.asyncAfter(deadline: .now() + 5) { terraRT.stopRealtime(type: connectionType) print("Real-time streaming stopped.") } // Optionally, disconnect after stopping the real-time data stream DispatchQueue.main.asyncAfter(deadline: .now() + 7) { terraRT.disconnect(type: connectionType) print("Disconnected from connection.") } } // Function to handle updates from the real-time data stream func handleUpdate(update: TerraRTiOS.Update) { // Process the real-time data update here print("Received update at timestamp: \(update.ts)") print("Update type: \(update.type)") if let value = update.val { print("Value: \(value)") } if let dataArray = update.d { print("Array of data values: \(dataArray)") } } // Call the function to start the real-time data management process manageRealtimeData() Simply passing in a token from the following endpoint will allow you to stream the same data you were reading previously within your app, and have it sent to the broker ### [hashtag](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/ios-swift#post-auth-user) Stream - Generate user token post https://ws.tryterra.co/auth/user Endpoint for generation of a token for a user (producer) connection Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Query parameters idstringOptional The ID of the user to generate a token for Header parameters dev-idstringRequired your developer ID x-api-keystringRequired your API key Responses chevron-right 200 Successful response application/json Responseobject Show propertiesplus chevron-right 403 Forbidden text/plain post /auth/user HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Successful response chevron-down [PreviousYour app -> Terrachevron-left](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra) [NextAndroidchevron-right](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/android) Last updated 1 year ago Was this helpful? * [Setting up a connection](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/ios-swift#setting-up-a-connection) * [POSTStream - Generate user token](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/ios-swift#post-auth-user) Was this helpful? sun-brightdesktopmoon Copy POST /auth/user HTTP/1.1 Host: ws.tryterra.co x-api-key: text dev-id: text Accept: */* Copy { "token": "OTYwNWFi5ZWQMTAxMjg0Y2Qw.gzrPzZcS3Gy8QDOxbiPRwu30PTB3VxW0eE" } sun-brightdesktopmoon --- # Setting up data destinations | Terra Docs [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations#overview) Overview -------------------------------------------------------------------------------------------------------------------------------- Terra’s Health & Fitness API is **event-based;** meaning it pushes all user health payloads via **events** directly to your **data** **destination** and removes the need to request data via the API. Therefore, setting up data destinations is a core step in your integration process. Terra API provides many options for **data destinations** such as webhooks, SQL databases, Supabase, and buckets. In this section, you'll learn how to set up your preferred destination in your Terra Dashboard. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations#set-up-data-destination) **Set up Data Destination** ------------------------------------------------------------------------------------------------------------------------------------------------------------------ * Head to [your Terra Dashboard > Connections pagearrow-up-right](https://dashboard.tryterra.co/dashboard/connections) . * Click on "Add New", and select from 10 data destinations: Webhook, Database, Bucket and other. * Add the necessary details and click on "Apply". circle-info **You don't have a data destination yet?** No worries! If you are just starting off building your product and want to test how Terra works, you can use [https://webhook.sitearrow-up-right](https://webhook.site/#!/) to set up a temporary destination for Webhooks. For further information about each destination, please see [Destinations](https://docs.tryterra.co/reference/health-and-fitness-api/destinations) in the Reference page. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations#destination-specific-steps) Destination-specific steps -------------------------------------------------------------------------------------------------------------------------------------------------------------------- Terra API supports various data destinations, some require additional steps to setup correctly. Click each for further information and detailed setup instructions: [**Webhooks**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/webhooks) * The most basic destination. Terra makes a POST request to your specified URL with new data events. [**SQL database (Postgres, MySQL)**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/sql-database-postgres-mysql) * Store structured data directly into your PostgreSQL or MySQL databases. Terra can manage table creation and data insertion, providing download links for full payloads. [**Supabase**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/supabase) * Leverage the combined power of Postgres and S3-compatible storage. Terra integrates seamlessly to manage both your database entries and raw data payloads within Supabase. [**Cloud Storage (AWS S3, GCP GCS, Azure Blob)**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp) * Dump raw data payloads directly into your preferred cloud storage bucket (AWS S3, Google Cloud Storage, or Azure Blob). Suitable for archival, batch processing, or data lake strategies. [**Queuing services (AWS SQS, Kafka)**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/queuing-services-sqs-kafka) * Integrate with managed message queues like AWS SQS or Kafka for resilient, scalable, and asynchronous data ingestion into your existing event-driven architectures. [PreviousSetting up data sourceschevron-left](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-sources) [NextWebhookschevron-right](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/webhooks) Last updated 8 months ago Was this helpful? * [Overview](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations#overview) * [Set up Data Destination](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations#set-up-data-destination) * [Destination-specific steps](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations#destination-specific-steps) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Implementation (Terra widget) | Terra Docs [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-terra-widget#id-1.-make-an-api-request) 1\. Make an API Request ----------------------------------------------------------------------------------------------------------------------------------------------------------------- Make an API Request to the [`/auth/generateWidgetSession`](https://docs.tryterra.co/reference#post-auth-generatewidgetsession) endpoint from your backend. Command Line Copy curl --request POST --url https://api.tryterra.co/v2/auth/generateWidgetSession \ --header 'dev-id: ' \ --header 'x-api-key: \ --header 'Content-Type: application/json' \ --data '{ "language": "en", "reference_id": "my_first_connection", "auth_success_redirect_url": "text", "auth_failure_redirect_url": "text", }' circle-info **Pro** **tip**: Use `reference_id` in your request Body to pass in your own end user's ID on your system. This will simplify reconciling the Terra [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) with your end user. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-terra-widget#id-2.-parse-the-widget-url-from-the-json-response) 2\. Parse the Widget URL from the JSON Response ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The endpoint will generate a **widget url** in the response. Retrieve it by parsing `"url"` . * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-terra-widget#id-3.-open-the-widget-url) 3\. Open The Widget URL ----------------------------------------------------------------------------------------------------------------------------------------------------------------- Pass the retrieved `"url"` to your client side, and open it either in: * an **in-app browser**, if using a mobile app, * or a **new tab,** if using a web app This will take your [end user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#end-user) to the provider selection screen, the Terra authentication widget. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FCZcrIrTlh3Br1VHBtS7s%252Fwidget.png%3Falt%3Dmedia%26token%3D591ee25e-2aa7-47ff-ba68-e88b893db3c9&width=768&dpr=3&quality=100&sign=41cf971b&sv=2) **Device** S**election** screen (Terra authentication widget) ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FTuSK9MXKw4AOlEQWhIWb%252Fscreenshot%2520%282%29.png%3Falt%3Dmedia%26token%3D7ed5038d-471a-4ed7-9818-ea18bb722364&width=768&dpr=3&quality=100&sign=589f4331&sv=2) **Login** Screen (example: Oura) ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252F1lAow8Zfl010xLxwpRUI%252Fscreenshot%2520%283%29.png%3Falt%3Dmedia%26token%3D36da4b9e-bd6d-495f-b0bb-bf70302d8574&width=768&dpr=3&quality=100&sign=cbc9ca60&sv=2) **Permission** screen (example: Oura) circle-info The permissions list can be [customised through your Terra Dashboard](https://docs.tryterra.co/health-and-fitness-api/integration-setup/customising-data-types) You can find a list of all your **authenticated** **users** in: * Your [Terra Dashboard > Usersarrow-up-right](https://dashboard.tryterra.co/dashboard/users) * Or by using [the /subscriptions endpoints](https://docs.tryterra.co/reference) * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-terra-widget#common-mistakes) ❌ Common Mistakes ------------------------------------------------------------------------------------------------------------------------------------------------- triangle-exclamation [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-terra-widget#common-mistakes-and-best-practices) Common Mistakes and Best Practices ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Do not expose your API credentials. Instead, always call the [`/auth`](https://docs.tryterra.co/reference) endpoints from your **backend.** * Do not call the API from your **frontend**, as this will lead to a **CORS error.** * Do not use **WebView** or **iFrame** for the authentication flow. Using them poses security risks due to the invisible URL bar, meaning that the user cannot know the domain onto which they are entering their username & password. Providers may completely block authentication leading to an error during the flow. Instead, use a **new tab** or an **in-app browser** to open the URL returned by the `/auth` endpoints. [PreviousAuthentication flowchevron-left](https://docs.tryterra.co/health-and-fitness-api/user-authentication/authentication-flow) [NextImplementation (Custom UI)chevron-right](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui) Last updated 8 months ago Was this helpful? * [1\. Make an API Request](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-terra-widget#id-1.-make-an-api-request) * [2\. Parse the Widget URL from the JSON Response](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-terra-widget#id-2.-parse-the-widget-url-from-the-json-response) * [3\. Open The Widget URL](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-terra-widget#id-3.-open-the-widget-url) * [❌ Common Mistakes](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-terra-widget#common-mistakes) Was this helpful? sun-brightdesktopmoon JSON Copy { "session_id": "23dc2540-7139-44c6-8158-f81196e2cf2e", "url": "https://widget.tryterra.co/session/344d475f-296a-489a-a88c-54183671dafd", "status": "success", "expires_in": 900 } sun-brightdesktopmoon --- # Quickstart | Terra Docs 2 minute video walkthrough of Quickstart [hashtag](https://docs.tryterra.co/health-and-fitness-api/quickstart#key-steps-to-setup-health-and-fitness-api) Key steps to setup Health & Fitness API ------------------------------------------------------------------------------------------------------------------------------------------------------------ Follow this short tutorial to set up event-based health data delivery via Webhooks. Learn how Terra manages user authentication and can automatically send new user data, simplifying your integration. (Other methods, like requesting historical data, are covered in the detailed guides. 1 ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/quickstart#integration-setup) Integration Setup #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/quickstart#a.-add-data-sources-from-your-terra-dashboard) A. Add Data Sources from your Terra Dashboard * First you need to select your data sources on your Terra dashboard. This determines: * (a) What data sources are available for end-users to chose on the Terra auth widget. * What data sources are automatically synced to your data destination via events. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FRJsLLU70XEMDDQORDZlM%252FCapture%2520d%25E2%2580%2599e%25CC%2581cran%25202025-05-16%2520a%25CC%2580%252018.21.38.png%3Falt%3Dmedia%26token%3Dc76b7c79-3d46-461b-b47a-910da4e7f8a1&width=768&dpr=3&quality=100&sign=ad19f759&sv=2) #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/quickstart#b.-add-a-data-destination-in-your-terra-dashboard) B. Add a Data Destination in your Terra Dashboard * The Health & Fitness API is **event**\-**based**, so the **Data** **Destinations** are where you will receive **payload events:** * (a) New health data updates * (b) Authentication events, de-auth events, etc. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FOUdYC0pQPunKGtLf6UUH%252FCapture%2520d%25E2%2580%2599e%25CC%2581cran%25202025-05-16%2520a%25CC%2580%252018.30.23.png%3Falt%3Dmedia%26token%3D1f5b2350-e9bb-4701-abf4-c7000bdcd9e7&width=768&dpr=3&quality=100&sign=4af0fd5b&sv=2) circle-info [hashtag](https://docs.tryterra.co/health-and-fitness-api/quickstart#how-to-setup-a-webhook-destination) How to setup a Webhook destination? ------------------------------------------------------------------------------------------------------------------------------------------------- **Webhook.site** * Using [**webhook.site**arrow-up-right](https://webhook.site/) you can generate a temporary webhook destinations for testing. * Copy _Your unique URL_ that is automatically generated when you enter the site. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FK8OxsTJyx4dIiVl8JxF9%252Fimage.png%3Falt%3Dmedia%26token%3Dd02d5923-0759-4520-9d23-adddc105aa6d&width=300&dpr=3&quality=100&sign=a63812f8&sv=2) * * * **Your own Webhook endpoint on your local machine** * First create a web server that runs locally on your computer (see code block). * Then, expose your server to the internet with a tool such as [ngrokarrow-up-right](https://ngrok.com/) and start receiving payloads. * If you are using ngrok, running `ngrok http {PORT_NUMBER}` will expose your server to the internet and return its URL. #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/quickstart#c.-obtain-your-api-key-and-dev-id-from-your-terra-dashboard) C. Obtain your API Key & Dev-ID from your Terra Dashboard ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FYXJQjaC0x8EHMd6IGsQf%252Fimage.png%3Falt%3Dmedia%26token%3Dce11b6c7-c64b-4cde-865b-0aee76bd1373&width=768&dpr=3&quality=100&sign=65645666&sv=2) Screenshot of the Terra dashboard with a red box highlighting the button to obtain API credentials circle-info #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/quickstart#core-concept-user_id) Core concept: \`user\_id\` All data is linked back to a `user_id` on Terra's side. This uniquely identifies a wearable account connection through the API and allows you to retrieve data for that wearable account. This is what Terra calls a [User (Terra user)](https://docs.tryterra.co/introduction/core-concepts#user-terra-user) . **You will use this** `**user_id**` **in all your data-related interactions with Terra** circle-info #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/quickstart#core-concept-reference_id) Core concept: \`reference\_id\` You can link a `user_id` to an entity on your end using a `reference_id`. This is a custom identifying metadata you can define on the Terra User object to link them back to a user on your app. 2 ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/quickstart#user-authentication) **User Authentication** * Next you need to authenticate a user via the API to a data source (e.g. to Oura, Fitbit, Withings). * Terra simplifies this by allowing you to generate a pre-built authentication widget session (by running the following code). * Copy/Paste the widget session `url` into web browser. To test the authentication flow, you can choose a data sources (e.g. Fitbit), and complete the flow. Python Node.js cURL 3 ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/quickstart#receive-data-updates) **Receive data updates** * Terra automatically sends new data to your **server (e.g. webhook endpoint)** when it becomes available from your users' wearables. * If you're using your own Webhook destination, the following code is an example of how you can handle Webhooks. Python Node.js 4 [hashtag](https://docs.tryterra.co/health-and-fitness-api/quickstart#example-payloads) Example payloads ------------------------------------------------------------------------------------------------------------ Activity Daily Sleep [hashtag](https://docs.tryterra.co/health-and-fitness-api/quickstart#next-steps) Next steps ------------------------------------------------------------------------------------------------ Now that you understand the basics, move onto onto our [**guides**arrow-up-right](https://docs.tryterra.co/health-and-fitness-api/integration-setup) for detailed documentation on the Health & Fitness API [PreviousOverviewchevron-left](https://docs.tryterra.co/health-and-fitness-api/getting-started) [NextIntegration setupchevron-right](https://docs.tryterra.co/health-and-fitness-api/integration-setup) Last updated 9 days ago Was this helpful? * [Key steps to setup Health & Fitness API](https://docs.tryterra.co/health-and-fitness-api/quickstart#key-steps-to-setup-health-and-fitness-api) * [Integration Setup](https://docs.tryterra.co/health-and-fitness-api/quickstart#integration-setup) * [User Authentication](https://docs.tryterra.co/health-and-fitness-api/quickstart#user-authentication) * [Receive data updates](https://docs.tryterra.co/health-and-fitness-api/quickstart#receive-data-updates) * [Example payloads](https://docs.tryterra.co/health-and-fitness-api/quickstart#example-payloads) * [Next steps](https://docs.tryterra.co/health-and-fitness-api/quickstart#next-steps) Was this helpful? sun-brightdesktopmoon Copy import flask app = flask.Flask(__name__) if __name__ == "__main__": app.run(host="localhost", port=8080) Copy # pip install terra-python from terra import Terra client = Terra( dev_id="", api_key="", ) response = client.authentication.generatewidgetsession( reference_id="my_first_connection", auth_success_redirect_url="https://example.com/success", auth_failure_redirect_url="https://example.com/failure", ) widget_url = response.url # e.g. "https://widget.tryterra.co/session/344d475f-296a-489a-a88c-54183671dafd" print(widget_url) Copy // npm i -s terra-api import { TerraClient } from "terra-api"; const client = new TerraClient({ apiKey: "YOUR_API_KEY", devId: "YOUR_DEV_ID" }); async function generateWidgetSession() { try { const response = await client.authentication.generatewidgetsession({ reference_id: "my_first_connection", auth_success_redirect_url: "https://example.com/success", auth_failure_redirect_url: "https://example.com/failure" }); console.log("Widget URL:", response.url); } catch (error) { console.error("Error generating widget session:", error.response?.data || error.message); } } generateWidgetSession(); CLI Copy curl --request POST --url https://api.tryterra.co/v2/auth/generateWidgetSession \ --header 'dev-id: ' \ --header 'x-api-key: ' \ --header 'Content-Type: application/json' \ --data '{ "language": "en", "reference_id": "my_first_connection", "auth_success_redirect_url": "https://example.com/success", "auth_failure_redirect_url": "https://example.com/failure", }' python Copy import logging import flask from flask import request logging.basicConfig(level=logging.INFO) _LOGGER = logging.getLogger("app") app = flask.Flask(__name__) @app.route("/consumeTerraWebhook", methods=["POST"]) def consume_terra_webhook() -> flask.Response: data = request.get_json() _LOGGER.info( "Received webhook for user %s of type %s", data.get("user", {}).get("user_id"), data["type"] ) # you can now use the incoming data in your app # handleData(data) if __name__ == "__main__": app.run(host="localhost", port=8000) javascript Copy const express = require("express"); const bodyParser = require("body-parser"); const app = express(); // Parse raw JSON bodies app.use( bodyParser.raw({ inflate: true, limit: "4000kb", type: "application/json", }) ); // Webhook endpoint app.post("/consumeTerraWebhook", (req, res) => { res.sendStatus(200); // Respond to Terra immediately try { const data = JSON.parse(req.body.toString("utf8")); console.log("Received Terra Webhook Data:"); console.log(JSON.stringify(data, null, 2)); } catch (err) { console.error("Failed to parse webhook payload:", err.message); } }); // Start server const port = 3000; app.listen(port, () => { console.log(`Server started on port ${port}`); }) Copy { "calories_data": { "total_burned_calories": 201.64948069082567, "net_activity_calories": 699.1220687609259, "calorie_samples": [], "net_intake_calories": 36.29916049628912, "BMR_calories": 1185.749074044957 }, "data_enrichment": { "total_stress_score": null, "cardiovascular_contributors": null, "respiratory_contributors": null, "respiratory_score": null, "stress_contributors": null, "start_time": null, "immune_index": null, "immune_contributors": null, "readiness_score": null, "cardiovascular_score": null, "readiness_contributors": null }, "metadata": { "timestamp_localization": 1, "start_time": "2026-01-12T15:15:33.569000+00:00", "upload_type": 0, "end_time": "2026-01-12T15:58:33.569000+00:00" }, "stress_data": { "medium_stress_duration_seconds": 6.349667550340612, "max_stress_level": 9.210017873757996, "stress_duration_seconds": 9.188461255789646, "stress_rating": null, "rest_stress_duration_seconds": 19.087716697774244, "activity_stress_duration_seconds": 17.692276279869738, "avg_stress_level": 5.423064674407496, "body_battery_samples": [], "low_stress_duration_seconds": 9.16660083749294, "high_stress_duration_seconds": 16.284780394560798, "samples": [\ {\ "level": 9.722553038898797,\ "timestamp": "2026-01-12T15:15:33.569000+00:00"\ },\ {\ "level": 5.607069716919538,\ "timestamp": "2026-01-12T15:27:33.569000+00:00"\ },\ {\ "level": 10.18828379497692,\ "timestamp": "2026-01-12T15:39:33.569000+00:00"\ },\ {\ "level": 11.682798631709282,\ "timestamp": "2026-01-12T15:51:33.569000+00:00"\ }\ ] }, "scores": { "biological_age": null, "recovery": null, "activity": null, "sleep": null }, "device_data": { "manufacturer": null, "hardware_version": null, "other_devices": [], "software_version": null, "name": null, "activation_timestamp": null, "serial_number": null, "data_provided": [], "last_upload_date": null }, "strain_data": { "strain_level": null }, "MET_data": { "avg_level": null, "num_low_intensity_minutes": null, "MET_samples": [], "num_high_intensity_minutes": null, "num_inactive_minutes": null, "num_moderate_intensity_minutes": null }, "tag_data": { "tags": [] }, "active_durations_data": { "standing_hours_count": null, "vigorous_intensity_seconds": 2146.912371935673, "activity_levels_samples": [], "rest_seconds": null, "standing_seconds": null, "low_intensity_seconds": null, "moderate_intensity_seconds": 2425.139891985638, "num_continuous_inactive_periods": null, "inactivity_seconds": 941.5119531235803, "activity_seconds": 1372.8110512769454 }, "oxygen_data": { "saturation_samples": [\ {\ "percentage": 80.01528099248304,\ "type": 0,\ "timestamp": "2026-01-12T15:15:33.569000+00:00"\ },\ {\ "percentage": 89.02423522918154,\ "type": 0,\ "timestamp": "2026-01-12T15:27:33.569000+00:00"\ },\ {\ "percentage": 97.62789203583579,\ "type": 0,\ "timestamp": "2026-01-12T15:39:33.569000+00:00"\ },\ {\ "percentage": 88.66506651767715,\ "type": 0,\ "timestamp": "2026-01-12T15:51:33.569000+00:00"\ }\ ], "vo2_samples": [], "avg_saturation_percentage": 89.09072682796142, "vo2max_ml_per_min_per_kg": null }, "distance_data": { "distance_meters": 16885.341964876527, "elevation": { "gain_planned_meters": null, "min_meters": null, "avg_meters": null, "gain_actual_meters": null, "loss_actual_meters": null, "max_meters": null }, "floors_climbed": 45, "steps": 19906, "swimming": { "num_strokes": null, "num_laps": null, "pool_length_meters": null }, "detailed": { "floors_climbed_samples": [], "step_samples": [\ {\ "timer_duration_seconds": 0,\ "timestamp": "2026-01-12T15:15:33.569000+00:00",\ "steps": 69\ },\ {\ "timer_duration_seconds": 12,\ "timestamp": "2026-01-12T15:27:33.569000+00:00",\ "steps": 252\ },\ {\ "timer_duration_seconds": 24,\ "timestamp": "2026-01-12T15:39:33.569000+00:00",\ "steps": 581\ },\ {\ "timer_duration_seconds": 36,\ "timestamp": "2026-01-12T15:51:33.569000+00:00",\ "steps": 1073\ }\ ], "distance_samples": [\ {\ "distance_meters": 11.596938389705349,\ "timer_duration_seconds": 0,\ "timestamp": "2026-01-12T15:15:33.569000+00:00"\ },\ {\ "distance_meters": 38.1556198632113,\ "timer_duration_seconds": 12,\ "timestamp": "2026-01-12T15:27:33.569000+00:00"\ },\ {\ "distance_meters": 79.80821244048354,\ "timer_duration_seconds": 24,\ "timestamp": "2026-01-12T15:39:33.569000+00:00"\ },\ {\ "distance_meters": 90.70677061556792,\ "timer_duration_seconds": 36,\ "timestamp": "2026-01-12T15:51:33.569000+00:00"\ }\ ], "elevation_samples": [] } }, "heart_rate_data": { "summary": { "resting_hr_bpm": 61.36617472975378, "avg_hrv_rmssd": null, "hr_zone_data": [], "avg_hr_bpm": 104.67539173542949, "min_hr_bpm": 109.02337832771033, "avg_hrv_sdnn": null, "max_hr_bpm": 52.89773898819859, "user_max_hr_bpm": null }, "detailed": { "hrv_samples_rmssd": [], "hrv_samples_sdnn": [], "hr_samples": [\ {\ "bpm": 94,\ "context": 0,\ "timer_duration_seconds": null,\ "timestamp": "2026-01-12T15:15:33.569000+00:00"\ },\ {\ "bpm": 82,\ "context": 0,\ "timer_duration_seconds": null,\ "timestamp": "2026-01-12T15:27:33.569000+00:00"\ },\ {\ "bpm": 133,\ "context": 0,\ "timer_duration_seconds": null,\ "timestamp": "2026-01-12T15:39:33.569000+00:00"\ },\ {\ "bpm": 111,\ "context": 0,\ "timer_duration_seconds": null,\ "timestamp": "2026-01-12T15:51:33.569000+00:00"\ }\ ] } } } Copy { "MET_data": { "num_high_intensity_minutes": null, "num_inactive_minutes": null, "avg_level": null, "num_low_intensity_minutes": null, "MET_samples": [], "num_moderate_intensity_minutes": null }, "oxygen_data": { "saturation_samples": [\ {\ "type": 0,\ "percentage": 92.71897169968557,\ "timestamp": "2026-01-12T15:17:24.946000+00:00"\ },\ {\ "type": 0,\ "percentage": 93.48002536123029,\ "timestamp": "2026-01-12T15:28:24.946000+00:00"\ },\ {\ "type": 0,\ "percentage": 91.1865484069052,\ "timestamp": "2026-01-12T15:39:24.946000+00:00"\ },\ {\ "type": 0,\ "percentage": 98.56181571992339,\ "timestamp": "2026-01-12T15:50:24.946000+00:00"\ },\ {\ "type": 0,\ "percentage": 96.73982424934387,\ "timestamp": "2026-01-12T16:01:24.946000+00:00"\ }], "vo2max_ml_per_min_per_kg": null, "avg_saturation_percentage": 85.74075219533049, "vo2_samples": [] }, "scores": { "sleep": null, "activity": null, "biological_age": null, "recovery": null }, "device_data": { "hardware_version": null, "serial_number": null, "activation_timestamp": null, "other_devices": [], "software_version": null, "data_provided": [], "last_upload_date": null, "name": null, "manufacturer": null }, "heart_rate_data": { "summary": { "resting_hr_bpm": 40.27773380616422, "avg_hr_bpm": 145.57619562270028, "hr_zone_data": [], "max_hr_bpm": 62.76590801535406, "user_max_hr_bpm": null, "avg_hrv_rmssd": null, "avg_hrv_sdnn": null, "min_hr_bpm": 88.04361787772406 }, "detailed": { "hrv_samples_sdnn": [], "hrv_samples_rmssd": [], "hr_samples": [\ {\ "context": 0,\ "timer_duration_seconds": null,\ "bpm": 88,\ "timestamp": "2026-01-12T15:17:24.946000+00:00"\ },\ {\ "context": 0,\ "timer_duration_seconds": null,\ "bpm": 161,\ "timestamp": "2026-01-12T15:28:24.946000+00:00"\ },\ {\ "context": 0,\ "timer_duration_seconds": null,\ "bpm": 145,\ "timestamp": "2026-01-12T15:39:24.946000+00:00"\ },\ {\ "context": 0,\ "timer_duration_seconds": null,\ "bpm": 114,\ "timestamp": "2026-01-12T15:50:24.946000+00:00"\ },\ {\ "context": 0,\ "timer_duration_seconds": null,\ "bpm": 148,\ "timestamp": "2026-01-12T16:01:24.946000+00:00"\ }] } }, "strain_data": { "strain_level": null }, "active_durations_data": { "low_intensity_seconds": null, "activity_seconds": 292.1944505275938, "standing_hours_count": null, "vigorous_intensity_seconds": 1629.9213866369444, "num_continuous_inactive_periods": null, "activity_levels_samples": [], "standing_seconds": null, "inactivity_seconds": 356.94645537788244, "moderate_intensity_seconds": 2549.030844567316, "rest_seconds": null }, "data_enrichment": { "total_stress_score": null, "immune_contributors": null, "stress_contributors": null, "respiratory_contributors": null, "respiratory_score": null, "cardiovascular_contributors": null, "immune_index": null, "readiness_score": null, "cardiovascular_score": null, "start_time": null, "readiness_contributors": null }, "metadata": { "timestamp_localization": 1, "upload_type": 0, "end_time": "2026-01-12T16:06:24.946000+00:00", "start_time": "2026-01-12T15:17:24.946000+00:00" }, "stress_data": { "low_stress_duration_seconds": 19.313615693723424, "max_stress_level": 0.4783574112515465, "body_battery_samples": [], "medium_stress_duration_seconds": 27.176295626275646, "high_stress_duration_seconds": 1.253318481875761, "rest_stress_duration_seconds": 30.944456595746683, "samples": [\ {\ "level": 0.8367534906275448,\ "timestamp": "2026-01-12T15:17:24.946000+00:00"\ },\ {\ "level": 9.015457752116914,\ "timestamp": "2026-01-12T15:28:24.946000+00:00"\ },\ {\ "level": 7.542179332824672,\ "timestamp": "2026-01-12T15:39:24.946000+00:00"\ },\ {\ "level": 0.7267409467304642,\ "timestamp": "2026-01-12T15:50:24.946000+00:00"\ },\ {\ "level": 13.339626251306429,\ "timestamp": "2026-01-12T16:01:24.946000+00:00"\ }], "stress_rating": null, "stress_duration_seconds": 30.171079973169284, "avg_stress_level": 0.9281102170234745, "activity_stress_duration_seconds": 5.485342085200179 }, "tag_data": { "tags": [] }, "calories_data": { "BMR_calories": 1801.1426192553054, "total_burned_calories": 265.51092094691603, "net_activity_calories": 481.3419040726358, "calorie_samples": [], "net_intake_calories": 145.58311256774806 }, "distance_data": { "steps": 7708, "floors_climbed": 20, "detailed": { "step_samples": [\ {\ "steps": 297,\ "timer_duration_seconds": 0,\ "timestamp": "2026-01-12T15:17:24.946000+00:00"\ },\ {\ "steps": 726,\ "timer_duration_seconds": 11,\ "timestamp": "2026-01-12T15:28:24.946000+00:00"\ },\ {\ "steps": 1091,\ "timer_duration_seconds": 22,\ "timestamp": "2026-01-12T15:39:24.946000+00:00"\ },\ {\ "steps": 1305,\ "timer_duration_seconds": 33,\ "timestamp": "2026-01-12T15:50:24.946000+00:00"\ },\ {\ "steps": 1659,\ "timer_duration_seconds": 44,\ "timestamp": "2026-01-12T16:01:24.946000+00:00"\ }], "elevation_samples": [], "floors_climbed_samples": [], "distance_samples": [\ {\ "distance_meters": 32.233222569064836,\ "timer_duration_seconds": 0,\ "timestamp": "2026-01-12T15:17:24.946000+00:00"\ },\ {\ "distance_meters": 87.88385373215999,\ "timer_duration_seconds": 11,\ "timestamp": "2026-01-12T15:28:24.946000+00:00"\ },\ {\ "distance_meters": 113.28706293967684,\ "timer_duration_seconds": 22,\ "timestamp": "2026-01-12T15:39:24.946000+00:00"\ },\ {\ "distance_meters": 136.35507455273805,\ "timer_duration_seconds": 33,\ "timestamp": "2026-01-12T15:50:24.946000+00:00"\ },\ {\ "distance_meters": 175.40270599823873,\ "timer_duration_seconds": 44,\ "timestamp": "2026-01-12T16:01:24.946000+00:00"\ }] }, "distance_meters": 14034.070754043652, "elevation": { "avg_meters": null, "min_meters": null, "gain_planned_meters": null, "gain_actual_meters": null, "max_meters": null, "loss_actual_meters": null }, "swimming": { "num_laps": null, "pool_length_meters": null, "num_strokes": null } } } Copy { "data_enrichment": { "sleep_score": null, "sleep_contributors": null }, "heart_rate_data": { "summary": { "user_max_hr_bpm": null, "avg_hr_bpm": 41, "max_hr_bpm": 71, "avg_hrv_rmssd": 116, "min_hr_bpm": 60, "resting_hr_bpm": 65, "avg_hrv_sdnn": null }, "detailed": { "hrv_samples_rmssd": [\ {\ "timestamp": "2026-01-12T15:18:04.316000+00:00",\ "hrv_rmssd": 57\ },\ {\ "timestamp": "2026-01-12T15:30:04.316000+00:00",\ "hrv_rmssd": 71\ },\ {\ "timestamp": "2026-01-12T15:42:04.316000+00:00",\ "hrv_rmssd": 54\ },\ {\ "timestamp": "2026-01-12T15:54:04.316000+00:00",\ "hrv_rmssd": 101\ },\ {\ "timestamp": "2026-01-12T16:06:04.316000+00:00",\ "hrv_rmssd": 43\ },\ {\ "timestamp": "2026-01-12T16:18:04.316000+00:00",\ "hrv_rmssd": 78\ },\ {\ "timestamp": "2026-01-12T16:30:04.316000+00:00",\ "hrv_rmssd": 91\ },\ {\ "timestamp": "2026-01-12T16:42:04.316000+00:00",\ "hrv_rmssd": 77\ },\ {\ "timestamp": "2026-01-12T16:54:04.316000+00:00",\ "hrv_rmssd": 89\ }], "hrv_samples_sdnn": [], "hr_samples": [\ {\ "context": 0,\ "timestamp": "2026-01-12T15:18:04.316000+00:00",\ "bpm": 87,\ "timer_duration_seconds": null\ },\ {\ "context": 0,\ "timestamp": "2026-01-12T15:30:04.316000+00:00",\ "bpm": 84,\ "timer_duration_seconds": null\ },\ {\ "context": 0,\ "timestamp": "2026-01-12T15:42:04.316000+00:00",\ "bpm": 135,\ "timer_duration_seconds": null\ },\ {\ "context": 0,\ "timestamp": "2026-01-12T15:54:04.316000+00:00",\ "bpm": 163,\ "timer_duration_seconds": null\ },\ {\ "context": 0,\ "timestamp": "2026-01-12T16:06:04.316000+00:00",\ "bpm": 168,\ "timer_duration_seconds": null\ },\ {\ "context": 0,\ "timestamp": "2026-01-12T16:18:04.316000+00:00",\ "bpm": 159,\ "timer_duration_seconds": null\ },\ {\ "context": 0,\ "timestamp": "2026-01-12T16:30:04.316000+00:00",\ "bpm": 170,\ "timer_duration_seconds": null\ },\ {\ "context": 0,\ "timestamp": "2026-01-12T16:42:04.316000+00:00",\ "bpm": 119,\ "timer_duration_seconds": null\ },\ {\ "context": 0,\ "timestamp": "2026-01-12T16:54:04.316000+00:00",\ "bpm": 163,\ "timer_duration_seconds": null\ }] } }, "device_data": { "activation_timestamp": null, "last_upload_date": null, "software_version": null, "serial_number": null, "data_provided": [], "hardware_version": null, "other_devices": [], "manufacturer": null, "name": null }, "sleep_durations_data": { "awake": { "num_wakeup_events": null, "duration_long_interruption_seconds": null, "duration_awake_state_seconds": 422.440743038517, "sleep_latency_seconds": 75.3128264600394, "duration_short_interruption_seconds": null, "wake_up_latency_seconds": 409.7986863235109, "num_out_of_bed_events": null }, "hypnogram_samples": [\ {\ "level": 4,\ "timestamp": "2026-01-12T15:18:04.316000+00:00"\ },\ {\ "level": 5,\ "timestamp": "2026-01-12T15:30:04.316000+00:00"\ },\ {\ "level": 2,\ "timestamp": "2026-01-12T15:42:04.316000+00:00"\ },\ {\ "level": 6,\ "timestamp": "2026-01-12T15:54:04.316000+00:00"\ },\ {\ "level": 0,\ "timestamp": "2026-01-12T16:06:04.316000+00:00"\ },\ {\ "level": 4,\ "timestamp": "2026-01-12T16:18:04.316000+00:00"\ },\ {\ "level": 6,\ "timestamp": "2026-01-12T16:30:04.316000+00:00"\ },\ {\ "level": 6,\ "timestamp": "2026-01-12T16:42:04.316000+00:00"\ },\ {\ "level": 6,\ "timestamp": "2026-01-12T16:54:04.316000+00:00"\ }], "asleep": { "num_REM_events": null, "duration_deep_sleep_state_seconds": 235.6767638816588, "duration_REM_sleep_state_seconds": 366.2891680639711, "duration_light_sleep_state_seconds": 79.73794929949709, "duration_asleep_state_seconds": 154.94272052544733 }, "sleep_efficiency": 20.45276477924687, "other": { "duration_in_bed_seconds": 372.64335780777157, "duration_unmeasurable_sleep_seconds": null } }, "respiration_data": { "oxygen_saturation_data": { "avg_saturation_percentage": 90, "start_time": "2026-01-12T16:54:04.316000+00:00", "end_time": "2026-01-12T16:54:04.316000+00:00", "samples": [\ {\ "timestamp": "2026-01-12T15:18:04.316000+00:00",\ "percentage": 91,\ "type": 0\ },\ {\ "timestamp": "2026-01-12T15:30:04.316000+00:00",\ "percentage": 93,\ "type": 0\ },\ {\ "timestamp": "2026-01-12T15:42:04.316000+00:00",\ "percentage": 92,\ "type": 0\ },\ {\ "timestamp": "2026-01-12T15:54:04.316000+00:00",\ "percentage": 98,\ "type": 0\ },\ {\ "timestamp": "2026-01-12T16:06:04.316000+00:00",\ "percentage": 99,\ "type": 0\ },\ {\ "timestamp": "2026-01-12T16:18:04.316000+00:00",\ "percentage": 94,\ "type": 0\ },\ {\ "timestamp": "2026-01-12T16:30:04.316000+00:00",\ "percentage": 93,\ "type": 0\ },\ {\ "timestamp": "2026-01-12T16:42:04.316000+00:00",\ "percentage": 92,\ "type": 0\ },\ {\ "timestamp": "2026-01-12T16:54:04.316000+00:00",\ "percentage": 94,\ "type": 0\ }] }, "breaths_data": { "avg_breaths_per_min": 15, "start_time": "2026-01-12T16:54:04.316000+00:00", "on_demand_reading": null, "end_time": "2026-01-12T16:54:04.316000+00:00", "samples": [\ {\ "breaths_per_min": 13,\ "timestamp": "2026-01-12T15:18:04.316000+00:00"\ },\ {\ "breaths_per_min": 12,\ "timestamp": "2026-01-12T15:30:04.316000+00:00"\ },\ {\ "breaths_per_min": 12,\ "timestamp": "2026-01-12T15:42:04.316000+00:00"\ },\ {\ "breaths_per_min": 12,\ "timestamp": "2026-01-12T15:54:04.316000+00:00"\ },\ {\ "breaths_per_min": 12,\ "timestamp": "2026-01-12T16:06:04.316000+00:00"\ },\ {\ "breaths_per_min": 12,\ "timestamp": "2026-01-12T16:18:04.316000+00:00"\ },\ {\ "breaths_per_min": 10,\ "timestamp": "2026-01-12T16:30:04.316000+00:00"\ },\ {\ "breaths_per_min": 12,\ "timestamp": "2026-01-12T16:42:04.316000+00:00"\ },\ {\ "breaths_per_min": 15,\ "timestamp": "2026-01-12T16:54:04.316000+00:00"\ }], "max_breaths_per_min": 17, "min_breaths_per_min": 18 }, "snoring_data": { "num_snoring_events": null, "total_snoring_duration_seconds": null, "start_time": "2026-01-12T16:54:04.316000+00:00", "end_time": "2026-01-12T16:54:04.316000+00:00", "samples": [\ {\ "timestamp": "2026-01-12T15:18:04.316000+00:00",\ "duration_seconds": 43\ },\ {\ "timestamp": "2026-01-12T15:30:04.316000+00:00",\ "duration_seconds": 3\ },\ {\ "timestamp": "2026-01-12T15:42:04.316000+00:00",\ "duration_seconds": 84\ },\ {\ "timestamp": "2026-01-12T15:54:04.316000+00:00",\ "duration_seconds": 98\ },\ {\ "timestamp": "2026-01-12T16:06:04.316000+00:00",\ "duration_seconds": 95\ },\ {\ "timestamp": "2026-01-12T16:18:04.316000+00:00",\ "duration_seconds": 34\ },\ {\ "timestamp": "2026-01-12T16:30:04.316000+00:00",\ "duration_seconds": 83\ },\ {\ "timestamp": "2026-01-12T16:42:04.316000+00:00",\ "duration_seconds": 34\ },\ {\ "timestamp": "2026-01-12T16:54:04.316000+00:00",\ "duration_seconds": 63\ }] } }, "scores": { "sleep": null }, "temperature_data": { "delta": null }, "metadata": { "is_nap": false, "summary_id": null, "start_time": "2026-01-12T15:18:04.316000+00:00", "timestamp_localization": 1, "end_time": "2026-01-12T22:59:04.316000+00:00", "upload_type": 0 }, "readiness_data": { "recovery_level": 0, "readiness": null } } sun-brightdesktopmoon --- # Supabase | Terra Docs [Supabasearrow-up-right](https://supabase.com/) offers the best of both worlds in terms of allowing you to have both [storage **buckets**arrow-up-right](https://supabase.com/docs/guides/storage) and [Postgres SQL **tables**arrow-up-right](https://supabase.com/docs/guides/database/tables) **.** Both coexist within the same platform, making development a breeze. ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/supabase#setup) Setup 1. [Create a storage bucketarrow-up-right](https://supabase.com/docs/guides/storage/buckets/creating-buckets) with an appropriate name (e.g. **terra-payloads**) in your project 2. [Create a tablearrow-up-right](https://supabase.com/docs/guides/database/tables#creating-tables) within your project. You do not need to add columns to it, Terra will handle that when connecting to it. 3. [Create an API keyarrow-up-right](https://supabase.com/docs/guides/api/api-keys#the-servicerole-key) for access to your supabase project. Terra will need read & write access to the previously created resources in steps 1 and 2. You'll then need to enter the above details (host, bucket name, and API key) into your Terra Dashboard when adding the Supabase destination ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/supabase#data-structure) Data Structure When using Supabase (since you get the best of SQL and S3 buckets 🎉) Terra stores the data in the same structure as for [SQL](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/supabase#data-structure) and for [S3 Buckets](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/supabase#data-structure-2) . Follow those sections for more detailed information on how that is stored! [PreviousSQL database (Postgres, MySQL)chevron-left](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/sql-database-postgres-mysql) [NextCloud storage (S3, GCP)chevron-right](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp) Last updated 8 months ago Was this helpful? * [Setup](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/supabase#setup) * [Data Structure](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/supabase#data-structure) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # SQL database (Postgres, MySQL) | Terra Docs SQL databases are easy to set up and often the go-to choices for less abstracted storage solutions. Terra currently supports **Postgres & MySQL**. ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/sql-database-postgres-mysql#setup) Setup You will need to ensure your SQL database is **publicly accessible**. As a security measure, you may implement [IP whitelisting](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/sql-database-postgres-mysql#security-ip-whitelisting) using the list of IPs above. Next, create a user with enough permissions to create tables & have read & write access within those tables. You can execute the scripts below based on your database Postgres MySQL Copy CREATE USER terra_user WITH PASSWORD 'your_password'; GRANT CONNECT ON DATABASE your_database_name TO terra_user; GRANT USAGE ON SCHEMA public TO terra_user; GRANT CREATE ON SCHEMA public TO terra_user; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO terra_user; Copy CREATE USER 'terra_user'@'%' IDENTIFIED BY 'your_password'; GRANT CREATE, SELECT, INSERT, UPDATE, DELETE ON your_database_name.* TO 'terra_user'@'%'; REVOKE ALL PRIVILEGES ON your_database_name.existing_table FROM 'terra_user'@'%'; ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/sql-database-postgres-mysql#data-structure) Data Structure Data will be stored in tables within your SQL database following the structure below: ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252F9xZwFWRrdOafV23SnZsz%252Fimage.png%3Falt%3Dmedia%26token%3D49e42e75-d8aa-4f11-bfea-aa6335b9506e&width=768&dpr=3&quality=100&sign=a714bd9f&sv=2) Users will be created in the `terra_users` table, data payloads will be placed in the `terra_data_payloads`, and all other payloads sent will be added to the `terra_other_payloads`. circle-info When using [SQL](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/sql-database-postgres-mysql#sql-database) as a destination, Terra handles data storage for you. All data payloads will be stored in a Terra-owned S3 bucket, and the download link for each payload will be found under the `payload_url` column [PreviousWebhookschevron-left](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/webhooks) [NextSupabasechevron-right](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/supabase) Last updated 8 months ago Was this helpful? * [Setup](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/sql-database-postgres-mysql#setup) * [Data Structure](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/sql-database-postgres-mysql#data-structure) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Implementation (Custom UI) | Terra Docs [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui#id-1.-build-your-ui) 1\. Build your UI -------------------------------------------------------------------------------------------------------------------------------------------------- First, create a **button** for each data source that a user might want to connect. (e.g. a "Connect to Fitbit" button). You may take inspiration from the Terra Widget when creating your own UI. You may use the [/integrations/detailed](https://docs.tryterra.co/reference#integrations-detailed) endpoint to fetch metadata for each source available through Terra when creating your UI. This enables you to dynamically retrieve the sources you’ve [activated in your Dashboard](https://docs.tryterra.co/health-and-fitness-api/integration-setup) (using the `enabled` boolean parameter in the response), along with their associated metadata, such as available **data** **types**, **display** **names**, and **logos**. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui#id-2.-make-an-api-request) 2\. Make an API Request -------------------------------------------------------------------------------------------------------------------------------------------------------------- From your backend, call the [`/auth/authenticateUser`](https://docs.tryterra.co/reference#auth-authenticateuser) to generate an authentication link Use the parameter `resource` to pass a source name (e.g. `"oura"` , `"withings"` ..) Command Line Copy curl --request POST --url https://api.tryterra.co/v2/auth/authenticateUser?resource=oura \ --header 'dev-id: ' \ --header 'x-api-key: \ --header 'Content-Type: application/json' \ --data '{ "language": "en", "reference_id": "my_first_connection", "auth_success_redirect_url": "text", "auth_failure_redirect_url": "text" }' See details in the [API Reference Page.arrow-up-right](https://docs.tryterra.co/reference#auth-generatewidgetsession) circle-info **Pro** **tip**: Use `reference_id` in your request Body to pass in your own end user's ID on your system. This will simplify reconciling the terra [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) with your end user. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui#id-3.-parse-the-auth-url-from-the-json-response) 3\. Parse the Auth URL from the JSON Response ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- The endpoint will generate an **authentication url** in the response. Retrieve it by parsing `"auth_url"` . * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui#id-4.-open-the-auth-url) 4\. Open The Auth URL ---------------------------------------------------------------------------------------------------------------------------------------------------------- Pass the retrieved `"auth_url"` to your client side, and open it either in: * an **in-app browser**, if using a mobile app, * or a **new tab,** if using a web app This will take the user straight to the [data source's](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#source-provider-integration) login screen so they can connect it. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FTuSK9MXKw4AOlEQWhIWb%252Fscreenshot%2520%282%29.png%3Falt%3Dmedia%26token%3D7ed5038d-471a-4ed7-9818-ea18bb722364&width=768&dpr=3&quality=100&sign=589f4331&sv=2) **Login** Screen (example: Oura) ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252F1lAow8Zfl010xLxwpRUI%252Fscreenshot%2520%283%29.png%3Falt%3Dmedia%26token%3D36da4b9e-bd6d-495f-b0bb-bf70302d8574&width=768&dpr=3&quality=100&sign=cbc9ca60&sv=2) **Permission** screen (example: Oura) circle-info The permissions list can be [customised through your Terra Dashboard](https://docs.tryterra.co/health-and-fitness-api/integration-setup/customising-data-types) * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui#common-mistakes) ❌ Common Mistakes ---------------------------------------------------------------------------------------------------------------------------------------------- triangle-exclamation [hashtag](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui#common-mistakes-and-best-practices) Common Mistakes and Best Practices ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Do not expose your API credentials. Instead, always call the [`/auth`](https://docs.tryterra.co/reference) endpoints from your **backend.** * Do not call the API from your **frontend**, as this will lead to a **CORS error.** * Do not use **WebView** or **iFrame** for the authentication flow. Using them poses security risks due to the invisible URL bar, meaning that the user cannot know the domain onto which they are entering their username & password. Providers may completely block authentication leading to an error during the flow. Instead, use a **new tab** or an **in-app browser** to open the URL returned by the `/auth` endpoints. [PreviousImplementation (Terra widget)chevron-left](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-terra-widget) [NextHandling authentication eventschevron-right](https://docs.tryterra.co/health-and-fitness-api/user-authentication/handling-authentication-events) Last updated 8 months ago Was this helpful? * [1\. Build your UI](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui#id-1.-build-your-ui) * [2\. Make an API Request](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui#id-2.-make-an-api-request) * [3\. Parse the Auth URL from the JSON Response](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui#id-3.-parse-the-auth-url-from-the-json-response) * [4\. Open The Auth URL](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui#id-4.-open-the-auth-url) * [❌ Common Mistakes](https://docs.tryterra.co/health-and-fitness-api/user-authentication/implementation-custom-ui#common-mistakes) Was this helpful? sun-brightdesktopmoon JSON Copy { "status": "success", "user_id": "23dc2540-7139-44c6-8158-f81196e2cf2e", "auth_url": "https://cloud.ouraring.com/oauth/authorize?response_type=code&client_id=...&redirect_uri=https%3A%2F%2Fapi.tryterra.co%2Fv2%2Fauth%2Foura%2Foauth2&scope=email+spo2+session+heartrate+personal+daily+workout+tag.." } sun-brightdesktopmoon --- # Android | Terra Docs Once you've started receiving data from a device into your app, you can start sending this data to Terra's websocket server (the broker). This will later allow you to receive it on your backend, and process it as per your requirements. circle-info ### [hashtag](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/android#prerequisite) Prerequisite Before following the steps below, make sure you've followed the guide to [stream data from a wearable device to your app](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android) [hashtag](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/android#setting-up-a-connection) Setting up a connection ------------------------------------------------------------------------------------------------------------------------------------------ You'll have previously set up a stream between a wearable device and your app [using the startRealTime function](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#start-real-time-streaming) . In order to to send this data back to the broker, you'll simply use a variant of the startRealTime function Copy import com.terra.TerraRT import com.terra.TerraRT.Connections import com.terra.TerraRT.DataTypes import com.terra.TerraRT.Update import android.os.Handler import android.os.Looper val terraRT = TerraRT() val token = "yourAuthToken" // Replace with your actual token // Initialize TerraRT SDK connection terraRT.initConnection(token) { success -> if (success) { println("TerraRT initialized successfully!") // Start device scan for BLE connection terraRT.startDeviceScan(type = Connections.BLE) { scanSuccess -> if (scanSuccess) { println("Device connected successfully!") // Start streaming real-time data using the new function signature val dataTypes: Set = setOf(DataTypes.HEART_RATE, DataTypes.STEPS) terraRT.startRealtime( type = Connections.BLE, dataTypes = dataTypes, token = token, updateHandler = { update -> handleUpdate(update) }, connectionCallback = { connectionSuccess -> if (connectionSuccess) { println("Real-time connection successfully established!") } else { println("Failed to establish real-time connection.") } } ) // Stop streaming after 5 seconds for demo purposes Handler(Looper.getMainLooper()).postDelayed({ terraRT.stopRealtime(type = Connections.BLE) println("Real-time streaming stopped.") // Optionally disconnect the device terraRT.disconnect(type = Connections.BLE) println("Device disconnected.") }, 5000) } else { println("Failed to connect to the device.") } } } else { println("Failed to initialize TerraRT.") } } fun handleUpdate(update: Update) { println("Received update at timestamp: ${update.ts}") println("Update type: ${update.type}") update.`val`?.let { value -> println("Value: $value") } } Simply passing in a token from the following endpoint will allow you to stream the same data you were reading previously within your app, and have it sent to the broker circle-info Make sure to pass in the correct user ID in the `id` query paramter in the call below. You may retrieve that user the getUserId function in the SDK, when about to ask your backend to create the token ### [hashtag](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/android#post-auth-user) Stream - Generate user token post https://ws.tryterra.co/auth/user Endpoint for generation of a token for a user (producer) connection Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Query parameters idstringOptional The ID of the user to generate a token for Header parameters dev-idstringRequired your developer ID x-api-keystringRequired your API key Responses chevron-right 200 Successful response application/json Responseobject Show propertiesplus chevron-right 403 Forbidden text/plain post /auth/user HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Successful response chevron-down [PreviousiOS (Swift)chevron-left](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/ios-swift) [NextTerra -> Your backendchevron-right](https://docs.tryterra.co/streaming-api/terra-greater-than-your-backend) Last updated 1 year ago Was this helpful? * [Setting up a connection](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/android#setting-up-a-connection) * [POSTStream - Generate user token](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/android#post-auth-user) Was this helpful? sun-brightdesktopmoon Copy POST /auth/user HTTP/1.1 Host: ws.tryterra.co x-api-key: text dev-id: text Accept: */* Copy { "token": "OTYwNWFi5ZWQMTAxMjg0Y2Qw.gzrPzZcS3Gy8QDOxbiPRwu30PTB3VxW0eE" } sun-brightdesktopmoon --- # Getting Started | Terra Docs [hashtag](https://docs.tryterra.co/teams-api/getting-started#introduction) Introduction -------------------------------------------------------------------------------------------- The Teams API allows developers to interact with team-based fitness tracking data used in sports training and monitoring. You can manage user accounts, retrieve performance metrics, and integrate with various fitness tracking providers. ### [hashtag](https://docs.tryterra.co/teams-api/getting-started#user-management) User Management #### [hashtag](https://docs.tryterra.co/teams-api/getting-started#coaches) Coaches Coaches are central to the Teams API, as they manage athletes and their associated data. **Creating a Coach** To begin using, you'll need to register a coach account. This involves providing necessary credentials and integration specifics related to the provider you're integrating with (e.g., VALD, Catapult). _Endpoint_: `POST /coaches` _Description_: Registers a new coach with the specified provider. **Required Fields**: * `reference_id`: Your internal identifier for the coach. * `provider`: The integration provider (e.g., `VALD`, `CATAPULT`). * Provider-specific authentication fields (e.g., `client_id`, `client_secret`, `token`). **Note**: After creating a coach, you'll receive a `coach_id` generated by the server, which you'll use for subsequent operations. **Deleting a Coach** If you need to remove a coach and all associated data, you can delete the coach account. _Endpoint_: `DELETE /coaches/{coachId}` _Description_: Deletes a coach and all associated athletes, activities, and tests. **Required Parameter**: * `coachId`: The unique identifier of the coach to be deleted. **Warning**: This action is irreversible and will remove all data related to the coach. #### [hashtag](https://docs.tryterra.co/teams-api/getting-started#athletes) Athletes Athletes are managed under coaches and represent the individuals whose performance data you're tracking. **Managing Athletes** While athletes are typically synced from the provider's system, you can retrieve and update athlete information as needed. _Endpoint to List Athletes_: `GET /coaches/{coachId}/athletes` _Description_: Retrieves all athletes under a specific coach. **Required Parameter**: * `coachId`: The unique identifier of the coach whose athletes you want to list. ### [hashtag](https://docs.tryterra.co/teams-api/getting-started#getting-data) Getting Data #### [hashtag](https://docs.tryterra.co/teams-api/getting-started#activities) Activities Activities represent performance sessions or events recorded by athletes. **Fetching Activities** You can retrieve all activities recorded by athletes under a specific coach. _Endpoint_: `GET /coaches/{coachId}/activities` _Description_: Retrieves activities within a specified time range for all athletes under the coach. **Required Parameter**: * `coachId`: The unique identifier of the coach. **Optional Query Parameters**: * `start_time`: Start of the time range (ISO 8601 format). * `end_time`: End of the time range (ISO 8601 format). **Fetching Activity Schemas** To understand the structure of activity metrics available, you can fetch the activity metrics schema. _Endpoint_: `GET /coaches/{coachId}/activities/metrics/schema` _Description_: Returns the schema of activity metrics for the specified coach. **Required Parameter**: * `coachId`: The unique identifier of the coach. #### [hashtag](https://docs.tryterra.co/teams-api/getting-started#tests) Tests Tests are specific assessments or measurements conducted with athletes. **Fetching Tests** You can retrieve all tests conducted by athletes under a specific coach. _Endpoint_: `GET /coaches/{coachId}/tests` _Description_: Retrieves tests within a specified time range for all athletes under the coach. **Required Parameter**: * `coachId`: The unique identifier of the coach. **Optional Query Parameters**: * `start_time`: Start of the time range (ISO 8601 format). * `end_time`: End of the time range (ISO 8601 format). ### [hashtag](https://docs.tryterra.co/teams-api/getting-started#additional-features) Additional Features #### [hashtag](https://docs.tryterra.co/teams-api/getting-started#webhooks) Webhooks Webhooks allow your application to receive real-time notifications when certain events occur, such as coach registration or athlete data updates. **Available Webhooks**: * `coach.registered`: Triggered when a new coach is registered. * `athlete.registered`: Triggered when one or more athletes are registered. **Setting Up Webhooks**: You'll need to configure your endpoint to receive webhook events and handle them appropriately. Ensure your endpoint is secure and can process the data received. #### [hashtag](https://docs.tryterra.co/teams-api/getting-started#handling-enums) Handling Enums The API uses various enumerations (enums) to represent specific sets of values for certain fields, such as `Sport`, `Position`, `Movement`, etc. **Examples of Enums**: * `Sport`: Indicates the type of sport (e.g., `FOOTBALL`, `BASKETBALL`). * `Side`: Indicates the side of the body (`LEFT`, `RIGHT`, `BOTH`). * `MetricType`: Indicates the type of metric (`FORCE`, `VELOCITY`, `POWER`). **Usage**: When processing data from the API, you'll encounter integer values representing these enums. Refer to the enum definitions provided in the API documentation to interpret these values correctly. #### [hashtag](https://docs.tryterra.co/teams-api/getting-started#integrating-with-providers) Integrating with Providers The Teams API supports integration with various fitness tracking providers. Each provider may have specific requirements for authentication and data retrieval. **Fetching Provider Details**: _Endpoint_: `GET /integrations/detailed` _Description_: Returns detailed information about available providers, including required login fields and logos. **Provider-Specific Fields**: When creating a coach or integrating with a provider, you'll need to supply provider-specific authentication fields such as `client_id`, `client_secret`, or `token`. **Example Providers**: * **VALD**: May require `client_id` and `client_secret`. * **Catapult**: May require an API `token`. **Note**: Always refer to the provider's documentation for the most accurate and up-to-date integration requirements. ### [hashtag](https://docs.tryterra.co/teams-api/getting-started#conclusion) Conclusion This guide provides an overview of how to get started with the Teams API for managing coaches, athletes, and retrieving performance data. By following the endpoints and guidelines outlined above, you can effectively integrate the Teams API into your application. For detailed information on each endpoint, including request and response formats, please refer to the API reference documentation. If you have any questions or need further assistance, feel free to reach out to our support team. Last updated 26 days ago Was this helpful? * [Introduction](https://docs.tryterra.co/teams-api/getting-started#introduction) * [User Management](https://docs.tryterra.co/teams-api/getting-started#user-management) * [Getting Data](https://docs.tryterra.co/teams-api/getting-started#getting-data) * [Additional Features](https://docs.tryterra.co/teams-api/getting-started#additional-features) * [Conclusion](https://docs.tryterra.co/teams-api/getting-started#conclusion) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Queuing services (SQS, Kafka) | Terra Docs [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/queuing-services-sqs-kafka#aws-sqs-simple-queue-service) AWS SQS (Simple Queue Service) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [AWS SQSarrow-up-right](https://aws.amazon.com/sqs/) is a managed queuing system allowing you to get messages delivered straight into your existing queue, minimising the potential of disruptions and barriers that may occur when ingesting a request from Terra API to your server. circle-exclamation [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/queuing-services-sqs-kafka#authentication-for-aws-destinations) Authentication for AWS destinations ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- All AWS-based require the following authentication setup. * * * #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/queuing-services-sqs-kafka#iam-user-access-key) IAM User Access Key The most basic way to allow Terra to write to your AWS resource is to [create an IAM userarrow-up-right](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html) with access limited to the resource you're trying to grant Terra access to. [Attach relevant policiesarrow-up-right](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_change-permissions.html) for access to the specific resource, (write access is generally the only one needed, unless specified otherwise) * * * #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/queuing-services-sqs-kafka#role-based-access) Role-based access In order to use role-based access, attach the following policy to your bucket: Copy { "Version": "2012-10-17", "Statement": [\ {\ "Effect": "Allow",\ "Principal": {\ "AWS": "arn:aws:iam::760292141147:role/EC2_Instance_Perms"\ },\ "Action": [\ "s3:GetObject",\ "s3:PutObject",\ "s3:DeleteObject"\ ],\ "Resource": "arn:aws:s3:::your-bucket-name/*"\ }\ ] } ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/queuing-services-sqs-kafka#data-structure) Data Structure Data sent to SQS can either take the type of `healthcheck` or `s3_payload`. See for further details. ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252F2F2evxB2QCMMmYrMTmZL%252Fimage.png%3Falt%3Dmedia%26token%3Dfd52a7a8-bfb7-4869-8178-15bb8baee6a4&width=768&dpr=3&quality=100&sign=909c69cd&sv=2) Each of these payloads will be a simple JSON payload formatted as in the diagram above. the `url` field in the data payload will be a download link from which you will need to download the data payload using a `GET` request. This is done to minimise the size of messages in your queue. The URL will be a [pre-signed linkarrow-up-right](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html) to an object stored in one of Terra's S3 buckets. circle-info **Note:** Terra offers the possibility of using your own S3 bucket in combination with the SQS destination. For setting this up, kindly contact Terra support. [PreviousCloud storage (S3, GCP)chevron-left](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp) [NextCustomising data typeschevron-right](https://docs.tryterra.co/health-and-fitness-api/integration-setup/customising-data-types) Last updated 8 months ago Was this helpful? * [AWS SQS (Simple Queue Service)](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/queuing-services-sqs-kafka#aws-sqs-simple-queue-service) * [Data Structure](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/queuing-services-sqs-kafka#data-structure) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Cloud storage (S3, GCP) | Terra Docs Terra allows you to connect an [S3 Bucketarrow-up-right](https://aws.amazon.com/s3/) as a destination, to get all data dumped directly into a bucket of your choice. [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp#authentication) Authentication ----------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp#aws) AWS All AWS-based destinations follow the same authentication setup. #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp#iam-user-access-key) IAM User Access Key The most basic way to allow Terra to write to your AWS resource is to [create an IAM userarrow-up-right](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html) with access limited to the resource you're trying to grant Terra access to. [Attach relevant policiesarrow-up-right](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_change-permissions.html) for access to the specific resource, (write access is generally the only one needed, unless specified otherwise) #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp#role-based-access) Role-based access In order to use role-based access, attach the following policy to your bucket: Copy { "Version": "2012-10-17", "Statement": [\ {\ "Effect": "Allow",\ "Principal": {\ "AWS": "arn:aws:iam::760292141147:role/EC2_Instance_Perms"\ },\ "Action": [\ "s3:GetObject",\ "s3:PutObject",\ "s3:DeleteObject"\ ],\ "Resource": "arn:aws:s3:::your-bucket-name/*"\ }\ ] } ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp#gcp) GCP For GCP destinations, you'll need to create a service account, and generate credentials for it. See the guide [herearrow-up-right](https://developers.google.com/workspace/guides/create-credentials#service-account) for further details. once you have generated credentials, download the JSON file with the credentials you just created, and upload it in the corresponding section when setting up your GCP-based destination * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp#data-structure) Data Structure ----------------------------------------------------------------------------------------------------------------------------------------------------------------- When data is sent to your [**S3 Bucket**arrow-up-right](https://aws.amazon.com/s3/) or [**GCS**arrow-up-right](https://cloud.google.com/storage) , it will be dumped using the following folder structure ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2F464213908-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FVGMJVuZnZyOtvV4b53cY%252Fuploads%252FILwssVx7o5iiFppgir7u%252Fimage.png%3Falt%3Dmedia%26token%3D43336f36-18b0-47e2-b089-d9d25ed8e9a4&width=768&dpr=3&quality=100&sign=d7cfcb2d&sv=2) Example for AWS S3 Versioned objects will be placed under the appropriate API version (in the screenshot above, this corresponds to `2022-03-16`. Non versioned objects (e.g. authentication Events) will be placed in their appropriate event type folder, outside of the version folder In all, every event will have as a parent folder the Event Type which it corresponds to, and will be saved with a unique name identifying it. As shown above, the name will either be a concatenation of one of the below: * For Data Events: the user ID & the start time of the period the event refers to * For all other Event Types: the user ID & timestamp the event was generated at [PreviousSupabasechevron-left](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/supabase) [NextQueuing services (SQS, Kafka)chevron-right](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/queuing-services-sqs-kafka) Last updated 8 months ago Was this helpful? * [Authentication](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp#authentication) * [AWS](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp#aws) * [GCP](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp#gcp) * [Data Structure](https://docs.tryterra.co/health-and-fitness-api/integration-setup/setting-up-data-destinations/cloud-storage-s3-gcp#data-structure) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Dedicated data source API keys | Terra Docs [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#overview) Overview ---------------------------------------------------------------------------------------------------------------------------------- Terra manages API Keys of data sources, meaning you can connect users without having to apply for each API Key. For some Data Sources, you may choose to have your own access keys for different reasons: 1. **Required by the provider:** the provider **requires** it in there terms that you use dedicated access keys. 2. **Preferred by you:** you simply wish to avoid rate limits and separate your environment from the managed Terra keys. You can find the list of providers that support this in the [**integrations table**](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#integrations-list) marked as `Managed`**.** We also included their appropriate developer dashboard in the table. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#how-to-setup-dedicated-access-keys) How to Setup Dedicated Access Keys? --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#strava) Strava 1. Log in to [https://strava.com/settings/apiarrow-up-right](https://strava.com/settings/api) 2. Create an application 3. Set the Authorization callback domain to api.tryterra.co, and save the client ID and client secret obtained 4. In your Terra dashboard, add Strava to your connections under API > Connections > Add more 5. Fill in the obtained client\_id and client secret on that connection's settings * * * ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#virtuagym) Virtuagym * Request an API key from [https://virtuagym.com/public-apiarrow-up-right](https://virtuagym.com/public-api) * In you Terra dashboard, add Virtuagym to your connections under API > Connections > Add more * After adding Virtuagym, go the Virtuagym options * Fill your portal name in the client id, and your API Key in the client secret * * * ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#huawei) Huawei 1. **Create a Huawei ID:** This can be achieved by following the [Registration & Verification guidearrow-up-right](https://developer.huawei.com/consumer/en/doc/start/registration-and-verification-0000001053628148) circle-info #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#identity-verification) 📘 Identity verification Through the Huawei ID Registration process, you will be asked to verify your identity. * If you own a business, please follow the guide for [DUNS number verificationarrow-up-right](https://developer.huawei.com/consumer/en/doc/start/atpopb-0000001062836624) or the guide [using a Business Licensearrow-up-right](https://developer.huawei.com/consumer/en/doc/start/mracoei-0000001062678404) * If you are an individual developer, follow [this guidearrow-up-right](https://developer.huawei.com/consumer/en/doc/start/ibca-0000001062388135) using your personal documents 1. **Apply for the** _**HUAWEI ID Service**_ This is separate from the Huawei ID registration - the _service_ is what will allow you to then access various Huawei APIs). Follow the guide [herearrow-up-right](https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/apply-id-0000001050069756) for a step-by-step explanation on how to achieve that * **Important parameters** Name Value **Redirect URL** [https://api.tryterra.co/v2/auth/huawei/oauth2arrow-up-right](https://api.tryterra.co/v2/auth/huawei/oauth2) **App access URL** [https://api.tryterra.co/arrow-up-right](https://api.tryterra.co/) **Callback address** [https://api.tryterra.co/v2/auth/huawei/oauth2arrow-up-right](https://api.tryterra.co/v2/auth/huawei/oauth2) 1. **Apply for Huawei Health Kit access** 1. Please follow the guide Health Kit access [herearrow-up-right](https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/apply-kitservice-0000001050071707) for an in-depth explanation of how to gain access to users' health data through Huawei Health Kit. 2. Make sure to register for notifications (webhooks) by following [these stepsarrow-up-right](https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/subscription-0000001078496860#section38652513104) : ![](https://docs.tryterra.co/~gitbook/image?url=https%3A%2F%2Ffiles.readme.io%2Fc6f3b5d-image.png&width=768&dpr=3&quality=100&sign=6b79363e&sv=2) * * * ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#freestylelibre) FreestyleLibre In **Germany** and **France**, it is necessary to have a doctor's license to be able to access FreestyleLibre of users residing in said regions. This would mean having a registered practice. Once you have a practice id for a practice on the LibreView web app after having created a professional account, you then would need to submit a support ticket for activation and we will be able to proceed as per the normal procedure. * * * ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#samsung-health-direct-connection-route) Samsung Health - Direct Connection Route As **privileged** **partners** of **Samsung** thanks to their investment in **Terra**, we have been granted access to their SDK for accessing Samsung Health directly without Health Connect. This route is much preferred to the Health Connect route due to the reasons discussed above. For access to this route, please get in touch with us through our support channels. [PreviousCustomising data typeschevron-left](https://docs.tryterra.co/health-and-fitness-api/integration-setup/customising-data-types) [NextUnderstanding Terra environmentschevron-right](https://docs.tryterra.co/health-and-fitness-api/integration-setup/understanding-terra-environments) Last updated 25 days ago Was this helpful? * [Overview](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#overview) * [How to Setup Dedicated Access Keys?](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#how-to-setup-dedicated-access-keys) * [Strava](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#strava) * [Virtuagym](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#virtuagym) * [Huawei](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#huawei) * [FreestyleLibre](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#freestylelibre) * [Samsung Health - Direct Connection Route](https://docs.tryterra.co/health-and-fitness-api/integration-setup/dedicated-data-source-api-keys#samsung-health-direct-connection-route) Was this helpful? sun-brightdesktopmoon sun-brightdesktopmoon --- # Requesting historical health data (REST API requests) | Terra Docs [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#overview) Overview -------------------------------------------------------------------------------------------------------------------------------------- Terra API is **event-based**, meaning **you** _**don’t**_ **need to manually request data via the API.** For **new** and **ongoing** **data** **updates**, Terra API automatically sends them to your configured Data Destination (e.g. Webhook, Database, or cloud storage bucket). If you need **historical** **user** **data**, you can request it using the **Health & Fitness API endpoints** by specifying the user ID, data type, and time range. This allows you to request past records on demand. In this guide you will learn: 1. When are historical data requests useful? 2. How to use the **Terra Dashboard** to make a historical data request? 3. How to use the **Terra's Health & Fitness API** to make a historical data request? 4. Request Parameters (e.g. send to destination and include samples) 5. How to handle requests of very long time ranges ? circle-check [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#prerequisites) **Prerequisites** ---------------------------------------------------------------------------------------------------------------------------------------------------- In order to receive Data as Events, you'll need to: 1. [**API Key & dev-id**:arrow-up-right](https://dashboard.tryterra.co/) Obtain your Terra API Key and dev-id from your Terra Dashboard 2. [**Destination Configured**:](https://docs.tryterra.co/health-and-fitness-api/integration-setup#set-up-your-data-sources-and-destinations) Set up a Data Destination where Terra will send event and data updates. 3. [**Data Sources Enabled**:](https://docs.tryterra.co/health-and-fitness-api/integration-setup#set-up-your-data-sources-and-destinations) Enable the specific data sources your app requires (e.g., activity, sleep). 4. **Connected at least a user. Requests are done using a** `user_id` **and at least a date.** 1. The [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) must be connected via Terra's Health & Fitness API. 2. The `user_id` is needed to make requests for historical data * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#id-1.-when-to-request-historical-data) 1\. When to request historical data? ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#a.-upon-creating-a-new-user) a. Upon creating a New User When an end user first connects an account (e.g. wearable, device, health app), you will by default only receive data from that point onwards. If you would like to **build a historical health & fitness profile of the user,** to establish **baselines** for statistics, or for any other calculations, you can make a request to Terra for data from prior to the user's authentication. circle-info #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#time-range-limits-in-historical-data-requests) Time Range limits in Historical Data Requests Some [providersarrow-up-right](https://github.com/tryterra/gitbook-docs/blob/master/health-and-fitness-api/broken-reference/README.md) impose limits on how far back a developer can request data. Those are: * **Garmin**: 5 years into the past, from the current point in time. This is subject to Garmin's backfill limits. * **Polar**: 30 days into the past, but not prior to the moment the user granted permission. * **Coros:** 3 months into the past, from the current point in time, or 24 hours prior to the user's authentication. Whichever of the two limits gets hit first gets applied * **Health Connect**: 30 days into the past, but not prior to the moment the user granted permission. ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#b.-as-a-pull-down-to-refresh-functionality) b. As a "pull down to refresh" functionality As a **fallback**, you should implement a "pull down to refresh" functionality or alternative (like a sync now button, etc...). Hitting this button should trigger a data pull of the last e.g. 14 days of data for the user, for all the data types you ingest. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#id-2.-request-data-via-the-dashboard) 2\. Request Data via the Dashboard -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- You may want your customer support team to use the Terra dashboard to debug by re-sending data, or verifying whether or not Terra fetches the data correctly. See the guide below for a step by step tutorial on how to do so. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#id-3.-request-data-via-the-api) 3\. Request Data via the API -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- To request historical data from your **Backend,** you need to call one of the [Data Retrieval Endpointsarrow-up-right](https://docs.tryterra.co/reference#historical-data-retrieval) . Refer to the [API endpoints](https://docs.tryterra.co/reference) section for further details on usage. ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#request-usage) Request Usage Refer to the [API endpoints](https://docs.tryterra.co/reference) section for further details on usage. #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#id-1.-required-parameters) **1\. Required Parameters:** To request historical data, the following request parameters are required: * `user_id` (required) * `start_date` (required) #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#id-2.-optional-parameters) **2\. Optional Parameters** Terra's Data Retrieval endpoints include many other useful and important parameters. 1. `with_samples` must be set to `true` to receive granular data (refer to[Integration setup](https://docs.tryterra.co/health-and-fitness-api/integration-setup) ) 2. `to_webhook` must be set to `true` if you want to receive data asynchronously to your Destination. For synchronous data retrieval (if your use case is time-sensitive), just set this parameter to `false`. circle-info ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#to_webhook-will-always-be-defaulted-to-true-if-not-provided) **to\_webhook** will always be defaulted to `true` if not provided circle-exclamation #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#handling-asynchronous-data-retrievals) Handling Asynchronous Data Retrievals * When making a `to_webhook=true` request, keep track of the value of the `terra-reference` header. * When the event is eventually sent to your Data Destination, the event's `terra-signature` will match that of the initial request, allowing you to mark off the data transfer as successfully completed. ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#api-request-example-python) API Request Example (Python) Taking **Python FastAPI** as an example framework, you may set up your server code to look like the following: circle-info #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#handling-asynchronous-data-retrievals-1) Handling asynchronous data retrievals When making a `to_webhook=true` request, keep track of the value of the `terra-reference` header. When the event is eventually sent to your webhook, the event's `terra-reference` will match that of the initial request, allowing you to mark off the data transfer as successfully completed ### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#request-longer-time-ranges) Request longer time ranges Following a large request, you will receive the following: #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#id-1.-large-request-processing-event) **1\. "Large Request Processing" Event** You will immediately receive a [Large request processing](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#large-request-processing) event. This indicates that Terra has acknowledged the large request and is currently processing the data retrieval from the [Provider](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#provider) . #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#id-2.-large-request-sending-event) **2\. "Large Request Sending" Event** Once data retrieval has finished, Terra will organise the data into **chunks**, and send a [Large request sending](https://docs.tryterra.co/reference/health-and-fitness-api/event-types#large-request-sending) payload, indicating **the number of payloads to expect.** #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#id-3.-chunks) **3\. Chunks** When a large request is made, Terra will send the data to you in chunks of: * at most 10MB * at most 10 objects in the `data` array The chunk size will be limited by whichever of the two limits gets hit first. #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#id-4.-header) **4\. Header** **ALL** **chunks** will contain the **same** `terra-reference` header value. Once the number of payloads indicated with the same `terra-reference` header value have been received, you can consider the data transfer request complete. circle-info [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#requests-with-greater-than-28-days-time-ranges) Requests with >28 days Time Ranges ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ For time ranges longer than 28 days, Terra will default to sending the data **asynchronously, even if** `**to_webhook**` **is set to** `**false**`. This is due to the large amounts of data being transferred, which would hang the request making/handling process for >30 seconds. [PreviousReceiving health data updates (events)chevron-left](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates) [NextWriting datachevron-right](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/write-data) Last updated 5 months ago Was this helpful? * [Overview](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#overview) * [1\. When to request historical data?](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#id-1.-when-to-request-historical-data) * [a. Upon creating a New User](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#a.-upon-creating-a-new-user) * [b. As a "pull down to refresh" functionality](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#b.-as-a-pull-down-to-refresh-functionality) * [2\. Request Data via the Dashboard](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#id-2.-request-data-via-the-dashboard) * [3\. Request Data via the API](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#id-3.-request-data-via-the-api) * [Request Usage](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#request-usage) * [API Request Example (Python)](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#api-request-example-python) * [Request longer time ranges](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data#request-longer-time-ranges) Was this helpful? sun-brightdesktopmoon Python Copy @app.post("/webhook") async def webhook_handler(request: Request): payload = await request.json() if payload.get("type") == "auth" and payload.get("status") == "success": # Calculate date range, to get data from 28 days ago to today start_date = (datetime.utcnow() - timedelta(days=28)).strftime('%Y-%m-%d') end_date = (datetime.utcnow() + timedelta(days=1)).strftime('%Y-%m-%d') headers = { "x-api-key": os.getenv("TERRA_API_KEY"), "dev-id": os.getenv("TERRA_DEVELOPER_ID") } endpoints = [\ "/activity", \ "/daily", \ "/sleep", \ "/body"\ ] # Fetch data from each endpoint results = {} for endpoint in endpoints: try: response = requests.get( f"{TERRA_API_URL}{endpoint}", headers=headers, params={ "start_date": start_date, "end_date": end_date, "to_webhook": True } ) response.raise_for_status() results[endpoint] = response.json() except requests.HTTPError as e: raise HTTPException(status_code=response.status_code, detail=f"Error fetching data from {endpoint}") return {"message": "Data fetched successfully", "data": results} return {"message": "Webhook type or status did not match criteria"} sun-brightdesktopmoon --- # Receiving health data updates (events) | Terra Docs Terra API simplifies health & fitness data syncing: once you connect a user, Terra automatically manages **token** **refreshes**, **authentication** **updates**, and delivers all **health** **and** **fitness** **data** directly to your Webhook/DB as soon as it’s available. Requesting data is not required unless you need to backfill historical data, to debug, or as a fallback. This lets you focus on your app while Terra handles the data flow and reliability. In this section, you will learn about: 1. [**Health Data Events**](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#data-events) **:** sent to your destination when new data is available on the user's account. 2. [**How to test your Destination**arrow-up-right](https://dashboard.tryterra.co/dashboard/generate) **:** Terra sends [events](https://docs.tryterra.co/introduction/core-concepts#event) to your [destination](https://docs.tryterra.co/introduction/core-concepts#destination) , learn how to test this. 3. [**Common errors and troubleshooting**](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#common-errors-and-troubleshooting) **:** when not receiving expected data. circle-check [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#prerequisites) **Prerequisites** ------------------------------------------------------------------------------------------------------------------------------------------------ In order to receive Data as **Events**, you'll need to: 1. [**API Key**:arrow-up-right](https://dashboard.tryterra.co/) Obtain your API Key from your Terra Dashboard 2. [**Destination Configured**:](https://docs.tryterra.co/health-and-fitness-api/integration-setup#set-up-your-data-sources-and-destinations) Set up a data destination where Terra will send event and data updates. 3. [**Data Sources Enabled**:](https://docs.tryterra.co/health-and-fitness-api/integration-setup#set-up-your-data-sources-and-destinations) Enable the specific data sources your app requires (e.g., oura, garmin, etc). 4. **Connected at least a user.** 1. If not, then no worries, you can use the [Payload Simulatorarrow-up-right](https://dashboard.tryterra.co/dashboard/generate) to test sending data to your destination! 2. However, make sure to familiarize yourself with Authentication Events. * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#id-1.-types-of-health-data-events) 1\. Types of Health Data Events ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Whenever a [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) has new data available on the respective platform they use, Terra will send a Data Event to your **Data** **Destination**. Data Events fall under one of the following categories: chevron-right(1) Activity: A tracked workout, with a defined start and end time.[hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#id-1-activity-a-tracked-workout-with-a-defined-start-and-end-time) Unique identifier (per [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) ): `metadata.summary_id` For example, an [End Userarrow-up-right](https://github.com/tryterra/gitbook-docs/blob/master/health-and-fitness-api/broken-reference/README.md) pressing **"start run"** on their watch, going for a 5k run, and pressing **"end run"** See [GET activity](https://docs.tryterra.co/reference#activity) for the full Schema & descriptions of each field chevron-right(2) Daily: the total daily summary of the user's activity up to the point in time of the event[hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#id-2-daily-the-total-daily-summary-of-the-users-activity-up-to-the-point-in-time-of-the-event) Unique identifier (per [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) ): `metadata.start_time` This can be the cumulative number of steps, calories burned, etc. `daily` payloads are always relevant to a given 24 hour period, defined by the `start_time` and `end_time` of the `metadata` key. When parsing, only consider the **date** part of the field, and ignore the time. See [GET daily](https://docs.tryterra.co/reference#daily) for the full Schema & descriptions of each field chevron-right(3) Body: the recorded body metrics for the user for a given day[hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#id-3-body-the-recorded-body-metrics-for-the-user-for-a-given-day) Unique identifier (per [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) ): `metadata.start_time` `body` payloads are always relevant to a given 24 hour period, defined by the `start_time` and `end_time` of the `metadata` key. See [GET body](https://docs.tryterra.co/reference#body) for the full Schema & descriptions of each field chevron-right(4) **Sleep: a** tracked sleep session, with a defined **start** and **end** time.[hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#id-4-sleep-a-tracked-sleep-session-with-a-defined-start-and-end-time) Unique identifier (per [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) ): `metadata.summary_id` This can include time spent in bed while awake, if recorded by the wearable. See [GET sleep](https://docs.tryterra.co/reference#sleep) for the full Schema, example, & descriptions of each field chevron-right(5) Menstruation: menstrual metrics for the user for a given day[hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#id-5-menstruation-menstrual-metrics-for-the-user-for-a-given-day) Unique identifier (per [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) ): `metadata.start_time` E.g. the phase they're currently on, their blood flow for the day, etc. `menstruation` payloads are always relevant to a given 24 hour period, defined by the `start_time` and `end_time` of the `metadata` key. See [GET menstruation](https://docs.tryterra.co/reference#menstruation) for the full Schema, example, & descriptions of each field chevron-right(6) Planned Workout: a step by step workout plan for the [end user](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#end-user) [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#id-6-planned-workout-a-step-by-step-workout-plan-for-the-end-user) Unique identifier (per [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) ): `metadata.summary_id` A planned workout, with a defined set of steps/reps/sets to be followed. For example, 15 min running at 7:00 pace, followed by 3x repetitions of 100m sprints with 45s jog at 8:00 min pace in between. See [here](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/write-data#writing-planned-workouts) for more info You can find more details about these **Data Events** in the [Event Type](https://docs.tryterra.co/reference/health-and-fitness-api/event-types) reference. You can find all your received events (payloads) in: * Your [Terra Dashboard > Payload Historyarrow-up-right](https://dashboard.tryterra.co/dashboard/debug) . circle-exclamation #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#overwriting-updating-data) Overwriting/Updating data * Whenever you receive an event for a [User](https://docs.tryterra.co/reference/health-and-fitness-api/core-concepts#user) which constitutes a duplicate, based on the data type's unique identifier (detailed in each section below), the received data will always be a **superset** of any previous data received. * This means you should always **overwrite** data stored on your end with the most up-to-date version. * Depending on the event type, use the **unique** **identifier** for each payload to overwrite data appropriately upon receiving an update (e.g. `metadata.start_date`, `metadata.summary_id`, etc). These **unique** **identifiers** are found in the category descriptions listed above. #### [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#example-of-a-health-and-fitness-payload) **Example of a Health & Fitness Payload** Data Events will take the following form: [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#id-2.-how-to-test-your-destination) 2\. How to test your Destination? ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- For testing out the different event types mentioned above, you may also use [the payload simulatorarrow-up-right](https://dashboard.tryterra.co/dashboard/generate) in the Terra Dashboard. See the tutorial below for a step by step guide. [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#id-3.-faq-common-errors-and-troubleshooting) 3\. FAQ: Common errors & troubleshooting ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Found in [**Debugging FAQ.**arrow-up-right](https://app.gitbook.com/o/FSHKsjH8Q1Ejnax0ajY6/s/VGMJVuZnZyOtvV4b53cY/~/changes/96/debugging-faq) * * * [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#checklist) ✅ Checklist -------------------------------------------------------------------------------------------------------------------------------------- circle-check [hashtag](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#receiving-data-updates) Receiving data Updates -------------------------------------------------------------------------------------------------------------------------------------------------------------- 1. **Set-up**: Have you tested that your destination can receive data payloads from Terra? 2. **Connect a User**: Have you connect a user via Terra? Have you received an Authentication Event? 3. **Receiving** **Data**: After completing an event (e.g. activity), did you receive a Data Event "Activity"? If you didn't receive an expected payload after a long time, please refer to our [**Debugging FAQ**arrow-up-right](https://app.gitbook.com/o/FSHKsjH8Q1Ejnax0ajY6/s/VGMJVuZnZyOtvV4b53cY/~/changes/96/debugging-faq) to ensure the user's data is synced properly. [PreviousManaging user health datachevron-left](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data) [NextRequesting historical health data (REST API requests)chevron-right](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/requesting-historical-data) Last updated 8 months ago Was this helpful? * [1\. Types of Health Data Events](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#id-1.-types-of-health-data-events) * [2\. How to test your Destination?](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#id-2.-how-to-test-your-destination) * [3\. FAQ: Common errors & troubleshooting](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#id-3.-faq-common-errors-and-troubleshooting) * [✅ Checklist](https://docs.tryterra.co/health-and-fitness-api/managing-user-health-data/receiving-data-updates#checklist) Was this helpful? sun-brightdesktopmoon ActivityPayload.json Copy { "type": "activity", "data": [\ {\ "metadata": {\ "type": 45,\ "start_time": "2024-10-03T18:17:45.000000+08:00",\ "city": null,\ "name": "MEDITATION",\ "state": null,\ "upload_type": 1,\ "country": null,\ "summary_id": "f09554ca56fde426de5d7f9c34fc0e1e3ff015c2ae253b39",\ "end_time": "2024-10-03T18:38:39.000000+08:00"\ },\ ..... ommitted for brevity\ }\ ], "user": { "reference_id": "2397", "active": true, "user_id": "9d5dc9eb-3e02-4b37-9a7b-b14b5a5a2b93", "last_webhook_update": "2024-10-03T11:13:43.360227+00:00", "created_at": null, "scopes": "fitness.sleep.read,fitness.body.read,fitness.body_temperature.read,fitness.activity.read,fitness.blood_pressure.read,fitness.location.read,calendar.settings.readonly,fitness.reproductive_health.read,userinfo.email,user.birthday.read,user.gender.read,fitness.oxygen_saturation.read,fitness.heart_rate.read,userinfo.profile,fitness.nutrition.read,fitness.blood_glucose.read", "provider": "GOOGLE" }, "version": "2022-03-16" } sun-brightdesktopmoon --- # Android | Terra Docs [hashtag](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#prerequisites) Prerequisites ------------------------------------------------------------------------------------------------------------------ Ensure you have the following before you begin: 1. **Android Studio**: The latest stable version. 2. **Terra Account**: Access to your Terra Developer account and API key. 3. **Gradle Dependency**: Ensure you include the TerraRT SDK in your project by adding the necessary dependencies. Copy implementation 'co.tryterra:terra-rtandroid:X.X.X' based on [the latest version on maven centralarrow-up-right](https://central.sonatype.com/artifact/co.tryterra/terra-rtandroid/0.4.1) [hashtag](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#sdk-initialization) SDK Initialization ---------------------------------------------------------------------------------------------------------------------------- circle-info Always initialize the `TerraRT` class to begin using the SDK. Do so every time the app is opened or brought into the foreground. To do this, run the TerraRT manager initialization function as below: Copy import android.app.Activity import android.content.Context import com.terra.TerraRT class MainActivity : Activity() { private lateinit var terraRT: TerraRT override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Replace with your actual developer ID and reference ID val developerId = "yourDeveloperId" val referenceId: String? = "yourReferenceId" // Initialize TerraRT SDK terraRT = TerraRT(devId = developerId, context = this, referenceId = referenceId) { success -> if (success) { println("TerraRT initialized successfully") // Proceed with other setup tasks } else { println("Failed to initialize TerraRT") // Handle failure case } } } } [hashtag](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#initializing-a-connection) **Initializing a Connection** ---------------------------------------------------------------------------------------------------------------------------------------------- Register the [phone](https://docs.tryterra.co/reference/streaming-api/core-concepts#phone) by calling [`initConnection`](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#initconnection) . This connects the [phone](https://docs.tryterra.co/reference/streaming-api/core-concepts#phone) to Terra, allows you to use other SDK functions, and allows it to be a [producer](https://docs.tryterra.co/reference/streaming-api/core-concepts#producer) once a [device](https://docs.tryterra.co/reference/streaming-api/core-concepts#device) is connected later on. Use the [terraRT instance created above](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#sdk-initialization) and call initConnection as below using an **authentication token**. To generate the **token**, make the below call **from your backend** Error while loading OpenAPI operation — Failed to fetch OpenAPI file [hashtag](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#device-connection-management) Device Connection Management ------------------------------------------------------------------------------------------------------------------------------------------------ Once initialized, you can scan for devices and connect to them using the TerraRT SDK. You can scan for devices using * BLE * ANT+ (if supported by the Android phone used) #### [hashtag](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#start-device-scan) Start Device Scan You can start scanning for devices and allow the user to connect to a wearable device using [startDeviceScan](https://docs.tryterra.co/reference/streaming-api/reference/android-kotlin#startdevicescan) . You can choose whether to use cached devices (ones you've connected to before) or show a connection widget if no cached device is found. ### [hashtag](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#real-time-data-streaming) Real-Time Data Streaming Once the device is connected, you can start streaming real-time data such as heart rate, steps, and more. circle-info Receiving a real time data stream depends on the [device](https://docs.tryterra.co/reference/streaming-api/core-concepts#device) being configured to broadcast the data it is collecting through BLE or ANT+ #### [hashtag](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#start-real-time-streaming) Start Real-Time Streaming #### [hashtag](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#stop-real-time-streaming) Stop Real-Time Streaming To stop real-time streaming for the connected device, use the following method: This stops data streaming for the specified connection type. #### [hashtag](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#disconnect-device) Disconnect Device To disconnect a connected device: This disconnects the BLE device or any specified connection type. ### [hashtag](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#example-usage) Example Usage #### [hashtag](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#full-example-managing-a-ble-connection-and-streaming-data) Full Example: Managing a BLE Connection and Streaming Data #### [hashtag](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#explanation) Explanation: 1. **Initialization**: The SDK is initialized using an authentication token. 2. **Device Connection**: A BLE device is scanned and connected. 3. **Real-Time Streaming**: Heart rate and steps data are streamed in real-time. 4. **Stop Streaming**: After a delay of 5 seconds, the stream is stopped, and the device is disconnected. [PreviousiOS (Swift)chevron-left](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/ios-swift) [NextYour app -> Terrachevron-right](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra) Last updated 11 months ago Was this helpful? * [Prerequisites](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#prerequisites) * [SDK Initialization](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#sdk-initialization) * [Initializing a Connection](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#initializing-a-connection) * [Device Connection Management](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#device-connection-management) * [Real-Time Data Streaming](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#real-time-data-streaming) * [Example Usage](https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/android#example-usage) Was this helpful? sun-brightdesktopmoon Copy import com.terra.sdk.TerraRT val terraRT = TerraRT() val token = "yourAuthToken" // Replace with your actual token // Initialize TerraRT SDK connection terraRT.initConnection(token) { success -> if (success) { println("TerraRT initialized successfully!") } else { println("Failed to initialize TerraRT.") } } Copy // Start device scan terraRT.startDeviceScan(type = Connections.BLE) { success -> if (success) { println("Device connected successfully!") } else { println("Failed to connect to the device.") } } Copy import com.terra.sdk.DataTypes val dataTypes: Set = setOf(DataTypes.HEART_RATE, DataTypes.STEPS) terraRT.startRealtime(type = Connections.BLE, dataTypes = dataTypes) { update -> handleUpdate(update) } Copy kotlinCopy codeterraRT.stopRealtime(type = Connections.BLE) Copy terraRT.disconnect(type = Connections.BLE) Copy kotlinCopy codeimport com.terra.sdk.TerraRT import com.terra.sdk.Connections import com.terra.sdk.DataTypes import com.terra.sdk.Update val terraRT = TerraRT() val token = "yourAuthToken" // Replace with your actual token // Initialize TerraRT SDK connection terraRT.initConnection(token) { success -> if (success) { println("TerraRT initialized successfully!") // Start device scan for BLE connection terraRT.startDeviceScan(type = Connections.BLE) { scanSuccess -> if (scanSuccess) { println("Device connected successfully!") // Start streaming real-time data val dataTypes: Set = setOf(DataTypes.HEART_RATE, DataTypes.STEPS) terraRT.startRealtime(type = Connections.BLE, dataTypes = dataTypes) { update -> handleUpdate(update) } // Stop streaming after 5 seconds for demo purposes android.os.Handler(Looper.getMainLooper()).postDelayed({ terraRT.stopRealtime(type = Connections.BLE) println("Real-time streaming stopped.") // Optionally disconnect the device terraRT.disconnect(type = Connections.BLE) println("Device disconnected.") }, 5000) } else { println("Failed to connect to the device.") } } } else { println("Failed to initialize TerraRT.") } } fun handleUpdate(update: Update) { println("Received update at timestamp: ${update.ts}") println("Update type: ${update.type}") update.val?.let { value -> println("Value: $value") } } sun-brightdesktopmoon --- # API Endpoints | API Reference | Terra Docs [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#authentication) Authentication -------------------------------------------------------------------------------------------------------- [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#integrations) Integrations ---------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-integrations-detailed) Get detailed information about available integrations get https://api.tryterra.co/v2/teams/integrations/detailed Returns detailed information about available providers, including required login fields and logos. Responses chevron-right 200 Integrations retrieved successfully. application/json Responseobject Show propertiesplus get /integrations/detailed HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Integrations retrieved successfully. [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#coach-management) Coach management ------------------------------------------------------------------------------------------------------------ ### [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-coaches) List all coaches get https://api.tryterra.co/v2/teams/coaches Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Responses chevron-right 200 A list of coaches application/json Responseobject Show propertiesplus get /coaches HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 A list of coaches ### [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#post-coaches) Create a new coach post https://api.tryterra.co/v2/teams/coaches Registers a new coach with credentials and integration specifics. Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Body application/jsonchevron-down application/json coach\_idstringRead-onlyOptional Unique identifier for the coach, generated by the server. external\_coach\_idstringRead-onlyOptional Identifier of the coach on the provider's systems reference\_idstringOptional ID of the coach on your system regionstringOptional Region in which the coach operates. providerstringOptional Integration provider associated with the coach (e.g., VALD, Catapult). created\_atstring · date-timeOptional The date and time when the coach was registered. client\_idstringWrite-onlyOptional Public identifier for the coach. client\_secretstringWrite-onlyOptional Secret key or token for authentication. tokenstringWrite-onlyOptional API key or token for the coach object Responses chevron-right 201 Coach created successfully application/json chevron-right 400 Invalid input, object invalid chevron-right 409 The coach already exists for your dev-id post /coaches HTTPchevron-down HTTPcURLJavaScriptPython Test it 201 Coach created successfully chevron-down ### [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#delete-coaches-coachid) Delete a coach delete https://api.tryterra.co/v2/teams/coaches/{coachId} Deletes a coach and all associated athletes, activities, and tests. Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Path parameters coachIdstringRequired Unique identifier of the coach to be deleted. Responses chevron-right 204 Coach deleted successfully. chevron-right 404 Coach not found. application/json delete /coaches/{coachId} HTTPchevron-down HTTPcURLJavaScriptPython Test it 204 Coach deleted successfully. chevron-down No content [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#coach-data-retrieval) Coach Data retrieval -------------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-coaches-coachid-athletes) Retrieve all athletes under a specific coach get https://api.tryterra.co/v2/teams/coaches/{coachId}/athletes Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Path parameters coachIdstringRequired Responses chevron-right 200 An array of athletes coached by the specified coach application/json Responseall of Show propertiesplus get /coaches/{coachId}/athletes HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 An array of athletes coached by the specified coach ### [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-coaches-coachid-activities) Retrieve all activities recorded by athletes under a specific coach get https://api.tryterra.co/v2/teams/coaches/{coachId}/activities Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Path parameters coachIdstringRequired Query parameters start\_timestring · date-timeOptional end\_timestring · date-timeOptional Responses chevron-right 200 List of activities within the specified time range for all athletes under the coach application/json Responseall of Show propertiesplus get /coaches/{coachId}/activities HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 List of activities within the specified time range for all athletes under the coach ### [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-coaches-coachid-activities-metrics-schema) Retrieve activity metrics schema for a coach get https://api.tryterra.co/v2/teams/coaches/{coachId}/activities/metrics/schema Returns the schema of activity metrics available for the specified coach. Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Path parameters coachIdstringRequired Unique identifier of the coach. Responses chevron-right 200 Schema retrieved successfully. application/json Responseall of Show propertiesplus chevron-right 404 Coach not found. application/json get /coaches/{coachId}/activities/metrics/schema HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Schema retrieved successfully. chevron-down ### [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-coaches-coachid-tests) Retrieve all tests conducted by athletes under a specific coach get https://api.tryterra.co/v2/teams/coaches/{coachId}/tests Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Path parameters coachIdstringRequired Query parameters start\_timestring · date-timeOptional end\_timestring · date-timeOptional Responses chevron-right 200 List of tests within the specified time range for all athletes under the coach application/json Responseall of Show propertiesplus get /coaches/{coachId}/tests HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 List of tests within the specified time range for all athletes under the coach [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#athlete-management) Athlete Management ---------------------------------------------------------------------------------------------------------------- ### [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-athletes) List all athletes get https://api.tryterra.co/v2/teams/athletes Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Responses chevron-right 200 An array of athletes application/json Responseobject Show propertiesplus get /athletes HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 An array of athletes ### [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#patch-athletes-athleteid) Update an athlete's information patch https://api.tryterra.co/v2/teams/athletes/{athleteId} Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Path parameters athleteIdstringRequired Body application/jsonchevron-down application/json coach\_idstringRead-onlyOptional The ID of the coach to which the athlete belongs athlete\_idstringRead-onlyOptional Unique identifier for the athlete, generated by the server. external\_athlete\_idstringRead-onlyOptional Unique identifier for the athlete on the provider's system, generated by the provider (e.g. VALD, Catapult) reference\_idstringOptional A string to reference the Athlete. This can be a UUID, email, or other, and can be used to reconcile the Athlete with your internal systems. providerstringRead-onlyOptional Integration provider associated with the Athlete (e.g., VALD, Catapult). first\_namestringOptional Athlete's first name. last\_namestringOptional Athlete's last name emailstringOptional Athlete's email created\_atstring · date-timeRead-onlyOptional The date and time when the athlete was registered. date\_of\_birthstring · dateOptional The date of birth of the athlete last\_updated\_atstring · date-timeRead-onlyOptional The date and time when the athlete was last updated (e.g. updated their first and last name). activebooleanOptional Determines whether or not Terra will send webhooks for the given athlete Responses chevron-right 200 Athlete updated No content patch /athletes/{athleteId} HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Athlete updated No content ### [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#patch-athletes) Bulk update multiple athletes patch https://api.tryterra.co/v2/teams/athletes Allows a developer to partially update multiple athlete records in a single request. Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Header parameters dev-idstringRequired Your developer ID Example: `testingTerra` x-api-keystringRequired Your API key Example: `OtHJok60oQmT8zhnUWc4SWBJI7ztPTs88C0gOsJJ` Body application/jsonchevron-down application/json dataobject\[\]Required Array of partial athlete objects for update. Show propertiesplus Responses chevron-right 200 All athlete updates were successful. application/json Responseobject Show propertiesplus chevron-right 207 Partial success, some athletes updated while others failed. application/json chevron-right 400 Bad Request. Invalid input or all updates failed due to validation errors. application/json chevron-right 403 Unauthorized. Invalid credentials provided. application/json patch /athletes HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 All athlete updates were successful. chevron-down ### [hashtag](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-athletes-athleteid) Retrieve a specific athlete by their ID get https://api.tryterra.co/v2/teams/athletes/{athleteId} Authorizations apiKeyAuth & devIdAuthchevron-down apiKeyAuth & devIdAuth x-api-keystringRequired dev-idstringRequired Path parameters athleteIdstringRequired Responses chevron-right 200 Detailed information about the athlete application/json Responseobject Show propertiesplus get /athletes/{athleteId} HTTPchevron-down HTTPcURLJavaScriptPython Test it 200 Detailed information about the athlete [PreviousCore Conceptschevron-left](https://docs.tryterra.co/reference/teams-api/core-concepts) [NextEvent typeschevron-right](https://docs.tryterra.co/reference/teams-api/event-types) Last updated 7 months ago Was this helpful? * [Authentication](https://docs.tryterra.co/reference/teams-api/api-endpoints#authentication) * [Integrations](https://docs.tryterra.co/reference/teams-api/api-endpoints#integrations) * [GETGet detailed information about available integrations](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-integrations-detailed) * [Coach management](https://docs.tryterra.co/reference/teams-api/api-endpoints#coach-management) * [GETList all coaches](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-coaches) * [POSTCreate a new coach](https://docs.tryterra.co/reference/teams-api/api-endpoints#post-coaches) * [DELETEDelete a coach](https://docs.tryterra.co/reference/teams-api/api-endpoints#delete-coaches-coachid) * [Coach Data retrieval](https://docs.tryterra.co/reference/teams-api/api-endpoints#coach-data-retrieval) * [GETRetrieve all athletes under a specific coach](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-coaches-coachid-athletes) * [GETRetrieve all activities recorded by athletes under a specific coach](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-coaches-coachid-activities) * [GETRetrieve activity metrics schema for a coach](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-coaches-coachid-activities-metrics-schema) * [GETRetrieve all tests conducted by athletes under a specific coach](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-coaches-coachid-tests) * [Athlete Management](https://docs.tryterra.co/reference/teams-api/api-endpoints#athlete-management) * [GETList all athletes](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-athletes) * [PATCHUpdate an athlete's information](https://docs.tryterra.co/reference/teams-api/api-endpoints#patch-athletes-athleteid) * [PATCHBulk update multiple athletes](https://docs.tryterra.co/reference/teams-api/api-endpoints#patch-athletes) * [GETRetrieve a specific athlete by their ID](https://docs.tryterra.co/reference/teams-api/api-endpoints#get-athletes-athleteid) Was this helpful? sun-brightdesktopmoon Copy GET /v2/teams/integrations/detailed HTTP/1.1 Host: api.tryterra.co Accept: */* Copy { "providers": [\ {\ "provider": "text",\ "name": "text",\ "icon": "text",\ "types": {\ "tests": true,\ "activities": true\ },\ "login_fields": [\ {\ "field": "text",\ "name": "text",\ "type": "text",\ "required": true,\ "options": [\ "text"\ ]\ }\ ]\ }\ ] } Copy GET /v2/teams/coaches HTTP/1.1 Host: api.tryterra.co x-api-key: YOUR_API_KEY dev-id: YOUR_API_KEY Accept: */* Copy { "data": [\ {\ "coach_id": "text",\ "external_coach_id": "text",\ "reference_id": "text",\ "region": "text",\ "provider": "text",\ "created_at": "2026-02-01T14:07:30.153Z"\ }\ ] } Copy POST /v2/teams/coaches HTTP/1.1 Host: api.tryterra.co x-api-key: YOUR_API_KEY dev-id: YOUR_API_KEY Content-Type: application/json Accept: */* Content-Length: 154 { "reference_id": "text", "region": "text", "provider": "text", "created_at": "2026-02-01T14:07:30.153Z", "client_id": "text", "client_secret": "text", "token": "text" } Copy { "coach_id": "text", "external_coach_id": "text", "reference_id": "text", "region": "text", "provider": "text", "created_at": "2026-02-01T14:07:30.153Z" } Copy DELETE /v2/teams/coaches/{coachId} HTTP/1.1 Host: api.tryterra.co x-api-key: YOUR_API_KEY dev-id: YOUR_API_KEY Accept: */* Copy GET /v2/teams/coaches/{coachId}/athletes HTTP/1.1 Host: api.tryterra.co x-api-key: YOUR_API_KEY dev-id: YOUR_API_KEY Accept: */* Copy { "coach": { "coach_id": "text", "external_coach_id": "text", "reference_id": "text", "region": "text", "provider": "text", "created_at": "2026-02-01T14:07:30.153Z" }, "data": [\ {\ "coach_id": "text",\ "athlete_id": "text",\ "external_athlete_id": "text",\ "reference_id": "text",\ "provider": "text",\ "first_name": "text",\ "last_name": "text",\ "email": "text",\ "created_at": "2026-02-01T14:07:30.153Z",\ "date_of_birth": "2026-02-01",\ "last_updated_at": "2026-02-01T14:07:30.153Z",\ "active": true\ }\ ] } Copy GET /v2/teams/coaches/{coachId}/activities HTTP/1.1 Host: api.tryterra.co x-api-key: YOUR_API_KEY dev-id: YOUR_API_KEY Accept: */* Copy { "coach": { "coach_id": "text", "external_coach_id": "text", "reference_id": "text", "region": "text", "provider": "text", "created_at": "2026-02-01T14:07:30.153Z" }, "data": [\ {\ "activity_id": "text",\ "start_timestamp_us": 1,\ "end_timestamp_us": 1,\ "description": "text",\ "teams": [\ {\ "name": "text",\ "is_home": 1\ }\ ],\ "athletes": [\ {\ "coach_id": "text",\ "athlete_id": "text",\ "external_athlete_id": "text",\ "reference_id": "text",\ "provider": "text",\ "first_name": "text",\ "last_name": "text",\ "email": "text",\ "created_at": "2026-02-01T14:07:30.153Z",\ "date_of_birth": "2026-02-01",\ "last_updated_at": "2026-02-01T14:07:30.153Z",\ "active": true\ }\ ],\ "athlete_participation": {\ "full": [\ "text"\ ],\ "partial": [\ "text"\ ],\ "unknown": [\ "text"\ ]\ },\ "tz_offset_seconds": 0,\ "periods": [\ {\ "period_id": "text",\ "name": "text",\ "athlete_participation": {\ "full": [\ "text"\ ],\ "partial": [\ "text"\ ],\ "unknown": [\ "text"\ ]\ },\ "detailed_athlete_participation": [\ {\ "athlete_id": "text",\ "external_athlete_id": "text",\ "is_home_team": 1,\ "participation": 1,\ "function": "text"\ }\ ],\ "start_timestamp_us": 1,\ "end_timestamp_us": 1,\ "athlete_metrics": [\ {\ "athlete_id": "text",\ "metrics": [\ {\ "name": "text",\ "value": 1,\ "unit": "text"\ }\ ]\ }\ ]\ }\ ],\ "activity_metrics": [\ {\ "name": "text",\ "value": 1,\ "unit": "text"\ }\ ],\ "athlete_metrics": {\ "ANY_ADDITIONAL_PROPERTY": [\ {\ "name": "text",\ "value": 1,\ "unit": "text"\ }\ ]\ },\ "events": [\ "text"\ ]\ }\ ] } Copy GET /v2/teams/coaches/{coachId}/activities/metrics/schema HTTP/1.1 Host: api.tryterra.co x-api-key: YOUR_API_KEY dev-id: YOUR_API_KEY Accept: */* Copy { "coach": { "coach_id": "text", "external_coach_id": "text", "reference_id": "text", "region": "text", "provider": "text", "created_at": "2026-02-01T14:07:30.153Z" }, "data": [\ {\ "key": "text",\ "display_name": "text",\ "unit": "text",\ "type": "text",\ "sport": 1\ }\ ] } Copy GET /v2/teams/coaches/{coachId}/tests HTTP/1.1 Host: api.tryterra.co x-api-key: YOUR_API_KEY dev-id: YOUR_API_KEY Accept: */* Copy { "coach": { "coach_id": "text", "external_coach_id": "text", "reference_id": "text", "region": "text", "provider": "text", "created_at": "2026-02-01T14:07:30.153Z" }, "data": [\ {\ "test_id": "text",\ "display_name": "text",\ "timestamp_us": 1,\ "test_type": 1,\ "exercise_type": 1,\ "athlete_weight": 1,\ "movement": 1,\ "tz_offset_seconds": 0,\ "category": 1,\ "duration_us": 1,\ "body_region": 1,\ "position": 1,\ "notes": "text",\ "device": "text",\ "test_result_metrics": [\ {\ "side": 1,\ "aspect": 1,\ "statistic_type": 1,\ "metric_type": 1,\ "contraction_type": 1,\ "value": 1\ }\ ],\ "sets": [\ {\ "metrics": [\ {\ "side": 1,\ "aspect": 1,\ "statistic_type": 1,\ "metric_type": 1,\ "contraction_type": 1,\ "value": 1\ }\ ],\ "timestamp_us": 1,\ "duration_us": 1,\ "side": 0,\ "aspect": -1,\ "reps": [\ {\ "offset_us": 1,\ "duration_us": 1,\ "metrics": [\ {\ "side": 1,\ "aspect": 1,\ "statistic_type": 1,\ "metric_type": 1,\ "contraction_type": 1,\ "value": 1\ }\ ]\ }\ ],\ "weight": 1,\ "exercise_name": "text",\ "variations": [\ null\ ],\ "movement": -1\ }\ ]\ }\ ] } Copy GET /v2/teams/athletes HTTP/1.1 Host: api.tryterra.co x-api-key: YOUR_API_KEY dev-id: YOUR_API_KEY Accept: */* Copy { "data": [\ {\ "coach_id": "text",\ "athlete_id": "text",\ "external_athlete_id": "text",\ "reference_id": "text",\ "provider": "text",\ "first_name": "text",\ "last_name": "text",\ "email": "text",\ "created_at": "2026-02-01T14:07:30.153Z",\ "date_of_birth": "2026-02-01",\ "last_updated_at": "2026-02-01T14:07:30.153Z",\ "active": true\ }\ ] } Copy PATCH /v2/teams/athletes/{athleteId} HTTP/1.1 Host: api.tryterra.co x-api-key: YOUR_API_KEY dev-id: YOUR_API_KEY Content-Type: application/json Accept: */* Content-Length: 120 { "reference_id": "text", "first_name": "text", "last_name": "text", "email": "text", "date_of_birth": "2026-02-01", "active": true } Copy PATCH /v2/teams/athletes HTTP/1.1 Host: api.tryterra.co x-api-key: text dev-id: text Content-Type: application/json Accept: */* Content-Length: 68 { "data": [\ {\ "athlete_id": "text",\ "active": true,\ "reference_id": "text"\ }\ ] } Copy { "data": [\ {\ "coach_id": "text",\ "athlete_id": "text",\ "external_athlete_id": "text",\ "reference_id": "text",\ "provider": "text",\ "first_name": "text",\ "last_name": "text",\ "email": "text",\ "created_at": "2026-02-01T14:07:30.153Z",\ "date_of_birth": "2026-02-01",\ "last_updated_at": "2026-02-01T14:07:30.153Z",\ "active": true\ }\ ], "errors": [\ {\ "athlete_id": "text",\ "error": "text"\ }\ ] } Copy GET /v2/teams/athletes/{athleteId} HTTP/1.1 Host: api.tryterra.co x-api-key: YOUR_API_KEY dev-id: YOUR_API_KEY Accept: */* Copy { "coach_id": "text", "athlete_id": "text", "external_athlete_id": "text", "reference_id": "text", "provider": "text", "first_name": "text", "last_name": "text", "email": "text", "created_at": "2026-02-01T14:07:30.153Z", "date_of_birth": "2026-02-01", "last_updated_at": "2026-02-01T14:07:30.153Z", "active": true } sun-brightdesktopmoon ---