Description
StickyHealth can send events to your server as HTTPS POST requests. Today the only event we send is notification.triggered: when your organization has a webhook configured, each notification StickyHealth would send a member arrives at your server instead of as a push notification from us, and you deliver it to the member yourself.
Setting up
Webhooks are not self-serve. To turn them on, email info@stickyhealth.com with your endpoint URL. We configure the endpoint and a signing secret for your organization and share the secret with you securely.
Your endpoint must:
- use
https://(we skip delivery to any other URL) - accept a
POSTwith a JSON body - respond within 10 seconds
Events
| Event | Sent when |
|---|---|
notification.triggered | One of the member's notifications is due, for example a reminder to log a meal. |
More event types may be added later. Ignore types you don't recognize, and still answer them with a 2xx status.
Payload
Every event has the same envelope:
{{code.b0}}| Field | Type | Description |
|---|---|---|
id | string | Unique event id (a UUID). Retries of the same event keep the same id, so use it to drop duplicates. |
type | string | The event type. |
created_at | string | When the event was created, ISO 8601 in UTC. |
external_uid | string | The member's id in your system: the user id (sub) from your sign-in token. If we hold no id from your sign-in for the member, our own member id. |
data | object | Event-specific fields. For notification.triggered: title and body, the text to show the member. |
metadata | object | null | Extra context, or null. For notification.triggered it holds chat_session_id when the notification belongs to a chat session. |
Headers
| Header | Value |
|---|---|
Content-Type | application/json |
X-Miri-Signature | sha256= followed by the hex HMAC-SHA256 of the raw request body, keyed with your signing secret |
X-Miri-Event-Type | The event type, same as type |
X-Miri-Webhook-Id | The event id, same as id |
X-Miri-Delivery-Attempt | 1 for the first attempt, then 2, 3... on retries |
X-Miri-External-Id | The member's id, same as external_uid |
Verifying the signature
Compute the HMAC-SHA256 of the exact bytes you received, keyed with your signing secret, and compare it with the X-Miri-Signature header in constant time. Verify before you parse the JSON: parsing and re-serializing the body changes the bytes, so the signature will not match.
{{code.b1}}Responses and retries
- 2xx: delivered. Respond quickly and do any slow work afterwards.
- 4xx: treated as a permanent rejection. We do not retry.
- 5xx, other statuses, timeouts (10 seconds) and connection errors: we retry. An event gets at most 5 attempts in total: the first, then retries after 30 seconds, 1 minute, 2 minutes and 5 minutes. After the fifth failed attempt the event is dropped.
If your endpoint keeps failing (around 10 server errors, timeouts or connection errors in a row), we pause delivery to it for 5 minutes. Events that come due during the pause are dropped, not queued. After the pause we send one event to test the endpoint, and normal delivery resumes once one succeeds.
Because of retries, the same event can arrive more than once. Use id (or X-Miri-Webhook-Id) to ignore repeats.