Webhook Payloads
When you create a verification link with awebhook_url, BotShield will POST a JSON event to that URL as soon as the verification state changes. This is the recommended way to receive results — polling is supported but adds latency and cost.
Event Types
Three events can fire per verification request:| Event | When it fires |
|---|---|
verification.success | User completed the biometric challenge successfully |
verification.failed | User explicitly denied / cancelled, or the flow errored out |
verification.expired | The verification link TTL lapsed without a response |
request_id.
Success Payload
Fields
| Field | Type | Description |
|---|---|---|
event | string | Always "verification.success" |
event_id | string | Unique event ID for idempotency. Safe to dedupe on. |
request_id | string | The verification request ID you received when creating the link |
organization_id | string | Your organization ID |
botshield_user_id | uuid | Pseudonymous BotShield user ID. Stable for this user across verifications on this account. |
auth_mode | enum | "linked-account" (user chose to associate with your platform) or "private" (anonymous) |
verified_at | string | ISO 8601 timestamp of the biometric event |
user_email | string or null | User email (only present when auth_mode === "linked-account") |
verification_token | string | Signed JWT receipt. Validate with sdk/verify-token. |
metadata | object or null | Whatever metadata object you included when creating the verification link |
Failed Payload
reason is one of: user_denied, device_lock_required, internal_error, platform_declined.
Expired Payload
verification.expired fires.
Validating the Webhook
- Verify the signature using the signed
verification_token— callsdk/verify-tokento confirm the token was issued by BotShield and has not been tampered with. - Check
event_idfor idempotency — BotShield may retry on delivery failure. Dedupe onevent_idto avoid double-processing. - Apply your policy based on the verdict + reason pair — the verification flow returns
verdict ∈ { 'pass', 'require_presence' }andreason ∈ { 'multipass_active', 'presence_fresh', 'multipass_stale', 'elevated_requires_presence', 'no_resolution' }. See Human Presence for the full reason enum.
Delivery and Retries
- BotShield sends webhooks over HTTPS with
Content-Type: application/json. - If your endpoint returns a non-2xx status, BotShield retries with exponential backoff up to 3 attempts over 5 minutes.
- A
200 OKresponse (empty body is fine) acknowledges receipt. - Webhooks that fail all retries are logged; you can replay them from the Partner Dashboard.
Related
- Human Presence — verdict + reason contract and the user-facing tier
sdk/verify-token— validate the verification JWT- Trusted Account Signal — Class A/B classification and how mature linkages strengthen MultiPass durability