Skip to main content
WEBHOOK

Headers

X-HMAC-Signature
string
required

Hex HMAC-SHA256 of {X-Timestamp}.{raw body} with the workspace's active secret key; for a webhook subscription, with the secret key that created it (the active key once that one is deleted).

X-Timestamp
integer
required

Unix time, in seconds, when the request was signed.

X-Auth-Client
string
required

The workspace's public key (pk_test_… or pk_live_…).

X-ProofAge-Webhook-Delivery-Id
string
required

ID of this delivery. A retry of the same delivery keeps it; use it to ignore duplicates.

Body

application/json
verification_id
string<uuid>
required

The verification this event is about.

status
enum<string>
required

The status the verification moved to. On a data.updated event, the current status, unchanged.

Available options:
approved,
declined,
resubmission_requested,
review,
abandoned,
expired
external_id
string | null
required

Your identifier for the person, as sent when the verification was created.

external_metadata
object | null
required

The metadata you attached when creating the verification, returned as sent.

reason
string | null
required

The decision reason code when the status is declined or resubmission_requested; null otherwise. Also null on the resubmission_requested a facial age estimation sends when it asks the person for an ID (GET reports that verification as documents_required). When attempts run out, the declined event carries the last attempt's reason. See Decision reasons.

timestamp
string<date-time>
required

When the status changed, ISO 8601.

event
enum<string>

What happened. status.updated: the verification moved to status. data.updated: someone on your team corrected document fields; status is the current status, which a correction never changes, document carries the corrected values and changed_fields names what changed. A payload without event, such as a retry of a delivery created before this field existed, means status.updated. Webhook subscriptions receive status.updated only.

Available options:
status.updated,
data.updated
document
object

The same object GET /v1/verifications/{id}/document returns, without media and meta, read from the attempt that decided the verification. Identity (KYC) workspaces receive eleven fields; age verification workspaces receive first_name, last_name, date_of_birth and document_number only, and the other seven keys are absent. null means the field was not read, is not printed on that document, or no document was read at all (a facial age estimation that passed without an ID, a test workspace, a wallet check); document itself is never null. Dates are YYYY-MM-DD and countries ISO 3166-1 alpha-2 (XK for Kosovo); type and gender are open enums. Fields your team corrected show the corrected value. A resend or a manual retry carries the document as it is now; an automatic retry carries the body as first sent. After the person's data is erased, only type and issuing_country are kept. Always present on the workspace webhook; left out of a webhook subscription's deliveries unless it was created with include_document_data.

changed_fields
string[]

Only on data.updated: the names of what this correction changed, for example ["date_of_birth"]. A name is a key of document.fields, or type, issuing_country or issuing_subdivision. Names only; the new values are in document.

duplicate_detected
boolean

Present and true only when the same face was found behind another verification in the workspace.

duplicate_count
integer

Present with duplicate_detected: how many earlier verifications matched.

duplicate_of
object

Present with duplicate_detected: the first matching verification.

fingerprint_signals
object

Optional device and network signals collected during the session. Treat it as informational; its fields may change. Left out of a webhook subscription's deliveries unless it was created with include_document_data.

manual_moderation
object

Present when a person in the console approved or declined the verification by hand.

Response

200

Any 2xx acknowledges the delivery.