Webhooks
Company tierIn the app: /webhooks
Webhooks send a signed HTTPS request to an address you give us whenever one of the events you choose happens, so a chat channel, a ticketing system or your own database hears about it straight away. Each request carries the record in the same shape the REST API returns, and we retry a failed delivery for nearly two days before giving up.
1.Add an endpoint (admin)
- Open Webhooks under Admin Settings.
- Give the endpoint a name and the https:// address that will receive the events. It must be reachable on the public internet.
- Tick the events to send: an incident is reported, a safety observation is reported, a corrective action is raised, a corrective action is completed or verified, a site audit is saved, an equipment inspection fails, a training record is added, a change is approved, a change is implemented, a permit is approved, a permit is closed out. Only events for modules your company has on are listed.
- Press Add Endpoint and copy the signing secret. It starts with whsec_ and is shown only now.
- Press Send Test Event to send a ping and see what your endpoint answered.
2.Receive an event
- Each event is a POST with a JSON body: id (the delivery's id), event (such as incident.created), createdAt, and data, the record as GET /api/v1/<resource>/<id> would return it.
- Headers: Migna-Event names the event, Migna-Delivery repeats the id, and Migna-Signature reads t=<unix time>,v1=<signature>.
- Answer with any 2xx status within 10 seconds. Do slow work after answering. A redirect counts as a failure, since we do not follow them.
- A delivery can arrive more than once, for example after a retry that did reach you. Use the id to ignore one you have already handled.
3.Check the signature
- Take t and v1 from the Migna-Signature header.
- Compute an HMAC-SHA256 of the text t, a full stop, then the raw request body, using the signing secret as the key, and write it as hexadecimal.
- Accept the request only if your result equals v1, compared in constant time, and t is within five minutes of now. Otherwise answer 400.
- If the secret leaks, press Rotate Secret. Deliveries are signed with the new secret straight away.
4.Follow up on failures (admin)
- Press Show Deliveries on an endpoint for its last 25 deliveries with the HTTP status or error.
- A failed attempt is tried again after 15 minutes, an hour, 4 hours, 12 hours and a day: six attempts in all. Press Send Again to try one now.
- An endpoint whose deliveries fail every attempt 15 times in a row is switched off, with the reason shown. Fix the receiver and press Turn On.
- We keep deliveries for 30 days. Adding, changing, rotating and deleting endpoints is recorded in the Activity Log.
5.Subscribe through the API (integrations)
- An integration that subscribes itself, such as a Zapier integration, needs an API key with the Zapier Webhooks permission. It can subscribe only to events about records the key can read.
- POST /api/v1/hooks with a JSON body of url (the https:// address to send to) and event (such as incident.created). The answer carries the subscription's id and its signing secret.
- GET /api/v1/hooks lists the key's subscriptions and the events it may subscribe to. DELETE /api/v1/hooks/<id> unsubscribes. A key sees and removes only its own, and holds at most 50.
- Deliveries are the same signed requests described above. If the receiving address answers 410 Gone, we delete the subscription.
- Each subscription is listed on the Webhooks page, marked with the key that made it. An admin can turn it off or delete it there; revoking the key deletes them all.
Common questions
- What is in the data?
- The same fields as the REST API: never files, photos, signatures, contact details or anything medical, and a privacy case without the person's name. To read more, call the REST API with the record's id.
- Which changes send an event?
- Incidents and observations reported in the app, from a QR code or with the assistant; corrective actions however they are raised (on the page, from another module, with an incident report, from a maturity gap, by importing a gap analysis or with the assistant), and closed on the page or with the assistant; audits and inspections saved in the app or uploaded from a phone that was offline; training records added on the Training page or by a QR course; changes approved or implemented; and permits approved or closed out.
- Why was my address refused?
- It must start with https:// and point at the public internet. We refuse addresses on private networks, both when you add them and when we send, so a webhook cannot be used to reach something inside our own network.