API Reference
Create verifications and retrieve results programmatically using the REST API.
Base URL
All API requests are made to:
Authentication
All endpoints except /auth require a Bearer token in the Authorization header. Obtain a token by calling the auth endpoint
with your account credentials.
POST /auth
Exchange your email and password for an access token.
Authorization: Bearer header401 response on
any endpoint, re-authenticate to get a fresh token. Rate limit: 5 attempts
per minute.Create Verification
POST /verification
Create a new verification request. Returns a unique URL to send to the person being verified.
"passphrase", "custom", or "none".
Required when the request collects personal data and the template does
not set one. The legacy "shared" mode is no longer accepted
for new verifications."custom" this can
also be a PEM-encoded RSA public key. For "passphrase" it
must be the ID of a passphrase key created in the dashboard. Required
unless the template supplies one.false).
Makes the request a Full verification.false).
Adds the address_verification indicators to the result (see Indicators). Makes the request a Full verification.false). Adds the location_consistency indicator to the result. Makes the
request at least a Basic verification.false). Makes the request a Full verification.external_id so
you can correlate results with your own system. Use values like UUIDs,
order numbers, or hashes — e.g. "PO12345", "job-candidate-1". Do not include names or other personally
identifiable information. See the template notes below.1 to 90 (default: 14). An unfinished link holds one
of your verification slots until it completes, expires, or is canceled,
so shorter lifetimes free unused slots sooner.Templates, Defaults & Gotchas
All fields are optional. If template_id is provided, its settings
are used as defaults — any field you explicitly provide overrides the template
value, and fields you leave out inherit it. A few things behave differently from
the dashboard:
- Template Request Rules are not enforced by the API. The Request Rules on a template (for example "require the
custom message to be changed" or "require a Reference ID") are checked only
by the dashboard's New Request form. An API call that references the
template can omit
external_idor send the template's message unchanged, and it will still succeed. If your integration depends on those values, validate them in your own code before calling the API. - Templates are a starting point, not a link. The verification copies the template's values when it is created. Editing the template later never changes verifications that already exist.
external_idis never inherited. Templates supply defaults for most settings, but not for the reference ID; it is always set per request.- The verification type is derived, not requested. There
is no
verification_typefield. The server works out Core, Basic or Full from what you ask for: any phone, address or license-photo option, or any field beyond name and address, makes it Full; name and address fields or the location check make it Basic; otherwise it is Core. The type determines which of your plan's verification allowances is used. - Encryption only applies when personal data is collected. If the request has no
requested_fields, phone verification or cropped headshot from license,encryption_key_modeis ignored and treated as"none". - Quota is checked at creation. When you have no
verifications of the needed type remaining, the request is rejected with a
402and the codeQUOTA_EXCEEDED.
Available Requested Fields
Example — Minimal Request
Example — Using a Template
Example — Full Custom Request
Send the url to the person being verified (via email, SMS, or embedded
in your app). They open it on their mobile device to complete the flow —
no app install required.
Rate limit: 100 requests per hour.
Get Verification
GET /verification?id={verification_id}
Retrieve the status and results of a verification. For completed verifications, the response contains the same data that was (or would be) delivered via webhook.
The response shape depends on the verification status:
Pending or Started
When status is "started", a started_at timestamp is also included.
Completed
result is the same payload your webhook receives. The address_verification and location_consistency objects
appear only when those checks were requested and able to run — see Indicators. If the personal data was purged, a pii_purged_at timestamp is also included.
Expired or Canceled
A "canceled" request has the same shape. Canceled and expired
requests carry no result data.
Manual Review
Same shape as completed, but status is "manual_review". This means the face match was inconclusive and
the end user submitted their images for human review.
Rate limit: 300 requests per hour.
Verification Statuses
Indicators
Indicators check details from the license against outside data sources and
add extra confidence in who you're dealing with. They appear in result (and in the webhook payload) alongside the standard
checks. For how to interpret them, and why a negative result is not proof
of fraud, see Data Fields & Indicators.
false,
when they could not run. For example, the address and location checks
need the barcode on the back of the license, and an outside data source
may be temporarily unavailable. Always test for the presence of the object
before reading it.address_verification
Present when address_verification was requested. Every Full request can include it.
true if the license address is a real, deliverable postal
addresstrue if the first and last name on the license are on
record at that addresstrue if the last name matched (often a household member)location_consistency
Present when location_consistency was requested. Available on Basic and Full requests. Informational
only — it never changes the overall result.
"consistent", "inconsistent", or "inconclusive". Inconclusive is common and not a negative
signal on its own.true for a VPN, proxy, Tor or hosting-provider connection; null when that data was unavailable"yes", "probably", "maybe" or "no", with a 0–100 score"city", "subdivision", "country" or "none"null unless a
distance could be measurednull when not applicablevpn, tor, hosting_provider, imprecise_ip_location, ip_not_located, address_not_geocoded or outside_expected_rangetrue if the connection changed between the barcode step
and submissionProxy detection (in verification)
Included in every verification's verification object, for all types.
true if the connection's IP address was found in the
intelligence datatrue if the connection came through a known proxy or
anonymizing serviceis_proxy is trueFace Match Scores
The face_match_score field in the verification result indicates
how confidently the selfie face matched the license photo:
See Face Match Scoring for a detailed breakdown of how scores are computed.
Error Responses
All errors follow a consistent format:
Validation errors include a details array listing each issue:
Error Codes
verification_type that ran out.Encryption
When encryption_key_mode is set:
- passphrase — PII is encrypted in the end user's
browser with a one-off ECDH P-256 public key derived from a passphrase you
chose in the dashboard (ECDH + HKDF-SHA256 + AES-256-GCM). The encrypted
data is passed through along with an
encryption_keyobject holding the non-secret Argon2id salt and parameters, so you can re-derive the private key from your passphrase. We cannot decrypt it. - custom — PII is encrypted with your RSA public key (RSA-OAEP + AES-256-GCM). The encrypted envelope is passed through for you to decrypt with your private key.
- none — PII fields are returned as plaintext,
filtered to only your
requested_fields. Intended for testing with your own information. - shared (legacy) — verifications created before passphrase keys existed. Their data is viewable only on the dashboard and appears as a placeholder in API and webhook responses.