Hosted Page Lifecycle and Attempts API
How hosted pages and their verification attempts behave over time, and how your server starts an attempt for a specific customer.
Pages and attempts
| Object | What it is | Lifetime |
|---|---|---|
Hosted page (/hosted/v/<page-token>) |
Your configured verification page for one product: branding, redirect URLs and, for VerifyAge, the minimum-age policy | Persistent — reused by every visitor until you change or deactivate it |
Attempt (?attempt=<attempt-token>) |
One visitor's verification on that page | About 60 minutes, or until it reaches an outcome |
Persistent and one-time pages
Pages created by the Wizards and published by VerifyFlow are persistent: one URL serves many visitors, each with their own attempt. Older one-time pages lock after their first completion. The Attempts API works with persistent pages only.
Product and environment binding
A page runs exactly one product and belongs to the API key it was created with, which fixes its environment (Test or Live). An attempt can only run that page's product, and only in that environment.
Attempt lifecycle
created (pending) ── visitor starts ──▶ in_progress ──▶ completed
├──▶ needs_review
├──▶ blocked
└──▶ error
pending / in_progress ── about 60 minutes ──▶ expired
- Resume. Reloading the page, or continuing on a phone through the desktop-to-mobile handoff, resumes the same attempt. It does not reset the attempt's retry allowance.
- Retry. Within an attempt, the page offers another try when a step can be
retried. After an
erroroutcome the visitor may be offered a new attempt;completed,needs_reviewandblockedare final outcomes. - Expiry. An unfinished attempt expires after about 60 minutes. The visitor reopens the page URL to start a new one.
- Billing. Creating an attempt is free; the verification is billed when it is submitted (Credits and Billing).
List your pages
GET /api/v1/hosted/pages[?product=<product>] — authenticated with
X-API-Key; the key's scopes must include the product.
curl "https://app.verifyhuman.io/api/v1/hosted/pages?product=verifyage" \
-H "X-API-Key: vhk_live_your_client_key"
{
"pages": [
{"page_token": "PAGE_TOKEN", "display_name": "Age check", "product": "verifyage", "active": true}
]
}
Only your own pages are listed. product must be one of verifyhuman,
verifyage, verifyidentity, verifycompliance.
Start an attempt
POST /api/v1/hosted/pages/{page_token}/attempts
curl -X POST https://app.verifyhuman.io/api/v1/hosted/pages/PAGE_TOKEN/attempts \
-H "X-API-Key: vhk_live_your_client_key" \
-H "Content-Type: application/json" \
-d '{"product": "verifyage", "return_url": "https://shop.example.com/age-check/return"}'
| Field | Required | Description |
|---|---|---|
product |
Yes | Must equal the page's product |
return_url |
Yes | Where the visitor is sent when the attempt finishes. Absolute HTTPS URL (HTTP only on Test pages), at most 400 characters, on a domain registered for your API key |
Response 201
{
"attempt_token": "ATTEMPT_TOKEN",
"verification_url": "https://app.verifyhuman.io/hosted/v/PAGE_TOKEN?attempt=ATTEMPT_TOKEN",
"status_url": "https://app.verifyhuman.io/hosted/status/ATTEMPT_TOKEN",
"expires_at": "2026-11-03T11:00:00Z"
}
Store attempt_token with your customer's session and send the customer to
verification_url. The request carries no personal data, and the page's own
settings are not changed.
| Status | error |
Meaning |
|---|---|---|
404 |
not_found |
No such page, or not yours |
422 |
product_mismatch |
product is not the page's product |
403 |
product_not_authorized |
The key or plan does not include the product |
409 |
page_inactive |
The page is not an active persistent page |
409 |
hosted_page_environment_mismatch |
The page and the key are in different environments |
422 |
invalid_return_url |
return_url is missing, not HTTPS, too long or not on a registered domain |
Status polling versus the trusted decision
status_url (GET /hosted/status/<attempt-token>) is public and returns only
the attempt's progress and verification_id. Use it to show progress, never to
grant access: it does not identify your account, page, environment or product.
Final result validation
When the customer returns to return_url?attempt=<attempt-token>:
- Require
attemptto equal theattempt_tokenyou stored for this customer. - Confirm the result with the signed webhook or the
Evidence Receipt for its
verification_id: expected product,environment: live,status: PASSand, for VerifyAge,age_verification.requirement_metwith a sufficientminimum_age. - Accept each
verification_idonce.
Full guidance: Confirming the result on your server.