Every webhook Fingerly sends has the same shape: four headers you can act on, and a JSON envelope whose data depends on the event type.
Event types
| Type | Sent when | Environments |
|---|---|---|
identification.completed | Any identification finishes. | live, test |
visitor.suspect | An identification reaches the high level. | live, test |
identification.refused | An identify request is refused. | live, test |
billing.status_changed | Your organization starts or stops accepting traffic. | live |
usage.daily_settled | A day of usage is settled. | live, test |
webhook.test is sent only when you choose Send test event for an endpoint. You cannot subscribe to it, and its data holds only endpoint_id. Ignore event types you do not handle.
Headers
Content-Typestringapplication/json.User-AgentstringFingerly-Webhooks/1.0.X-Fingerly-Event-IDstringThe envelope'sid.X-Fingerly-Event-TypestringThe envelope'stype, so you can route before parsing.X-Fingerly-TimestampstringUnix seconds when this attempt was signed. It changes on every retry.X-Fingerly-Signaturestringsha256=followed by the lowercase hex HMAC-SHA256 signature. While a secret is rotated, one such value per secret, separated by commas.
Signature
The signature is an HMAC-SHA256 over the timestamp, a full stop, and the raw request body, keyed with the endpoint's signing secret. Use the whole secret, whsec_ prefix included, as the key.
signed_payload = X-Fingerly-Timestamp + "." + raw_body
signature = "sha256=" + hex(hmac_sha256(signing_secret, signed_payload))
- Compare signatures in constant time.
- Split the header on commas and accept the delivery if any signature matches.
- Reject a timestamp more than five minutes from your clock.
- Verify the exact bytes you received. Parsing and re-serialising the JSON changes them.
Envelope
idstringThe event's ID, a UUIDv7. The same on every retry: deduplicate on it. Also sent asX-Fingerly-Event-ID.typestringAlways<event type>.versionintegerThe envelope version,1.organization_idstringYour organization.environmentstringlivefor production traffic,testfor staging and development.created_atstringWhen the underlying fact happened, RFC 3339 in UTC. Not when it was delivered.dataobjectThe event's data. Its fields are listed on each event's page.
Compatibility
- New fields may be added to
dataand to the envelope within version1. Ignore fields you do not know. - New event types are only delivered to endpoints that subscribe to them.
- Do not rely on the order of JSON keys.