Dashboard

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

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:

  1. Publish your Flow in the VerifyFlow dashboard.
  2. Copy the live hosted page URL.
  3. Your mobile app calls your backend.
  4. Your backend returns the hosted page URL.
  5. 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:

  1. Validates the HMAC-SHA256 signature using your webhook signing secret.
  2. Processes the verification.completed event.
  3. Updates the session status in your database.
  4. 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:

  1. App returns via deep link → show a "Confirming your result…" loading state.
  2. App polls your backend: GET /your-api/verify-status?session_ref=<id> every 1–2 seconds.
  3. Your backend returns { "status": "pending" } until the webhook is received.
  4. Once the webhook arrives, your backend updates the session and returns { "status": "pass" } or { "status": "fail" }.
  5. 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:

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.


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.