Webhooks
Webhook
Webhooks are the most basic Destination 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..
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
Payload signing
Every webhook sent by Terra includes an HMAC-based signature header terra-signature, which takes the form:
t=1723808700,v1=a5ee9dba96b4f65aeff6c841aa50121b1f73ec7990d28d53b201523776d4eb00In order to verify the payload, you may use one of Terra's SDKs as follows:
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.
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 (HMAC) with SHA-256. To prevent downgrade attacks, 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_payloadstring
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
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
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.
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.
Terra sends all outbound requests (webhooks, database connections, etc.) from the same set of IPs. See the full IP list on the data destinations overview page.
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), Terra retries the delivery up to 10 times with exponential backoff, starting at 30 seconds between the first and second attempt and approximately doubling between each subsequent attempt. The cumulative window across all retries is ~8 hours.
After the retry budget is exhausted, the event is dropped. There is no notification when this happens, so it's important to monitor your endpoint's health to avoid silent data loss.
Timeout and circuit breaker
Terra waits 8 seconds for your server to respond before considering the request timed out.
When a destination shows a sustained high failure rate, Terra activates a per-destination circuit breaker that briefly pauses delivery. This protects your server from continued load while it's clearly unhealthy and protects Terra's delivery pipeline from spending capacity on requests that are unlikely to succeed.
What trips the circuit:
Client-side timeouts (your server didn't respond within 8 seconds).
HTTP 5xx responses from your server.
HTTP 4xx responses that persist past the third delivery attempt on the same event (
retries >= 2). The first two attempts of any event still treat 4xx as a per-message issue — only sustained 4xx across retries is taken as evidence that the destination itself is misconfigured.
The breaker only fires on unambiguous meltdowns — a destination that is failing the vast majority of recent attempts over a meaningful sample. A handful of failures or a mild degradation (e.g. occasional timeouts) does not trip the circuit; the rest of your traffic flows normally.
While the circuit is open:
Data events for that destination are held back, not attempted, and re-queued with the same exponential backoff used for normal retries.
Each re-queue counts toward the event's 10-retry limit, even though no delivery was attempted. If the destination remains broken across all 10 cycles, the event is dropped without ever reaching your server.
Authentication and de-authentication events still flow during a circuit break. These control-plane events bypass the breaker so your auth/connection lifecycle is never delayed by data-path issues.
Recovery:
The breaker is short-lived and recovers automatically. After a brief pause, Terra cautiously tests the destination with a single request. If your server responds successfully, normal traffic resumes immediately. If it still fails, the pause re-engages. There is no manual action required — the circuit cycles until your destination is healthy or until the events have exhausted their retry budget.
Respond within 8 seconds. If you need more time to process the data, accept the webhook immediately (return 200) and process it asynchronously. A brief timeout episode can cascade into dropped events if the circuit breaker stays open through all 10 retry cycles.
4xx responses on first attempts are safe. Validation errors on a single bad payload (e.g. an unexpected field) are treated as per-message issues. Terra will not penalize your destination for an occasional 4xx — only for persistent 4xx across retries on the same event, which suggests the URL itself is misconfigured.
Monitor for sustained outages. If your destination is down long enough that all 10 retry attempts for a given event are exhausted (~8 hours cumulative), that event is dropped — there's no notification. New events generated after recovery will be delivered normally, but events generated during the outage window can be permanently lost. We recommend setting up endpoint health monitoring on your side to catch extended outages early.
Ping mode (S3 payload delivery)
For high-volume integrations or large payloads, Terra supports a ping mode that keeps webhook payloads small. Instead of sending the full data payload in the POST body, Terra uploads it to cloud storage and sends a lightweight summary with a pre-signed download URL.
When ping mode is enabled, your webhook receives:
url— A pre-signed link to the full data payload, hosted on Terra's infrastructure. Download it with aGETrequest.expires_in— URL validity in seconds (300 = 5 minutes).
How to process ping mode payloads:
Receive the webhook POST as usual and verify the signature.
Check if the
typefield is"s3_payload".Download the full payload from the
urlfield using aGETrequest.Process the downloaded JSON as you would a normal webhook payload.
Authentication and connection events (auth success, deauth, etc.) are always delivered inline in the POST body, even when ping mode is enabled. Only data payloads use the S3 URL delivery.
To enable ping mode, open your webhook destination on the Connections page, set Delivery mode to Ping, and save. It is configured per destination and does not require any changes to your webhook URL. If you do not see a Delivery mode option, contact Terra support and we'll enable it for you.
Last updated
Was this helpful?