Trusted details, shared with control

Share trusted details, not your whole ID.

Verify on your phone, see exactly what is requested, and approve before anything is shared.

For example:

See the request

Know what is being asked before you approve.

The service starts a Verihop request. You complete the guided check, review the requested details and continue where you left off.

What the video shows

A service asks for specific details. You complete verification on your phone, review the request and approve sharing. You return to the service when the check is complete.

What to expect

Clear, quick and under your control.

Clear

See who is asking and exactly what they need.

Fast

Successful supported checks have no routine review queue.

Reusable

Use a saved valid verification when the service accepts it.

Private by design

Approve only the requested details.

Phone held over a passport for NFC identity verification

How it works

Start from a Verihop link or QR code. You see who is asking and which details they need before anything is shared.

1

Open the request

Verihop shows the requesting service and the exact details it wants.

2

Verify on your phone

Follow the guided identity-document and live-holder checks available for the request.

3

Approve and continue

Approve the requested details and continue where you left off.

TRY DEMO See an age check from start to finish. Complete the flow on your phone and see exactly what the demo receives.

Made for real life

Prove what's needed. Get on with what you were doing.

Age

Prove you're old enough.

Confirm your age and continue.

Rentals & services

Verify who you are.

Share the verified details requested.

Account onboarding

Verify and continue.

Complete the check and return directly to the service.

Account access

Prove it's really you.

Verify for sensitive actions, support, or account recovery.

Building one of these experiences? See how Verihop works for companies, integrations and customer journeys. Explore FOR COMPANIES →

Your choice

Strong checks. Simple choices.

Check the documentRead the MRZ and secure chip where supported.

Check the holderUse guided liveness and face comparison for the active verification.

Approve the requestThe service receives the details you approve.

How Verihop handles identity information

Ready when you are

See what a Verihop request feels like.

Try the age-check demo, review the exact requested details, and complete the phone flow.

Personal Identity API

One API for trusted details.

Create a session. Send the launch URL. Fetch the approved result. Verification, consent and device routing are handled for you.

Need the product and business overview? See FOR COMPANIES →

INTEGRATION STEPS

From session to approved result in four steps.

View integration steps

1. Create the session

POST /v1/sessions

2. Open Verihop

Use launch_url or qr_url; native iOS apps open app_clip_url unchanged.

3. Receive the callback

session_id + result_token

4. Fetch the result

GET /v1/sessions/{id}/result

One-time exchange on your backend.

Optional: check session status GET /v1/sessions/{id}

API keys stay on your backend. Verified personal data is not placed in callback URLs.

Device flows & callbacks

A backend-owned session starts the flow; approved identity information is fetched server-to-server.

View integration flow
View User Flow

Test in the Customer Portal

Run a Session Example before writing the production integration.

Use a test account to choose requested fields, configure a callback, run the Session Example, and inspect the real request, response, session status, and structured result.

Open Developer Area

Agent-ready integration skill

Give your coding agent the Verihop playbook.

One secure source for test setup, server-side sessions, callbacks, results, launch behavior, and concise patterns for Node, Python, Swift, Kotlin, Java, Go, PHP, Ruby, and cURL.

Download SKILL.md

Postman collection

Import the Verihop API collection.

Use a Test key to try the collection. Keep the idempotency key for retries and fetch the result once on your backend.

Download Postman Collection

Basics

Illustrative values below are not reusable credentials. Use the actual returned URLs, IDs and deadlines.

Base URL: https://api.verihop.com

Authenticate partner requests from your backend only:

Authorization: Bearer <api_key>

GET requests have no request body. Session status and result reads use the matching Test or Live key; JWKS needs no API key.

Create a test account first to get an API key for integration. Test-account responses are redacted by design, and the same account can later be upgraded to active for production.

Test redacts returned personal values; phone checks still process identity data. Live access requires separate use-case, field, callback and go-live approval.

Create a test account

POST /v1/sessions

Create a verification session and receive the public launch fields.

The examples use a Test key. Live verification settings are provided when your account is activated.

This example requests Personal Details and document details from either an ID card or a passport; it does not require both.

Session timing and expiry
  • Use the returned expires_at as the absolute deadline. Opening the link or continuing verification never extends this deadline.
  • Never reuse expired launch or callback tokens. Resolve the previous attempt before deliberately starting a new Session; an uncertain result exchange must not trigger an automatic replacement.
  • Verihop never refreshes a Session automatically. The partner must create the replacement Session; compatible documents already verified and stored locally may still be reused.

Headers

Authorization: Bearer <api_key>
Content-Type: application/json
Idempotency-Key: <uuid>

Body

{
  "app": "RideNow",
  "header": "Identity details",
  "fields": ["legalName", "over18", "documentNumber", "documentExpiry"],
  "allowedDocuments": ["idCard", "passport"],
  "callback": "https://partner.example/verihop/callback"
}
Body element guide
  • app: Partner app display name shown inside Verihop (max 80 chars).
  • header: Short verification title shown to the user (max 120 chars).
  • fields: List the catalog tokens you need. An omitted or empty list requests no fields.
  • allowedDocuments: Optional document-type allowlist using passport, idCard, driverLicense, or residencePermit. Omit it to accept any supported document type; do not send an empty array.
  • callback: Base return URL sent in POST /v1/sessions. Verihop opens it after completion and appends session_id, result_token (success path), and optional callback_jwt; required and allowlist-validated in your production policy.
Fields, allowed documents, and minimum evidence

fields says which verified values you request. allowedDocuments says which document types may provide evidence.

{
  "fields": ["legalName", "over18"],
  "allowedDocuments": ["passport", "idCard"]
}

This means Passport OR ID Card is eligible. It does not require both. The user chooses the concrete document used by each relevant section in the Verihop app.

  • passport, idCard, driverLicense, and residencePermit are cumulative document-type assertions (AND). A request such as ["legalName", "passport", "idCard"] requires Passport + ID Card.
  • documentNumber, documentExpiry, documentCountry, and documentNationality are one detail bundle. With explicit required types, they apply to each compatible required contributor; without one, the holder chooses one eligible document for the whole bundle. Driving licences do not supply documentNationality.
  • Personal facts are global and conflict-safe; committed evidence can establish them without requiring another document.
  • A holder may have multiple documents of the same type, including two passports from the same issuing country. Document type is not a unique identifier; receipt-backed partner evidence is distinguished by receiptId.
  • Impossible combinations are rejected at creation. Requiring Passport while allowing only ID card is invalid. A Driver's licence-only request for documentNationality is also invalid.
Header element guide
  • Authorization: Partner API key in bearer format.
  • Content-Type: Use application/json for request body parsing.
  • Idempotency-Key: Recommended for creation retries. Generate a UUID for each new attempt and reuse it only with the identical request body.
Success 201 response
{
  "session_id": "sess_123",
  "expires_at": 1893456900,
  "launch_url": "https://www.verihop.com/verify.html?session_id=sess_123&token=h_example123456789",
  "app_clip_url": "https://appclip.apple.com/id?p=KycBox.VerifyBox.Clip&session_id=sess_123&token=h_example123456789",
  "qr_url": "https://www.verihop.com/verify.html?session_id=sess_123&token=h_example123456789",
  "status_url": "https://api.verihop.com/v1/sessions/sess_123"
}
Response element guide
  • session_id: Unique session identifier for tracking and result retrieval.
  • expires_at: Session expiry (Unix epoch seconds).
  • launch_url: Primary URL for web, Android, QR codes, emails, SMS, and general handoff.
  • app_clip_url: Direct native App Clip URL for iOS partner apps. Open it exactly as returned; do not reconstruct it.
  • qr_url: QR-safe URL; currently equivalent to launch_url.
  • status_url: Session status endpoint for server-side polling.
Common errors
  • 401 missing_bearer_token, 401 invalid_api_key
  • 403 customer_inactive
  • 400 missing_callback_url, invalid_callback_url, callback_host_not_allowed
  • 400 field_not_allowed, invalid_field_token, invalid_allowed_documents
  • 409 idempotency_key_conflict, idempotency_key_in_progress, idempotency_key_expired
  • 413 request_too_large
  • 429 rate_limit_exceeded, daily_quota_exceeded

GET /v1/sessions/{id}

Optional: monitor session progress without fetching personal data.

Authorization: Bearer <api_key>
Success 200 response
{
  "session_id": "sess_123",
  "status": "issued",
  "issued_at": 1893456000,
  "expires_at": 1893456900,
  "last_status": null,
  "last_status_at": null,
  "opened_at": null,
  "result_available": false,
  "result_token_expires_at": null
}

A completed session can show status: "used" and last_status: "success". result_available means a result was stored; it can remain true after consumption or expiry. Fetch the result once, before its deadline.

Polling is read-only and never marks a session as opened. A completed Test-key session also includes result_token, so you can fetch its redacted result in Postman. Live result tokens come through the callback.

GET /v1/sessions/{id}/result

Fetch verified result payload server-to-server using one-time result token.

A launch token starts with h_ and cannot be used here. X-Result-Token requires the short-lived res_ token from a live callback or completed test-key status response.

Authorization: Bearer <api_key>
X-Result-Token: <result_token>
Success 200 response

Illustrative Test response for the request above: the user chose an ID card. Personal values are redacted; IDs and timestamps are examples.

{
  "session_id": "sess_123",
  "status": "success",
  "result": {
    "legalName": "XXXTEST_USERXXX",
    "over18": "XXXTEST_USERXXX"
  },
  "personalDetailsDocument": {
    "type": "idCard",
    "issuingCountry": "ESP",
    "receiptId": "dr_AAAAAAAAAAAAAAAAAAAAAAAA"
  },
  "documents": [
    {
      "type": "idCard",
      "issuingCountry": "ESP",
      "receiptId": "dr_AAAAAAAAAAAAAAAAAAAAAAAA",
      "details": {
        "documentNumber": "XXXTEST_USERXXX",
        "documentExpiry": "XXXTEST_USERXXX"
      }
    }
  ]
}

result contains requested Personal Details only. personalDetailsDocument identifies the verified document selected by the user as their Personal Details source. The same document also appears in documents[]; that duplication is deliberate and is not an additional verification.

Document-only results omit personalDetailsDocument.

documents[] contains every unique document that supported the Session: the Personal Details source, generic Document Details source, and each exact required-document source. Every entry contains type, issuingCountry, receiptId, and details. When no document details were requested, details is {}. Internal field attribution is never exposed.

  • This endpoint delivers the approved private result once. Each receiptId points to that document’s historical verification evidence.
  • Complete verification → receive the callback → fetch the result and receipt IDs.
  • For a multi-document result, retrieve each documents[].receiptId independently with GET /v1/document-receipts/{receipt_id}. There is no combined receipt endpoint or combined JWS.
  • Retrieving a Document Receipt is repeatable, but it does not recover or replay this private result payload.
  • Private result access ends at the earlier stored Session or result-token deadline. At or after that exact boundary, the response is 410 result_token_expired; receipt reads and verification stay independent.
  • One unique supporting document produces one Document Receipt; two unique supporting documents produce two.
  • When a saved verification is reused, the receipt preserves the original verified_at; reuse is not represented as a new document verification.

Test mode

Test mode preserves this exact structure and redacts only actual Personal Details and document-detail values with XXXTEST_USERXXX. It does not redact type, issuingCountry, receiptId, or structural keys.

Common errors
  • 401 missing_bearer_token, invalid_api_key, missing_result_token
  • 403 customer_inactive, api_key_environment_mismatch, invalid_result_token
  • 410 result_token_expired
  • 409 result_token_used
  • 404 result_not_available, session_not_found
  • 503 document_receipt_unavailable

GET /.well-known/jwks.json

Public verification keys for callback JWTs and Document Receipts.

No API key is required. The cache lifetime is 300 seconds. Verify signatures and claims on your backend; if key discovery fails or the key is unknown, stop verification.

Success 200 response
{
  "keys": [
    {
      "kty": "RSA",
      "kid": "example-key-id",
      "alg": "RS256",
      "use": "sig",
      "n": "...",
      "e": "AQAB"
    }
  ]
}

DOCUMENT RECEIPTS · OPTIONAL

GET /v1/document-receipts/{receipt_id}

Retrieve an already-issued Document Receipt from your partner backend. Persistent retrieval is an optional extension to the four-step Sessions integration.

Authorization: Bearer <api_key>
Issuance and reuse
  • Document Receipts are prepared automatically when verification completes. Use the receiptId values returned by GET /v1/sessions/{id}/result to retrieve them.
  • The partner-facing identifier is the opaque dr_.... Internal receipt identifiers and data-model terminology are not part of the public contract.
  • Reuse of the same underlying verification for the same partner returns the same Document Receipt. Different partners receive different Document Receipts. A genuinely fresh verification creates a new receipt lineage.
Success 200 response
{
  "receiptId": "dr_AAAAAAAAAAAAAAAAAAAAAAAA",
  "receiptVersion": 1,
  "issuedAt": "2026-09-11T12:00:00.000Z",
  "document": {
    "type": "idCard",
    "issuingCountry": "ESP"
  },
  "receipt": "eyJhbGciOiJSUzI1NiIsImtpZCI6InZocmNwdC1yczI1Ni0yMDI2MDkxMS0wMSIsInR5cCI6InZlcm...eyJyZWNlaXB0X3ZlcnNpb24iOjEsInZlcmlmaWNhdGlvbiI6ey4uLn19.signature-placeholder"
}

The abbreviated signature above is a display placeholder, not a cryptographically valid sample receipt. receipt contains the original compact signed JWS, not a URL. The response identifies the document by type and issuing country without identity PII.

Ownership, retrieval, and lifecycle
  • Use the owning partner account's Bearer API key. Knowing a dr_ identifier does not authorize access.
  • A missing receipt and another partner's receipt both return the same non-enumerating 404 document_receipt_not_found.
  • Repeated authorized retrieval returns the same stored JWS. It does not consume or re-sign the receipt and does not perform another document verification.
  • A multi-document result has multiple independent receipt IDs. Call this endpoint once per ID; Verihop does not provide a combined receipt or multi-document JWS.
  • Availability follows the approved receipt lifecycle and historical-key policy. It is not a promise of permanent storage.
verihop_v1 methodology and signature verification

The partner-facing methodology is verihop_v1, version 1. Verihop obtains document information from the supported document, runs its holder-verification flow, checks liveness, and matches the presented person against the document-holder evidence.

  • Successful completion is presented as verification outcome verified, holder verification passed, and liveness passed.
  • A successfully verified stored document can support later Sessions without a new face, selfie, or liveness step merely because it is reused.
  • The methodology does not claim separate issuer or document cryptographic authentication.
  • Historical evidence does not establish that a document is currently valid and does not bind or authenticate the complete Session result payload.
  • A receipt is not a global person/document identifier or cross-partner identity lineage.

Decoding a compact JWS is not signature verification. Verify on your backend with the configured Verihop JWKS endpoint. Require alg=RS256, typ=verihop-document-receipt+jwt, a recognized receipt-purpose kid, the configured issuer, and the audience derived from your trusted partner configuration. Do not take a key URL, expected audience, or trust decision from the unverified token. Callback and Document Receipt signing keys are separate purposes.

Handler errors
  • 400 invalid_document_receipt_id
  • 401 missing_bearer_token, 401 invalid_api_key
  • 403 customer_inactive, 403 api_key_environment_mismatch
  • 404 document_receipt_not_found
  • 409 document_receipt_revoked, 423 document_receipt_held, 410 document_receipt_erased
  • 503 document_receipt_verification_unavailable, 503 document_receipt_unavailable

Field Catalog

Request field tokens (fields)

legalName, dateOfBirth, over18, over21, passport, idCard, driverLicense, residencePermit, documentNumber, documentExpiry, documentCountry, documentNationality

Response result fields

result contains requested Personal Details: legalName, dateOfBirth, over18, and over21. Requested document attributes appear in documents[].details. Type requirements such as passport and idCard require those documents; they do not add a boolean field to result or include every document attribute.

Frequently Asked Questions

Can the flow start from a desktop website with a QR code?

Yes. Your backend creates a session using POST /v1/sessions, then renders the returned qr_url inside a QR shown on the desktop page. The user scans that QR with their phone and Verihop opens the best available experience.

Should the QR open a website first, or open Verihop directly?

Best UX is direct launch: encode the returned qr_url. It is the same universal HTTPS handoff as launch_url and supports app, lightweight, and web fallback paths.

Is the deep link the same for iOS and Android?

Use launch_url on Android and for general web handoff. An iOS partner app that wants the native App Clip card should open the returned app_clip_url. Your callback shape remains the same: Verihop appends session_id, success-path result_token, and optional callback_jwt.

How do I launch the Verihop App Clip directly from my iOS app?

Create the session on your backend and send the returned app_clip_url to your iOS app. Open that URL with SwiftUI Link or UIApplication.open on iOS 17 or later. Do not parse launch_url, copy its token, or hard-code Verihop's App Clip bundle ID. If the full Verihop app is installed, iOS opens it instead while preserving the same session.

What should Android partner apps register for callbacks?

If you use a custom callback such as ridenow://verified, the Android partner app must declare an intent filter for that scheme and host. If you use an https:// callback for desktop or web-started flows, treat it as a backend endpoint unless your Android app owns that domain with verified App Links.

For desktop/web-initiated flows, what callback should I use?

Use an https:// return endpoint on your backend. Verihop opens that URL on the phone with session_id and the success-path result_token in the query. This is a user return, not a server-to-server webhook. Your backend validates the stored session binding and fetches GET /v1/sessions/{id}/result. The desktop page can check your backend for completion.

Does POST /v1/sessions return a partner JWT?

No. Creation returns orchestration fields and opaque launch URLs, not a JWT or private identity values. Open the returned URL unchanged.

What does the callback contain?

A successful return includes session_id and result_token, plus callback_jwt when enabled. Some app flows also include status or source metadata. These are not personal results or proof of verification. Validate the session binding, verify any supplied callback JWT, and fetch the approved result on your backend.

Should partners verify callback_jwt, and where?

Yes, on partner backend when present. Verify signature and claims using Verihop JWKS at GET /.well-known/jwks.json. Validate issuer/audience/expiry and ensure JWT claims match callback query values.

Can my frontend call GET /v1/sessions/{id}/result directly?

No. Keep API keys server-side and fetch results from your backend only. The frontend/web client should only handle UI and pass state to your backend session.

How should we handle expiration and retries?

Reconcile a consumed, expired or uncertain result exchange first. Never automatically retry result GET or create another Session. Only a deliberate new logical action starts a new attempt.

What if Verihop is not installed on the phone?

Open the returned launch_url or qr_url; the hosted handoff provides the supported app, App Clip, or installation guidance. On Android, the user can return after installation and tap Open Verihop while the session is still valid. Do not create a replacement merely because installation was needed. After expiry, let the user deliberately start a new attempt.

How does idempotency work, and is misuse protected?

POST /v1/sessions supports Idempotency-Key for retry-safe create-session calls: same key + same payload replays the original response, while same key + different payload returns 409 idempotency_key_conflict. Misuse is further mitigated with API-key auth, callback allowlist policy, field allowlist checks, per-customer rate limits/quota, short session TTL, and one-time result_token.

Example

Open Movie Age-Check Demo

Start in test mode

Create a session and inspect the full handoff.

Use a redacted test account, keep credentials on your backend, and move to production only after callback and field controls are approved.

Privacy-focused identity verification

Get the trusted details your decision needs.

Request verified identity or eligibility details. Customers complete the check on their phone and approve what is shared.

For example:

not ID pictures or selfie files.

Try the live demo
  • Guided mobile journey
  • Approved structured results
  • No document-image result
Verihop flow overview on device Verihop flow step for document and profile checks

From check to trusted details

Ask for what you need. Receive what was approved.

  1. RequestChoose the details your decision needs.
  2. VerifyVerihop handles supported document and holder checks.
  3. ReceiveYour backend receives the approved result.
What the video shows

A service asks for specific details. The customer completes verification on their phone, reviews the request and approves sharing. The service receives the approved result.

Why this matters

Less friction. Less identity data to protect.

Verification should help customers continue, without turning a single decision into another document archive.

More than half

of people in the Netherlands surveyed said they would never share a copy of their passport, ID card or driving licence online.

CBS, 2025
See the research and methodology

In the same FullCircl study, average onboarding took 35 minutes, 2.8 times longer than customers said they wanted. FullCircl, State of Identity Verification 2025

The Dutch privacy regulator reported 39,407 personal-data breach notifications in 2025. Autoriteit Persoonsgegevens, 2026

What you gain

Strong checks. A smoother customer journey.

Select a benefit to see how it works.

Match the holderDocument and holder checks

MRZ and NFC chip reading support the holder comparison.

Keep customers movingGuided check on a supported phone

Completion time can vary by device, document and connection.

Decide right awayResult after a successful check

A successful verification returns the result without a routine manual-review queue.

Handle less sensitive dataApproved structured fields

Receive approved fields, not the customer’s passport image or selfie.

Don’t ask twiceReuse when valid and accepted

Customers can approve a saved on-device verification when it remains valid and your policy accepts it.

Compare with document-upload flows
Typical document-upload flow With Verihop
Verify from an imageThe customer submits photos of an identity document for verification. Read the chip + match the holderThe controlled pilot reads document data from the NFC chip and compares the holder with its portrait. It does not authenticate the issuing government.
Wait for the resultAutomated checks may require additional checks or manual review before a decision is available. Get an instant resultSuccessful verification produces the result immediately, with no routine manual-review queue.
Collect the documentPassport, ID, or selfie files may become sensitive data your company needs to receive, store, and protect. Receive only what you needYour system receives the approved verified information, not the customer's passport image or selfie.
Verify them againReturning customers may need to repeat the document and holder check for another request. Reuse when acceptedCustomers can approve a saved on-device verification when it remains valid and your policy accepts it.
Identity document data flowing through a phone into approved fields

Start with the decision

What do you actually need to know?

Age & eligibility

Is this person over 18?

Request a verified age result.

Account onboarding

Who is signing up?

Check the details your onboarding decision needs.

Rentals & access

Is this the right person?

Verify identity before access is granted.

Account recovery

Is this the account holder?

Request a fresh check for sensitive actions.

Verihop verifies the approved details. Your company makes the decision.

Customer Portal

Test the complete handoff before you go live.

Test

Run redacted sessions and inspect the handoff.

Go live

Submit your production setup and field scope for review.

Operate

Monitor sessions, callbacks, usage and team access.

Start with one use case

Which trusted details does your product need?

Bring your customer journey and decision. We’ll map the smallest useful request and a path to testing it.