Webhooks
Artery webhooks let your server receive real-time push notifications whenever new health data is ingested for one of your users. Register an endpoint and subscribe it to data type slugs — your server is called automatically whenever matching data arrives.
Registering a Webhook
Webhook endpoints are registered and managed from the Artery dashboard. Each endpoint subscribes to one or more data type slugs (e.g. steps, heart_rate, sleep_session). A delivery is triggered whenever a health event of a subscribed type is ingested for one of your users.
One endpoint per data category per environment. The platform enforces a limit of one active webhook endpoint per data category (Activity, Vitals, Sleep) per environment (sandbox / production).
Payload Structure
Webhook requests are HTTP POST with a JSON body. Multiple events may be batched into a single delivery.
{
"events": [
{
"eventId": "550e8400-e29b-41d4-a716-446655440000",
"dedupeHash": "abc123hash",
"userId": "hashed-user-id",
"dataType": "steps",
"source": "apple_health",
"value": 1000,
"unit": "count",
"startDate": "2024-01-15T08:00:00+00:00",
"endDate": "2024-01-15T09:00:00+00:00",
"recordedAt": "2024-01-15T10:30:00+00:00"
}
]
}Verifying Signatures
Every request includes an X-Artery-Signature header in the format sha256=<hmac-sha256-hex>. Always verify this before processing the payload — reject requests that fail.
The signature is an HMAC-SHA256 of the raw request body (UTF-8). The signing secret is a 64-character hex string — decode it from hex before use:
import { createHmac, timingSafeEqual } from 'crypto';
function verifyWebhookSignature(rawBody, signature, signingSecret) {
const key = Buffer.from(signingSecret, 'hex');
const expected = 'sha256=' + createHmac('sha256', key)
.update(rawBody, 'utf8')
.digest('hex');
return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
app.post('/webhook/artery', (req, res) => {
if (!verifyWebhookSignature(req.rawBody, req.headers['x-artery-signature'], process.env.ARTERY_SIGNING_SECRET)) {
return res.status(401).end();
}
res.status(200).end(); // Acknowledge within 10 seconds
processEvents(req.body.events).catch(console.error);
});Reliability
Your endpoint must return a 2xx status within 10 seconds. Acknowledge immediately and process events asynchronously to avoid timeouts.
Use eventId or dedupeHash to handle duplicate deliveries safely — the platform guarantees at-least-once delivery.
Retry Policy
Failed deliveries are retried with exponential backoff. After 11 failed attempts the message is permanently abandoned.
| Attempt | Delay after previous |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 6 hours |
| 7–11 | 24 hours each |