Webhooks
Receive asynchronous event callbacks from iLive.
Webhooks let iLive push verification results to your backend as soon as a user finishes a managed session. You don't have to poll — iLive calls you when the verdict is final.
When webhooks fire
A webhook is delivered exactly when a managed session reaches a final
verdict (pass, fail, or retry). Webhooks are not sent for direct
sessions or for in-flight session state changes.
Register a receiver by setting webhook_url when you create the session:
The webhook URL must be HTTPS and must not resolve to an internal or private IP. Non-HTTPS URLs are rejected at session creation and never delivered if somehow set.
Payload
iLive POSTs a JSON body:
The session_id is the canonical identifier. Pair it with the result
endpoint (GET /api/v1/session/{id}/result) or the photo endpoint
(GET /api/v1/session/{id}/photo) to fetch the full record including the
ICAO-compliant photo.
Delivery semantics
iLive delivers each verdict with up to two attempts: if the first POST fails with a 5xx or a network error, we retry once after a short delay. If both attempts fail the webhook is dropped and the failure is logged on our side.
Because retries exist but are capped, design your handler to be
idempotent keyed on session_id. Receiving the same verdict twice
should be a no-op.
Verifying authenticity
Every outbound webhook is signed with HMAC-SHA256 using a per-account secret. iLive attaches three headers to each delivery:
| Header | Description |
|---|---|
X-iLive-Signature | sha256=<hex> — HMAC-SHA256 of the signed payload |
X-iLive-Timestamp | Unix seconds at signing time — use for replay protection |
X-iLive-Webhook-Id | Random UUID per delivery — use for idempotency |
The signed payload is:
where raw_body is the exact bytes of the request body as delivered.
Do not re-parse and re-serialise JSON before verifying — whitespace and
key ordering would change the bytes and the signature would not match.
Your signing secret is created when your tenant account is provisioned and is shown once — both on creation and when you rotate it from the iLive admin console or tenant portal. Store it alongside your other backend secrets; a rotation invalidates the previous secret immediately.
When verifying, always:
- Read
X-iLive-SignatureandX-iLive-Timestampfrom the request. - Recompute
sha256=hex(HMAC_SHA256(secret, f"{timestamp}.{raw_body}")). - Compare using a constant-time comparison.
- Reject the request if
|now - timestamp| > 300seconds.
Receiver examples
Defence in depth
Signatures prove the payload came from iLive and hasn't been tampered with, but you can layer additional controls:
- IP allowlist. If your edge supports it, restrict the webhook route to iLive's published egress ranges (available from support on request).
- Confirm via pull. Before granting access based on a webhook, call
GET /api/v1/session/{id}/resultwith your server-side API key. That endpoint is always authoritative.
Handling the event
Once the signature has been verified, persist the event keyed on
session_id (or X-iLive-Webhook-Id for exact-duplicate detection)
before acting on it. A minimal Python handler:
Respond 2xx as soon as you have persisted the event. iLive treats any
non-2xx response (or a timeout past ten seconds) as a delivery failure
and will retry once.
Related: Managed sessions · Liveness overview · Error codes.