Scores and metrics are computed continuously as data arrives. The last piece of the pipeline is getting that data to you. Sonar provides two delivery mechanisms — an Events API you poll on your schedule, and Webhooks that push to you in real time. Use either or both, depending on your architecture.
Events are notifications, not data payloads. They tell you what changed and for whom — you then query the REST API to fetch the actual values. This keeps event payloads small and predictable, while the API gives you full control over what data you pull and in what format.
Delivery Methods
Events API (Pull)
A poll-able events log with cursor-based pagination. Call the events endpoint with your last cursor to get everything that happened since — no data is lost, and you control the cadence.
Best for: Backend services, batch processing, catching up after downtime.
GET /v1/events?cursor=evt_01HX3K...&limit=100
You can also filter by user to only receive events for a specific user:
GET /v1/events?cursor=evt_01HX3K...&user_id=usr_abc123&limit=100
{
"events": [
{
"event_id": "evt_01HX4M9ABC",
"event_type": "data.updated",
"metrics": ["resting_heart_rate", "heart_rate_variability", "steps"],
"user_id": "usr_abc123",
"device_id": "dev_garmin_456",
"timestamp": "2026-03-01T14:22:00Z"
},
{
"event_id": "evt_01HX4M9ABD",
"event_type": "score.updated",
"scores": ["recovery_score", "sleep_score"],
"user_id": "usr_abc123",
"timestamp": "2026-03-01T14:23:12Z"
}
],
"cursor": "evt_01HX4M9ABD",
"has_more": true
}
Start with cursor omitted to read from the beginning. Store the returned cursor and pass it on the next call — Sonar keeps your position in the log. The has_more flag tells you whether additional pages are available.
Webhooks (Push)
Real-time HTTP POST notifications to your endpoint. Sonar fires a webhook whenever health data updates, scores recompute, or devices connect or disconnect — typically within seconds of the underlying event.
Best for: Real-time UIs, alerting systems, low-latency workflows.
{
"webhook_id": "whk_01HX4N2DEF",
"event_type": "score.updated",
"scores": ["recovery_score"],
"user_id": "usr_abc123",
"timestamp": "2026-03-01T14:23:12Z"
}
Register your endpoint URL in the Dashboard or via the API. You can subscribe to specific event types — for example, only score.updated — so your endpoint only receives what it needs.
Our Recommendation
Use both mechanisms together. Webhooks give you real-time responsiveness — push a score update to your UI the moment it happens. The Events API gives you reliability — poll periodically to catch anything your webhook handler might have missed during a deployment, network blip, or endpoint downtime.
A typical integration looks like:
- Webhooks trigger real-time UI refreshes and push notifications.
- Events API runs on a scheduled job (every 5–15 minutes) to reconcile and ensure nothing was dropped.
- When your webhook handler receives an event, it calls the REST API to fetch the actual data — the metrics, scores, or device details referenced in the notification.
This gives you the speed of push delivery with the durability guarantees of a persistent event log.
Event Types
Each event tells you what changed so you know which API endpoint to query for the full data.
| Event | Fires when |
|---|---|
data.updated |
New health data synced — includes metrics list and device_id |
score.updated |
Health scores recomputed — includes which scores changed |
device.connected |
User connected a new device — includes device_id and provider |
device.disconnected |
User disconnected a device — includes device_id and provider |
Event granularity. When a device syncs, Sonar emits a single data.updated event per user containing all affected metrics — not one event per metric. A Garmin sync that delivers heart rate, HRV, and steps produces one data.updated with "metrics": ["resting_heart_rate", "heart_rate_variability", "steps"]. Score recomputations triggered by that same sync produce a separate score.updated event listing all affected scores.
Webhook Security
Every webhook request includes a signature in the X-Sonar-Signature header, computed as an HMAC-SHA256 hash of the request body using your webhook signing secret. Always verify this signature before processing a webhook — it confirms the request came from Sonar and hasn't been tampered with.
X-Sonar-Signature: sha256=a1b2c3d4e5f6...
Your signing secret is generated when you register a webhook endpoint and is available in the Dashboard. Rotate it at any time — Sonar will start signing with the new secret immediately.
Reliability & Guarantees
Event Retention
Events are retained in the log for 30 days. As long as you poll at least once within that window, you won't miss anything. For most integrations polling every 5–15 minutes, retention is never a concern.
Webhook Retries
If your endpoint returns a non-2xx status code or doesn't respond within 15 seconds, Sonar retries with exponential backoff — up to 8 attempts over approximately 24 hours (delays of ~10s, 30s, 1m, 5m, 15m, 1h, 4h, 12h). After all retries are exhausted, the event is marked as failed and remains available through the Events API.
Ordering
Events are delivered in chronological order within the Events API. Webhooks are dispatched in order but may arrive out of order due to network conditions or retry scheduling — use the timestamp field to reconcile if ordering matters to your application.
Idempotency
Webhook deliveries may be duplicated in rare cases (e.g., your endpoint times out after processing but before responding). Design your handler to be idempotent — the event_id (Events API) or webhook_id (Webhooks) is stable and safe to use as a deduplication key.
Comparison
| Events API | Webhooks | |
|---|---|---|
| Delivery | Pull (you poll) | Push (HTTP POST) |
| Latency | Your poll interval | Seconds |
| Reliability | Cursor-based, 30-day retention | 8 attempts over ~24 hours |
| Ordering | Guaranteed chronological | Best-effort |
| Security | API key authentication | HMAC-SHA256 signature |
| Setup | None — call the endpoint | Register URL + signing secret |
| Best for | Backend processing, reconciliation | Real-time UIs, alerting |
Frequently Asked Questions
How do I get the actual data after receiving an event?
Events are notifications — they tell you what changed, not the values themselves. Use the metrics or scores field to know which REST API endpoint to call. For example, a data.updated event with "metrics": ["resting_heart_rate"] means you should query GET /v1/users/{user_id}/daily?metrics=resting_heart_rate to fetch the new value.
What happens if my webhook endpoint is down? Sonar retries with exponential backoff — up to 8 attempts over ~24 hours. If all retries fail, the event stays in the events log. This is why we recommend running a periodic Events API poll alongside webhooks — it acts as a safety net.
Are there rate limits on the Events API? Yes — the Events API follows the same rate limits as the rest of the Sonar API. See API Conventions for current limits. For most integrations, polling every 5–15 minutes stays well within bounds.
Can I filter which events I receive?
Yes. Both the Events API and webhook subscriptions support filtering by event type, and the Events API also supports filtering by user_id. Subscribe your webhook only to score.updated, or poll the Events API for a specific user's data.updated events — you control what you process.
Go Deeper
- API Conventions — Authentication, rate limits, and cursor-based pagination
- Authentication — Token types, scopes, and security
Sonar