Subscribing to Webhooks¶
Webhook delivery is managed through the Subscription Management API under base path /api/v2. A subscription is the unit of delivery: it ties one or more event types to a single delivery URL with its own signing secret.
Subscription Model¶
Each subscription has:
- A human-readable
name - One or more
event_types(all delivered to the same endpoint) — see Event Types - Its own
notification_url(delivery target) - Its own
signature_key(HMAC secret — shown only at creation and rotation) - An
api_versionpinning the payload format (2026-06-11is current) - An
is_activetoggle
One organisation can hold multiple subscriptions — e.g. one for patient.* events going to your EHR sync, another for appointment.* going to a scheduling integration, each with isolated credentials.
Authentication¶
All /api/v2/* endpoints require a JWT Bearer token:
| Claim | Required | Used for |
|---|---|---|
organisation_id |
Yes | Identifies your organisation |
user_id |
No | Audit logging |
name / user_name |
No | Audit logging |
The first time you call POST /api/v2/subscriptions with a new organisation_id, the organisation is auto-provisioned from the JWT claims — there is no separate registration step.
Subscription Endpoints¶
| Method | Path | Description |
|---|---|---|
POST |
/api/v2/subscriptions |
Create a subscription. Returns signature_key once. |
GET |
/api/v2/subscriptions |
List your subscriptions. Optional ?is_active=true\|false. |
GET |
/api/v2/subscriptions/:id |
Get a single subscription (signature_key hidden). |
PATCH |
/api/v2/subscriptions/:id |
Update name, event_types, notification_url, api_version, or is_active. |
DELETE |
/api/v2/subscriptions/:id |
Delete the subscription. |
POST |
/api/v2/subscriptions/:id/rotate-secret |
Generate a new signature_key. Returned once. |
POST |
/api/v2/subscriptions/:id/test |
Send a synthetic webhook to your notification_url to confirm wiring. |
Create a Subscription¶
Request Body¶
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Human-readable subscription name. Non-empty. |
event_types |
array | Yes | Non-empty array of event types. No duplicates. |
notification_url |
string | Yes | Valid delivery URL. Must use https:// outside of development. |
api_version |
string | No | Payload format version. Defaults to the latest (2026-06-11). Rejected with 400 INVALID_API_VERSION if unknown. |
Request¶
curl --location '{base_url}/api/v2/subscriptions' \
--header 'Authorization: Bearer JWT_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"name": "Patient + appointment webhook",
"event_types": ["patient.created", "patient.updated", "appointment.created"],
"notification_url": "https://example.com/webhooks/spry",
"api_version": "2026-06-11"
}'
Success Response¶
Code: 201 Created
{
"subscription": {
"id": "773aaca1-4e36-4efc-b425-1201341a1712",
"organisation_id": "3533728b-e152-4021-8e35-449adb9c0001",
"name": "Patient + appointment webhook",
"event_types": ["patient.created", "patient.updated", "appointment.created"],
"notification_url": "https://example.com/webhooks/spry",
"api_version": "2026-06-11",
"is_active": true,
"created_at": "2026-06-01T09:26:33.000Z",
"updated_at": "2026-06-01T09:26:33.000Z"
},
"signature_key": "<128 hex chars>",
"message": "Save this signature_key — it is used to verify webhook signatures and will not be shown again. Rotate via POST /subscriptions/:id/rotate-secret."
}
Response Fields¶
| Field | Type | Description |
|---|---|---|
subscription |
object | The created subscription record. |
subscription.id |
string | Subscription identifier — use it on all /subscriptions/:id routes. |
subscription.organisation_id |
string | Owning organisation. |
subscription.name |
string | Subscription name. |
subscription.event_types |
array | Subscribed event types. |
subscription.notification_url |
string | Delivery target. |
subscription.api_version |
string | Pinned payload format version. |
subscription.is_active |
boolean | Whether deliveries are enabled. |
subscription.created_at / updated_at |
string (date) | ISO 8601 timestamps. |
signature_key |
string | HMAC secret for signature verification. Returned only at creation and on rotation — store it immediately. |
message |
string | Reminder that the key will not be shown again. |
Error Response¶
Code: 400 Bad Request
Rotate the Signature Key¶
Generates a new signature_key, returned once in the response. The previous key stops signing immediately — including in-flight retries of earlier events, which are re-signed with the new key on each attempt. Update your endpoint to verify with the new key promptly to avoid rejecting retried deliveries.
Test a Subscription¶
Sends a synthetic webhook to your notification_url, signed with the subscription's current signature_key. The payload envelope includes "test": true so you can ignore test deliveries in production code paths. The response includes the dispatched payload and the HTTP result so you can debug from the API side.
Organisations¶
/api/v2/organisations exposes your organisation profile. Webhook credentials live on subscriptions, not on the organisation.
| Method | Path | Description |
|---|---|---|
GET |
/api/v2/organisations |
Get your organisation's profile. |
PATCH |
/api/v2/organisations |
Update name or is_active. |