Signals webhooks
Receive Signals alerts, episodes, readings and patient changes as signed webhooks: subscribers, events, reach, signatures and redelivery.
Signals can push events to your system instead of you polling GET /alert. A subscriber is a Signals client with a webhook URL and a list of events. Signals manages the deliveries; Ovok exposes the routes to create and run subscribers, and holds their credentials.
Every route on this page needs a Manager application or a user with the capabilities shown.
| Task | Route | Capabilities |
|---|---|---|
| Create a subscriber | POST /v1/signals/api/user | signals_webhooks:update, signals_events:read |
| Change its URL, events or reach | POST /v1/signals/api/user/:id | signals_webhooks:update, signals_events:read |
| Delete it | DELETE /v1/signals/api/user/:id | signals_webhooks:delete |
| Check its endpoint | GET /v1/signals/api/subscriber/:id/webhook | signals_webhooks:read |
| Send a test event | POST .../webhook/test | signals_webhooks:update |
| Turn it off or on | POST .../webhook/disable, .../enable | signals_webhooks:update |
| Rotate its signing secret | POST .../webhook/rotate-secret | signals_webhooks:update |
| See what was sent | GET /v1/signals/api/events, .../events/:id/attempts | signals_events:read |
| Send events again | POST /v1/signals/api/events/redeliver, .../events/:id/redeliver | signals_webhooks:update |
Create a subscriber
curl --request POST 'https://api.sandbox.ovok.com/v1/signals/api/user' \
--user "${OVOK_MANAGER_ID}:${OVOK_MANAGER_SECRET}" \
--header 'Content-Type: application/json' \
--data '{
"role": "SUBSCRIBER",
"name": "Ward alerts",
"webhookUrl": "https://example.com/signals/webhook",
"events": ["alert.*"],
"reach": "all"
}'- Add
episode.*only once your tenant hasepisodicAlertson; until then it answers403FEATURE_DISABLED(see Events). - Send
role: "SUBSCRIBER". Through Ovok, only subscribers are created; any other role answers403. - Don't send
clientId,secretorwebhookSecret. Ovok generates the subscriber's id and Signals login, which it never uses, and answers422if you send them. - Subscribers are on event schema 2. Sending another
eventSchemaanswers422. - The answer carries
signingSecretonce. Store it: you need it to verify deliveries, and you get a new one only by rotating it. Locationnames the new subscriber under/v1/signals/api/user/:id.
A create retried after a timeout can make a second subscriber. List them with GET /v1/signals/api/user and delete the extra one.
Reach: which patients it hears about
reach | Patients |
|---|---|
attached (default) | Only the patients attached to it. Attach them with POST /v1/signals/api/subscriber/:id/patients. |
all | Every patient of your tenant, including patients enrolled later. |
Events
Name exact events, or a whole family with a wildcard such as alert.*.
| Event | When |
|---|---|
alert.triggered | A reading breaches a trigger and opens an alert. |
alert.refired | Another breach refreshes an open alert. |
alert.resolved | A trigger resolves the alert. |
alert.acknowledged | Someone acknowledges the alert. |
alert.empty, alert.note, alert.inactive | An empty reading, a note, or a patient going quiet raises an alert. |
episode.opened, episode.closed | An episode starts or ends. |
observation.created, observation.updated | A reading is stored or changed. One delivery per reading: subscribe only if you need them. |
patient.subscribed, patient.unsubscribed | A patient is attached to or detached from the subscriber. |
patient.config, patient.inactive | A patient's config changes, or the patient goes inactive. |
webhook.test | You sent a test event. It is not queued, retried or listed. |
webhook.disabled | Signals turned another subscriber's endpoint off because it answered 410 or kept failing. You are never told about your own. |
Readings posted with Prefer: respond-sync report their alerts in the answer, and send no webhook for them.
Episode events need episodes. Signals records episodes only while your tenant has episodicAlerts on. Naming an episode event while it is off answers 403 FEATURE_DISABLED. Turn it on with PATCH /v1/signals/api/tenant and {"settings":{"episodicAlerts":true}}.
Verify each delivery
Deliveries follow Standard Webhooks. Each one carries webhook-id, webhook-timestamp and webhook-signature; verify them with a Standard Webhooks library and the subscriber's signingSecret (whsec_…). The body is one JSON event with its type, its data and when it happened. If you set custom, every delivery carries it back as x-actimi-custom.
Answer 2xx quickly and do the work afterwards. A delivery that fails is retried.
Rotating the secret. rotate-secret returns the new secret once. The old one keeps signing for 24 hours, so webhook-signature carries both and you can switch with no gap. Rotate again only after your receiver uses the new secret.
When deliveries fail
| Situation | What happens |
|---|---|
| Recent attempts failed | The endpoint is failing. Signals keeps retrying. |
| Five days of failures with no delivery | Signals turns the endpoint off (disabledReason: failing). |
Your endpoint answers 410 Gone | Signals turns it off at once (disabledReason: gone). |
| You disabled it | Nothing is sent (disabledReason: manual). |
While an endpoint is off, new events are held, not dropped. Ovok tells your project's admins when Signals turns one off. After you fix the receiver, enable it, then send the held events with POST /v1/signals/api/events/redeliver?status=held&since=<ISO 8601 time>. since is required; the call answers 202 with how many it queued, at most 1,000 at a time. Enabling alone re-queues nothing.
GET /v1/signals/api/events lists every event with how its delivery went. It pages oldest first, and can lag a little behind the newest deliveries.
Related
Last updated on
Signals standalone
Use Signals' own API through Ovok at /v1/signals/api: app types, authentication, what Ovok adds to each call, and a first patient, reading and alert.
List alerts, or the episodes they were folded into
List alerts, or the episodes they were folded into, through Ovok's Signals gateway.