Webhooks

Introduction

Webhooks push data to your server automatically whenever new events occur—no polling required. Receive scores, biomarkers, archetypes, insights, and raw data logs in real-time.


Setup

  1. Go to the Sahha Dashboard
  2. Navigate to Webhooks in the sidebar
  3. Add your endpoint URL (must be HTTPS)
  4. Select which event types you want to receive
  5. Copy your secret key for signature verification
Webhooks Secret Key

Testing your endpoint

Use the Send Test Event button in the dashboard to verify your endpoint is receiving and processing webhooks correctly before going live.


Event Types

Event Type Description Schema
ScoreCreatedIntegrationEvent Health score generated (activity, sleep, wellbeing, readiness, etc.) View
BiomarkerCreatedIntegrationEvent Biomarker value calculated (steps, heart rate, sleep duration, etc.) View
ArchetypeCreatedIntegrationEvent Archetype assignment (activity level, sleep pattern, chronotype, etc.) View
DataLogReceivedIntegrationEvent Raw health data received from user's device View

View Event Reference


Delivery

Interval

Scores and biomarkers update throughout the day as new data arrives. To control how frequently you receive these updates, configure the webhook interval in the dashboard.

The interval acts as a deduplication window. When a score or biomarker is delivered, subsequent updates for the same metric and profile are held until the interval expires. If multiple updates occur within the window, only the final value is sent when the interval ends.

Interval Behavior
Real-time Every update delivered immediately
1 min – 720 min Updates batched; final value sent at interval end

Data Logs are always real-time

The delivery interval only applies to scores and biomarkers. Data log events ( DataLogReceivedIntegrationEvent) are always delivered immediately since each log contains new raw data rather than an updated value.

Behavior

Aspect Details
Timeout Sahha waits up to 30 seconds for a response
Success codes 2xx status codes indicate successful delivery
Retries Failed deliveries are retried up to 5 times with exponential backoff
Ordering Events may arrive out of order—use timestamps for sequencing

Handling Requests

Every webhook request includes these headers:

Header Description
X-Signature HMAC-SHA256 hash of the payload using your secret key
X-External-Id The profile's external identifier—use this to associate the event with a user in your system
X-Event-Type The event type string—use this to determine how to parse the payload

Verifying Signatures

To ensure a webhook request is genuinely from Sahha (and not a malicious actor), verify the X-Signature header. Compute an HMAC-SHA256 hash of the raw request body using your secret key, then compare it to the signature in the header. If they match, the request is authentic.

Handler Example

Webhook handler with signature verification
javascript
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.text({ type: '*/*' }));
const SECRET_KEY = process.env.SAHHA_WEBHOOK_SECRET;
app.post('/webhook', (req, res) => {
const signature = req.get('X-Signature');
const externalId = req.get('X-External-Id');
const eventType = req.get('X-Event-Type');
// Validate headers
if (!signature || !externalId || !eventType) {
return res.status(400).json({ error: 'Missing required headers' });
}
// Verify signature
const hmac = crypto.createHmac('sha256', SECRET_KEY);
const computed = hmac.update(req.body).digest('hex');
if (signature.toLowerCase() !== computed.toLowerCase()) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process event (do heavy work async to respond quickly)
const payload = JSON.parse(req.body);
processEventAsync(eventType, externalId, payload);
res.status(200).json({ received: true });
});
app.listen(3000);

Best Practices

  • Always verify signatures — Never process a webhook without validating X-Signature first
  • Respond quickly — Return 200 OK immediately, handle processing asynchronously
  • Handle duplicates — Use the event id field for idempotency in case of retries
  • Use HTTPS — Your endpoint must use TLS encryption
  • Secure your secret — Store in environment variables, never hardcode in your application

Support

Need help? Contact support@sahha.ai or join the Slack Community .

Previous
API
Next
Scores