Mobile App Drop-In — Backend API Pattern
How to wire your backend to create and manage VerifyHuman hosted verification sessions for a mobile app drop-in integration.
For the mobile-side setup (opening the URL, browser containers, deep links), see the Mobile App Drop-In guide.
Backend-owned session creation
Your backend should create the verification session and return only the hosted verification URL to the mobile app.
Never put a VerifyHuman private API key inside your mobile app binary. API keys embedded in app binaries can be extracted and abused. Always create sessions server-side.
Session creation options
Option 1 — VerifyFlow stable URL (recommended for most teams)
If you have published a VerifyFlow Flow, the hosted page URL is stable and reusable. Your backend can return the same URL to every user session without creating a new token each time.
This is the simplest path:
- Publish your Flow in the VerifyFlow dashboard.
- Copy the live hosted page URL.
- Your mobile app calls your backend.
- Your backend returns the hosted page URL.
- The app opens it.
Suitable for: high-volume flows where each verification is independent (bot detection, age gate, marketplace onboarding).
Option 2 — Per-session tokens via POST /hosted/generate
For use cases where you need single-use, per-user tokens with user-specific configuration or short TTLs:
POST /hosted/generate
Authorization: Bearer <your-api-key>
Content-Type: application/json
{
"product": "verifyidentity",
"redirect_url": "myapp://verify-complete?result=pass",
"failure_redirect_url": "myapp://verify-complete?result=fail",
"expires_in_hours": 1,
"page_title": "Identity Verification",
"success_message": "Verification complete. Returning to app…",
"failure_message": "Verification failed. Please try again."
}
Response:
{
"hosted_url": "https://app.verifyhuman.io/hosted/v/<token>",
"token": "<token>",
"expires_at": "2026-05-17T11:30:00Z"
}
Your backend returns only hosted_url to the mobile app.
Example backend flow
Mobile app Your backend VerifyHuman
────────── ──────────── ───────────
POST /your-api/start-verification
──────▶ validate user
call POST /hosted/generate (or return VerifyFlow URL)
store session_ref → token mapping
◀────── { "hosted_verification_url": "..." }
open in SFSafariViewController / Chrome Custom Tabs
──────▶ /hosted/v/<token>
user completes flow
POST /hosted/complete/<token>
◀────── redirect_url (deep link return)
app returns via deep link
GET /your-api/verify-status?session_ref=<id>
──────▶ look up token
check internal status
(populated by webhook)
◀────── { "status": "pass" | "fail" | "pending" }
Webhook-first confirmation
Webhooks are the authoritative source of verification results. Configure an endpoint in your dashboard that:
- Validates the HMAC-SHA256 signature using your webhook signing secret.
- Processes the
verification.completedevent. - Updates the session status in your database.
- Optionally triggers downstream actions (account activation, order approval, etc.).
POST https://your-backend.com/api/webhooks/verifyhuman
X-VerifyHuman-Signature: sha256=<hmac>
Content-Type: application/json
{
"event": "verification.completed",
"verification_id": "...",
"status": "PASS",
"product": "verifyidentity",
"environment": "live",
"timestamp": "2026-05-17T10:30:00Z"
}
See the Webhooks guide for full payload structure and signature validation.
Polling fallback
VerifyHuman does not provide a per-hosted-session status polling endpoint. When the app returns from the hosted flow via deep link, the webhook may not have arrived yet (typical delivery latency is under 1 second, but network conditions vary).
Recommended pattern:
- App returns via deep link → show a "Confirming your result…" loading state.
- App polls your backend:
GET /your-api/verify-status?session_ref=<id>every 1–2 seconds. - Your backend returns
{ "status": "pending" }until the webhook is received. - Once the webhook arrives, your backend updates the session and returns
{ "status": "pass" }or{ "status": "fail" }. - App shows the result and navigates accordingly.
Example webhook handler (Python/Flask pseudocode):
@app.route('/api/webhooks/verifyhuman', methods=['POST'])
def verifyhuman_webhook():
payload = request.get_data()
sig = request.headers.get('X-VerifyHuman-Signature', '')
# Validate signature using your webhook signing secret.
if not validate_signature(payload, sig, WEBHOOK_SECRET):
return '', 401
event = request.get_json()
if event.get('event') == 'verification.completed':
session = db.get_session_by_verification_id(event['verification_id'])
if session:
session.status = 'pass' if event['status'] == 'PASS' else 'fail'
db.save(session)
return '', 200
Redirect URL behavior
The POST /hosted/complete/<token> endpoint (called internally by the hosted page JS on completion) returns the configured redirect URL. The hosted page then navigates the user to that URL.
| Outcome | URL used |
|---|---|
| Verification passed | redirect_url from hosted page config |
| Verification failed | failure_redirect_url from hosted page config (if set) |
| User denied (e.g. age gate) | failure_redirect_url from hosted page config |
| No URL configured | User stays on the hosted result page |
Both URLs are validated server-side. They can be:
- HTTPS web URLs
- Custom deep link schemes (e.g.
myapp://verify-complete) - Universal links / App Links
Do not rely on the redirect URL or its query parameters as proof of verification. They are UX routing signals only. Confirmation must come from your webhook or backend status endpoint.
Test mode
Test hosted page URLs (available from the VerifyFlow flow detail page) run the full hosted flow without consuming live credits. Use them during development and QA.
- Test URLs display a yellow banner: "Test mode — sample run only."
- Test webhook events are sent to webhook endpoints configured with
environment: test. - Test deep link returns work identically to live.
Status polling via mobile REST API (alternative)
If you are using the Mobile REST API (/api/mobile/v1/) rather than hosted pages, status polling endpoints do exist:
| Product | Status endpoint |
|---|---|
| VerifyHuman | GET /api/mobile/v1/verifyhuman/status/{verification_id} |
| VerifyAge | GET /api/mobile/v1/verifyage/status/{session_id} |
| VerifyIdentity | GET /api/mobile/v1/verifyidentity/status/{session_id} |
| VerifyTrust | GET /api/mobile/v1/verifycompliance/status/{session_id} |
These use the mobile session model (not the hosted page token). See the Mobile API & SDK documentation for authentication and session management.
Related
- Mobile App Drop-In guide — mobile-side setup (browser containers, deep links, snippets)
- Hosted Flows Guide — full configuration reference
- Mobile API & SDK — full native integration
- Webhooks — result delivery and signing