The verifier encodes exactly these sentences. Where a vendor’s page leaves something unstated, the block says so rather than filling it in.
Oura
HMAC signatureHMAC-SHA256, keyed by your client secret, over the x-oura-timestamp value followed by JSON.stringify(body); hex, upper-case, in x-oura-signature.
hmac.update(timestamp + JSON.stringify(body));
const calculatedSignature = hmac.digest('hex').toUpperCase();
Oura's sample signs JSON.stringify of the parsed body, not the raw bytes, so this tool re-serializes the body you paste the same way. If Oura's serializer and JavaScript's ever differ (key order, spacing, escaped characters), a genuine request can fail this check; the page says when the raw body would have matched instead.
What to send back
- Respond quickly (under 10 seconds) with a 2xx status, and process the event asynchronously.
- Oura retries failed deliveries 10 times each for 4xx responses, 5xx responses and timeouts, for about an hour.
- A 410 response cancels the subscription.
Handshake: When you create a subscription Oura sends GET <callback>?verification_token=…&challenge=…; check the token and reply with JSON {"challenge": "…"}.
Source: Oura API v2 OpenAPI document (1.43), “Webhooks for Real-Time Data Updates” — read 2026-10-31 (via the site's source-snapshot workflow). Guide: Oura integration guide.
WHOOP
HMAC signatureHMAC-SHA256, keyed by your app's client secret, over the X-WHOOP-Signature-Timestamp value followed by the raw body; base64, in X-WHOOP-Signature.
To verify the signature, first prepend the timestamp header value to the raw http request body. Then, generate a SHA256 HMAC signature of that string using the secret key for your app, which can be found in the WHOOP Developer Dashboard. Finally, base64 encode the result, and compare it to the signature header.
What to send back
- Return a successful 2XX; WHOOP recommends doing so within a second and processing asynchronously.
- WHOOP retries failed deliveries five times over about one hour; anything other than a 2XX, or no response before timing out, counts as failed.
- Duplicates are possible: use trace_id to detect them.
Source: WHOOP Developer Platform, “Webhooks” — read 2026-10-31 (via the site's source-snapshot workflow). Guide: WHOOP integration guide.
Terra
HMAC signatureterra-signature: t=<timestamp>,v1=<signature>. HMAC-SHA256, keyed by the endpoint's signing secret, over timestamp + "." + raw body; compare with every v1 value, ignore other schemes.
The signed_payload string is created by concatenating:
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.
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
What to send back
- Respond with a 2XX within 8 seconds — Terra's own advice is to accept immediately (return 200) and process asynchronously.
- Otherwise Terra retries up to 10 times with exponential backoff, starting at 30 seconds and roughly doubling, across about 8 hours; after that the event is dropped with no notification.
- Terra requires the raw, unaltered body for verification: read it before any JSON parsing.
Source: Terra docs, “Webhooks” (data destinations) — read 2026-10-31 (via the site's source-snapshot workflow). Guide: Terra integration guide.
Polar AccessLink
HMAC signatureHMAC-SHA256 of the payload, keyed by the signature_secret_key returned when you created the webhook; hex, in Polar-Webhook-Signature. Event type in Polar-Webhook-Event.
Hash-based message authentication code (HMAC SHA-256) is used to sign every webhook payload Accesslink sends. The secret key for calculating signature is given to client when they create the webhook.
To verify sender client should calculate HMAC and compare it to the signature in payload header.
Polar's sample returns toHexString(mac.doFinal(data.getBytes())) without saying upper or lower case; its example header is lower-case, and this tool compares hex case-insensitively.
What to send back
- Webhook delivery expects response 200 from the remote endpoint — including the PING sent when the webhook is created or its URL changes, or it is not created/modified.
- A webhook is automatically deactivated if push notifications have not been successful for seven days; re-enable it with the activate webhook endpoint.
Source: Polar AccessLink API v3 reference, “Accesslink webhooks” — read 2026-10-31 (via the site's source-snapshot workflow). Guide: Polar AccessLink integration guide.
Strava
Validation handshake, events unsignedNo signature is documented for event POSTs. Subscription validation is a GET with hub.mode, hub.challenge and hub.verify_token; echo hub.challenge as JSON within two seconds.
The query string of this GET request will contain a "hub.challenge" field that you must use to validate your callback address.
Your callback address must respond within two seconds to the GET request from Strava’s subscription service.
What to send back
- Validation GET: respond within two seconds with status 200 and the hub.challenge echoed in the body as application/json.
- Event POST: acknowledge with 200 OK within two seconds; pushes are retried up to a total of three attempts if a 200 is not returned.
- Strava's webhook page documents no signature header for event POSTs, so an event cannot be authenticated from the request alone.
Source: Strava Developers, “Webhook Events API” — read 2026-10-31 (via the site's source-snapshot workflow). Guide: Strava integration guide.
Withings
Shared token, no signatureNo signature. Withings suggests a secret query parameter on the callback URL you subscribe (its example: ?token=<random-secret>) plus an allowlist of its notification IPs. The body is form-encoded.
When you set the callback URL on your subscription, append a query parameter only you and Withings know. Withings POSTs to this exact URL, so the parameter is delivered with every notification:
Your handler reads token from the incoming request and rejects any value that doesn't match the secret you configured. Combine this with the IP allowlist for defense in depth.
What to send back
- Your endpoint returns HTTP 2xx within a few seconds.
- If it does not return HTTP < 400, Withings retries the same notification in 5 cycles over about 5 hours (+10 s, +1 min, +1 h, +4 h), 2 HTTP attempts each.
- After 20 days of unresolved failures the subscription is auto-cancelled; missed notifications are not redelivered — backfill via the Data API using lastupdate.
Source: Withings developer guide, “Notifications overview” — read 2026-10-31 (via the site's source-snapshot workflow). Guide: Withings integration guide.
Wahoo
Shared token, no signatureNo signature. Wahoo sends the webhook_token you configured inside the JSON body; ignore any request without it.
Specify a token that you would like us to send. Any request that doesn't include this token should be ignored.
What to send back
- Return HTTP 200. Without it Wahoo retries after 30 minutes, 4 hours, 24 hours and 72 hours.
- Wahoo's page states no response time limit.
- Duplicate webhooks are possible when files are updated or deleted, and the user's token needs the offline_data scope.
Source: Wahoo Cloud API documentation, “Webhooks” — read 2026-10-31 (via the site's source-snapshot workflow). Guide: Wahoo integration guide.
Google Health API
Shared token, no signatureThe documented check is the Authorization header: Google sends the endpointAuthorization secret you configured with every notification. A GOOGLE-HEALTH-API-SIGNATURE header appears in Google's examples, but the page does not say how it is computed, so this tool does not check it.
The value of secret is sent in the Authorization header with each notification message. You can use this token to verify that incoming requests are from the Google Health API.
What to send back
- Validate the Authorization header and respond to data change notifications with HTTP 204 No Content immediately; process the payload asynchronously.
- Any other status code, or a timeout, and the Google Health API retries later — so make handling idempotent.
- Verification handshake (on subscriber create or endpoint update): two POSTs with body {"type": "verification"}; answer the one carrying your Authorization header with 200 or 201, and the one without credentials with 401 or 403.
Source: Google Health API, “Webhook subscriptions” — read 2026-10-31. Guide: Google Health API reference.