Persona inquiry webhook (Government ID verification)
Receives Persona's inquiry events. Called by Persona only — there is no session, and the request is authenticated by the Persona-Signature header (t=<unix time>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">, one space-separated pair per secret while a secret is being rotated), checked against PERSONA_WEBHOOK_SECRET over the raw body before it is parsed. The event is only a signal. The inquiry it names is read back from Persona, and that answer — never the payload — decides. The inquiry must be held by exactly one verification row, with the same recipient as its reference id and the configured Inquiry Template. Only the approved decision verifies the recipient: declined and failed move it to failed, expired to expired, and completed, needs_review, or any status this service does not know changes nothing. A settled verification never moves again, so redeliveries and out-of-order events are harmless, and an event about an inquiry that has since been replaced matches no row. An event for a document that is no longer signable (completed, declined, voided, expired, or this recipient already signed or declined) is ignored. Events that are not for this service are acknowledged with 200 so Persona stops retrying them. Only a failure a retry could fix (503: Persona could not be read, 500) asks for redelivery.
View as MarkdownHeader Parameters
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Persona's JSON:API event. Only data.attributes.name and the inquiry id in data.attributes.payload.data are read.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/webhooks/persona" \ -H "Persona-Signature: string" \ -H "Content-Type: application/json" \ -d '{}'{ "ok": true, "ignored": true}Check a verification code
Phone methods only: a government_id recipient has no code to check (400 unsupported_method) — that verdict arrives from Persona on POST /webhooks/persona. Checks the code with the verification provider. On success the server records the verification and sets an HttpOnly session cookie scoped to this signing link (valid 2 hours); the cookie, not the response body, is what later authorizes signing actions, and a page refresh keeps it. A successful verification replaces any earlier session for this link — there is one active session — so a signer who verifies from a second browser ends the first browser session at that moment. Five wrong codes per sent code exhaust the attempt budget (verification_too_many_attempts) until a new code is sent. Requires the access code first when one is set.
Recipient download URL
Presigned URL for the recipient — the final artifact once completed, else the original.