Skip to content

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_version pinning the payload format (2026-06-11 is current)
  • An is_active toggle

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:

Authorization: Bearer JWT_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

POST /api/v2/subscriptions

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

{ "code": "INVALID_API_VERSION", "message": "Unsupported api_version", "data": null }

Rotate the Signature Key

POST /api/v2/subscriptions/:id/rotate-secret

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

POST /api/v2/subscriptions/:id/test

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.