Skip to main content
Consent
  • The consent url of a KYC workspace shows the KYC text. GET /v1/consent returned https://app.proofage.net/consent to every workspace, and that page showed the age-verification text, so an identity-verification integration that shows the page at url showed a text other than the one its users accept. A KYC workspace now gets https://app.proofage.net/consent?type=kyc; age-verification workspaces keep the address they had. The response shape is unchanged. If you stored the address instead of reading it from the response, read it again. See Consent.
  • New consent versions. The age-verification text is now version 4 and the KYC text version 2. The only change is the contact address, now [email protected]. The previous versions are no longer active: accepting them answers 409, so an integration that stored id and text_sha256 instead of reading GET /v1/consent before each acceptance must read them again. The hosted widget needs nothing.
Domains
  • ProofAge moved to proofage.net. The API is now https://api.proofage.net/v1, the console https://app.proofage.net, these docs https://docs.proofage.net, and new verification links are issued on idv.proofage.net. The API spec, the Postman collection and the examples on these pages name the new hosts.
  • Nothing you have breaks. api.proofage.xyz keeps answering, with the same keys and the same signatures, so an integration or an SDK release that names it needs no change. Links issued before the move keep working on the host they were issued on, the browser SDK loader is still served from app.proofage.xyz, and MCP clients connected to app.proofage.xyz/mcp/admin stay connected. Console pages opened on the old host are sent to the new one.
  • If your site has a Content Security Policy that names idv.proofage.xyz in frame-src, add idv.proofage.net: the verification URL the API returns is now on that host.
  • SDK releases to match: @proofage/node 0.14.0, proofage (Python) 0.9.0, proofage/php-sdk 0.9.0 and proofage/laravel-client 0.11.0 default to https://api.proofage.net. Earlier releases keep working against api.proofage.xyz.
Plugins
  • PrestaShop module. Age verification for PrestaShop 8.1 to 9.x, without code: protect products, categories, CMS pages, controllers, URL paths or the whole shop, with add-to-cart, checkout and order creation blocked server-side until the shopper is verified. Download it from GitHub. See PrestaShop.
API, webhooks and Zapier
  • List verifications. GET /v1/verifications lists the workspace’s verifications, newest first, as {"data": [...], "next_cursor": ...}. Filter by status (comma-separated) and external_id; page with limit (1 to 100, 20 by default) and cursor. Use it to find a verification by your own ID. The query string is part of the signature, sorted by name, with a comma written as %2C. See Reading results.
  • Webhook subscriptions. POST, GET and DELETE /v1/webhook-subscriptions subscribe more URLs to the decision webhooks, in addition to the workspace’s webhook URL, and remove them: up to 50 per workspace (422 WEBHOOK_SUBSCRIPTION_LIMIT past that), optionally for some statuses only. A subscription gets status.updated webhooks only, never data.updated. Unless it was created with include_document_data: true, its body leaves out document, fingerprint_signals and manual_moderation.performed_by. Its deliveries are signed with the secret key that created it, or with the active key once that key is deleted. A 410 answer deletes the subscription. See Webhooks.
  • Because a subscription’s body can leave it out, document is no longer required in the webhook schema. The workspace’s webhook URL still receives it on every webhook.
  • Set a test outcome from your code. POST /v1/verifications/{id}/test-outcome sets approved, declined, review or resubmission_requested on a test workspace’s verification that is not final, with an optional reason note. One nobody has opened is moved through started and submitted first, so exactly one decision webhook is sent. A live workspace answers 403 TEST_WORKSPACE_ONLY; a final verification 422 INVALID_STATUS. See Sandbox and test data.
  • Webhook URLs must be public. A new webhook URL, on a workspace or a subscription, must be https; private, loopback, link-local and cloud-metadata addresses, local names and URLs with credentials are refused, and a Unicode host name must be written in punycode. The address is checked again before each delivery, and a delivery to one that has become private is skipped. An http URL saved before keeps working. See The webhook URL.
  • Redirects are no longer followed. A 3xx from your webhook URL is recorded as the answer and not retried; set the URL your handler serves. Only the first 2 KB of your response body are kept with each attempt.
  • callback_url and the workspace’s redirect URL accept http and https URLs only.
  • The per-IP rate limit counts each workspace separately, so workspaces calling from one IP address no longer share it. The per-workspace limit is unchanged. See Rate limiting.
  • ProofAge for Zapier. Send verification links from any Zap and act on the decision, without code. Shared by invite for now. See Zapier.
  • SDK releases to match: @proofage/node 0.13.0, proofage (Python) 0.8.0, proofage/php-sdk 0.8.0 and proofage/laravel-client 0.10.0 add listing verifications, webhook subscriptions and test outcomes. In the SDK types manual_moderation.performed_by is now optional, because subscription deliveries leave it out.
Webhooks and console
  • Correct document fields the reader got wrong. An administrator or a support specialist can correct a field on an approved, declined or in-review verification, in the console or with the new MCP tool correct-document-fields. The status does not change and no check runs again. The recognised value is kept; your corrected value is what the webhook and GET /v1/verifications/{id}/document return. See Verifications and review.
  • New webhook event data.updated. Every webhook payload now has event: status.updated for the status webhooks you already receive, and data.updated when a correction is made. A data.updated has the same fields as a status webhook, with the current status, the corrected document and a new changed_fields (the names of the fields changed, no values). A payload without event is a status.updated, so event is optional in the schema. Read event before status: a handler that ignores it sees what looks like a repeat of the status it already has, and must not treat it as a new decision. See Webhooks.
  • The document type, issuing country and issuing state or province can be corrected too, on every workspace. A corrected country clears the state or province that was read with the old one, unless that is corrected as well. changed_fields then names type, issuing_country or issuing_subdivision.
  • Resending or retrying an older webhook sends the document as it is now, corrections included.
  • SDK releases to match: @proofage/node 0.12.0, proofage (Python) 0.7.0, proofage/php-sdk 0.7.0 and proofage/laravel-client 0.9.7. The new keys are optional in their types.
Dashboard and MCP
  • Resubmission insights count people, not verifications. The dashboard card and the resubmission part of the MCP get-verification-stats now merge a person’s verifications by external_id within a workspace, and count each person once, on the day of their final outcome. Someone declined on one link and approved on the next is one approval on the 2nd attempt, on the day of the approval, and no longer a decline plus a first-attempt approval. A new verification after an approval starts a new count of its own, and verifications without an external_id are counted one by one. The response keys are unchanged, volume stays per verification, and the MCP legend has a new person entry.
API
  • DOCUMENT_PORTRAIT_NOT_FOUND on a document front upload. A front image with no photo of the holder on it, such as a closed passport cover or the back of a card, is now refused at upload with 422 and this code, instead of failing later in the verification. Ask the person to retake the document photo. Not sent for every workspace; handle it like the other upload codes in Error handling.
Billing
  • The 500 free verifications no longer expire after 15 days. They are used before your card is charged, and there is no monthly minimum while any are left or in a month that used them. Your administrators get an email when 100, 30 and 0 are left. See Pricing.
API
  • issuing_subdivision in the document result. issuing_subdivision in document is the state or province that issued the document, as a bare code right after issuing_country (for example FL with US), or null. Today it is filled for US driving licences and ID cards. It is on every workspace, in GET /v1/verifications/{id}/document, in the webhook document and in the MCP list-verifications document, and it is kept after erasure. See Reading results.
  • SDK releases to match: @proofage/node 0.11.0, proofage (Python) 0.6.0, proofage/php-sdk 0.6.0 and proofage/laravel-client 0.9.6.
API
  • address in the document result, on identity (KYC) workspaces only. GET /v1/verifications/{id}/document now returns address in fields: the printed text as read, trimmed, null when empty, not parsed and not normalised. It may contain line breaks. fields carries eleven keys on KYC workspaces, seven of them KYC-only. Age workspaces do not receive address.
  • The decision webhook carries document. Every decision webhook now has the same document object as GET /v1/verifications/{id}/document, without the images: type, issuing_country and fields, with eleven fields on identity (KYC) workspaces and four on age workspaces. It is present on every status and is all null when nothing was read, and on test workspaces. A resend or a manual retry carries the document as it is now; an automatic retry carries the body as first sent. Stored webhook bodies in your logs now hold the person’s name and birth date until erasure. If your handler validates the body with a strict schema, allow the new key. See Webhooks.
  • nationality is published only when the document itself states it.
  • MCP list-webhook-deliveries returns the last attempt’s request_body only with include_payload: true, like payload.
  • Erasure covers every stored copy of a webhook body. The copy of the body kept with each delivery attempt, and what a receiver answered, are now erased with the rest of the person’s data, and an erasure that lands while a delivery is in flight is no longer undone.
  • gender can be X. F, M or X, where X means the document states that the sex is unspecified.
  • SDK releases to match: @proofage/node 0.10.0, proofage (Python) 0.5.0, proofage/php-sdk 0.5.0 and proofage/laravel-client 0.9.5. They type address and the webhook document, both optional. See Reading results and Data models.