POST that Aniva sends to your server when something changes. You do not
need to poll.
Events are thin. They carry the object id, the new status, a revision and the url to read. They
never carry lab values or personal data. Read the url with your API key to get the data.
Quick setup
- Build an HTTPS endpoint that accepts
POSTand answers2xxwithin 15 seconds. - Register it with Create Webhook.
Store the
secretfrom the response. Aniva shows it only once. - Verify the signature of every request.
- Send a test event. Check the result in List Deliveries.
webhooks_manage scope. Ask Aniva to add it. A webhook belongs to the
API key that created it, and a key can own at most 5 webhooks.
Events
You receive an event only for objects your API key can read with the matchingGET endpoint.
Choose the types with enabled_events. Send ["*"] to receive every type, also types added later.
- A status event fires on every move into that status, also a move back. For example, a kit that
goes from
dispatchedback topendingsendshome_kit_order.pending. - One change can send two events with the same
status_revision, for exampleappointment.confirmedandappointment.rescheduled. results.updatedfires on every change of the results: a new value, a correction, a fault, a new or replaced document, or a sample that leaves the object. It arrives within a few minutes of the last change.results.completedandresults.faultalways come with aresults.updatedof the sameresults_revision. Results can reopen and complete again, so you can get a secondresults.completed.
results.updated to show partial results, or to results.completed to act only on
final results.
results.completed follows the result values, not the PDF. The report PDF can arrive before or
after the values. Some labs first send a preliminary PDF and later replace it with the final one
under the same document id. The replacement sends results.updated. Read
documents[].original_file_name to tell the two apart: Labor Quade ends a preliminary report
(Vorbefund) in _V and the final report (Endbefund) in _E, for example
7642100312_B0012_FA_E.pdf.
Location, profile and shipment events arrive within a few minutes. Aniva waits until the object has
not changed for 2 minutes, so a burst of edits sends one event. These rules also apply:
- Anonymous profiles send no events.
- A shipment sends no event when you lose access to it.
- A shipment status change sends
shipment.updatedand theshipment.<status>event with the samerevision.
Payload
Status event data
appointment.confirmed
Results event data
home_kit_order.results.completed
Location, profile and shipment event data
shipment.in_transit
ping carries data.object webhook and data.id, the webhook id.
Verify the signature
Events carry no data, but you should still verify each one. A valid signature proves that the event came from Aniva. Each request carries the headerswebhook-id, webhook-timestamp (Unix
seconds) and webhook-signature.
- Take the raw request body. Verify it before you parse the JSON.
- Build the signed content
{webhook-id}.{webhook-timestamp}.{raw body}. - Base64-decode the part of your secret after
whsec_. Use it as the key. - Compute HMAC-SHA256 of the signed content and encode it as base64.
- Compare it in constant time with each
v1,<signature>entry inwebhook-signature. The entries are separated by spaces. One match is enough. - Reject the request when
webhook-timestampis more than 5 minutes from your clock.
Node.js
Rotate the secret
Call Rotate Secret to get a new secret. For 24 hours, Aniva signs with the old and the new secret, so deploy the new one within that time. After a leak, sendrevoke_current_secret_now: true to stop the old secret at once.
Delivery
- Answer
2xxwithin 15 seconds. Store or queue the event and do the work later. - Use an
httpsURL on port 443 with a public host. Aniva does not follow redirects: a3xxcounts as a failure. - Delivery is at least once and unordered. Drop duplicates by
webhook-id. Use the revisions to ignore an older event. - Answer
410 Goneto stop the events. Aniva disables the webhook at once. - Aniva keeps deliveries for 30 days. After that, you cannot list or resend them.
Retries
A non-2xx answer, a timeout or a network error starts a retry. Each event gets up to 10 attempts
over about three days:
After attempt 10, the delivery is
failed. Send it again with
Resend Delivery. It keeps the same webhook-id.
Failure notices
Aniva emails the webhook’salert_emails when no delivery succeeded for 24 hours, when an event is
failed, and when the webhook is disabled. After 5 days without a successful delivery, Aniva
disables the webhook. A disabled webhook gets no new events, and its waiting deliveries are
cancelled.
To start again, fix your endpoint and send
status: "enabled" with
Update Webhook. Missed events are not sent
again by themselves. Resend them, or read the current state with the GET endpoints.
Best practices
- Drop duplicates. Skip an event whose
webhook-idyou already processed. - Use the revisions. Store the highest
status_revision,results_revisionandrevisionper object. Ignore an event with a lower one. - Fetch the
url. The event says that something changed. TheGETendpoint says what. - Answer fast. Queue the event and answer
2xxbefore you process it. - Reconcile. Run a regular job that reads open objects with the
GETendpoints. Polling stays a valid fallback. - Test after each deploy. Use Send Test Event.