Developers

From a request to a recorded answer.

Connect Identity Entry without code, or use the HTTP API. Set up a workspace, a policy and a scoped API key, then start checks from your own backend.

No-code connections

Verify and Access can start from the tools a company already runs, with no code. Each one sends the person a verification link and brings the result back to the workspace as Pass, Caution or Fail.

Shopify
Paste the Identity Entry webhook address in your Shopify notification settings. Each order sends the buyer a link.
Stripe, Square, PayPal
Add the Identity Entry address to your payment account. Every completed payment sends the buyer a link.
Eventbrite, Tito, Ticket Tailor
Connect from the workspace. Ticket holders flow in for Access, and check-ins flow back.
Your website
Copy and paste the "Verify with Identity Entry" button, or add a hosted link to your thank-you page or confirmation email.
Sign in with Identity Entry
OpenID Connect, the same standard as signing in with Google. People sign in to your site with a verified identity.

For anything else, use the HTTP API below from your own backend.

Checkout

Identity Entry Checkout is a verification step before your own Pay button, on any store. The buyer verifies, or is recognized from their existing profile without a new scan, and returns to your page with a short-lived signed pass. Each completed checkout is one Verify, $1, including a recognized returning buyer.

POST /v1/checkout/sessions

GET /v1/checkout/sessions/:id

GET /v1/checkout.js

From your server, create a session with a key that has verifications:write. amount_cents is a whole number in the currency's smallest unit. return_url must be on a website listed on one of your buttons in Connections. Send the buyer to verify_url.

curl -X POST "$IDENTITY_API/v1/checkout/sessions" \
  -H "Authorization: Bearer $IDENTITY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "order_number": "1001",
    "amount_cents": 4999,
    "currency": "usd",
    "merchant_reference": "cart_77",
    "buyer_email": "buyer@example.test",
    "return_url": "https://shop.example.test/checkout"
  }'

{ "session": { "id": "chk_…", "status": "open", "order_number": "1001",
    "amount_cents": 4999, "currency": "usd", "result": null, "account_id": "ten_…" },
  "verify_url": "https://api.identityentry.com/v1/checkout/verify?session=chk_…&k=…",
  "jwks_url": "https://api.identityentry.com/oidc/jwks" }

Without a server, add the script and a button before your Pay button. The script opens the verify window, keeps the Pay button named in data-pay-button disabled until a pass with an accepted result arrives (data-accept, default pass), puts the pass in a hidden field (data-field-name, default identity_entry_pass) and fires an identityentry:checkout event with pass, session_id and result. Use data-session-url with a server-made verify_url instead of a publishable key.

<script src="https://api.identityentry.com/v1/checkout.js" async></script>
<button type="button" data-identity-entry-checkout="pk_ie_…"
  data-order-number="1001" data-amount-cents="4999" data-currency="usd"
  data-pay-button="#pay">Verify identity</button>
<button id="pay" type="submit">Pay</button>

On return the page address carries ie_checkout_session, ie_checkout_result and ie_checkout_pass. The pass is an RS256 JWT signed with the keys at /oidc/jwks. Before charging, check the signature, typ, aud (your account id), exp (10 minutes) and that the order number and amount match your order, or call GET /v1/checkout/sessions/:id.

header  { "alg": "RS256", "typ": "ie-checkout+jwt", "kid": "…" }
payload { "iss": "https://api.identityentry.com", "aud": "ten_…", "sub": "chk_…",
          "session_id": "chk_…", "order_number": "1001", "amount_cents": 4999,
          "currency": "usd", "merchant_reference": "cart_77", "result": "pass",
          "verification_id": "ver_…", "reused_profile": false,
          "iat": 1790000000, "exp": 1790000600, "created_at": 1789999900,
          "completed_at": 1790000000 }

Results are pass (verified), caution (in review) and fail (rejected). A finished checkout sends checkout.session.completed to your webhooks with the session in data.session. A later review shows on the session as current_result.

Shield

Identity Entry Shield keeps Chargeback Evidence Records. Each completed Verify linked to an order becomes a tamper-evident record: the ID, face match and liveness results with their times, the consent, and the order it belongs to. Records are kept for 2 years. Shield is $100 a month per business, and these endpoints need an active Shield subscription.

GET /v1/shield/evidence?transaction=…

GET /v1/shield/evidence/:id

POST /v1/shield/dispute-packages

GET /v1/shield/dispute-packages/:id/pdf

Look up a record by transaction (the processor id, such as pi_…, or a platform reference, such as shopify:1042) or by order_number, using a key with verifications:read. To answer a chargeback, create a dispute package with evidence_record_id or transaction, plus an optional dispute_ref and reason, using a key with verifications:write. Then download it as a PDF.

A record shows what Identity Entry checked and when. It does not prove who owns the card, and it does not decide how a chargeback ends.

Create a verification

Send this from your backend with a scoped workspace API key. subject_id is your own reference for the person and policy_id selects a configured policy. Repeating a request with the same idempotency key returns the original response.

curl -X POST "$IDENTITY_API/v1/verifications" \
  -H "Authorization: Bearer $IDENTITY_API_KEY" \
  -H "Idempotency-Key: onboarding-001" \
  -H "Content-Type: application/json" \
  -d '{
    "subject_id": "user_001",
    "policy_id": "pol_default",
    "external_reference": "onboarding-001"
  }'

Response shape

Timestamps are in milliseconds. The returned subject ID is the internal identifier, not the one you sent.

{
  "verification": {
    "id": "ver_…",
    "status": "created",
    "subject_id": "subj_…",
    "external_reference": "onboarding-001"
  },
  "capture_url": "https://app.identityentry.com/verify#…",
  "expires_at": 1790000000000
}

send_capture_email is not part of this endpoint. Capture-link email belongs to the signed-in workspace flow below.

Operator workspace

The workspace uses cookie-authenticated operator endpoints behind a same-origin backend, separate from bearer API keys. Setup and login create an HttpOnly, Secure, SameSite=Lax session cookie. Browser code never receives the setup token or a workspace API key.

POST /v1/operator/setup

POST /v1/operator/login

GET /v1/operator/workspace

POST /v1/operator/logout

Capture-link email

In the workspace, the new check dialog can email the capture link when the operator selects that option and enters a valid address. The cookie-authenticated request may include send_capture_email: true; the bearer route does not.

Email status is stored and reported carefully. sending means confirmation is in progress. accepted means our email service took the message, which does not guarantee it reached the inbox. failed covers a known rejection, and unknown means the outcome could not be confirmed. Unknown results are not retried, so keep the capture link at hand to share another way.

Authentication

Verification endpoints require a Bearer API key. Reads need verifications:read; create and cancel need verifications:write. Capture uses a separate short-lived token scoped to one session. A workspace API key never belongs in browser code.

Capture session

The capture URL carries its token in the fragment, and the client sends it in x-capture-token. A session is valid for 30 minutes from when it is issued, and the server also checks its stored token hash and expiry.

GET /v1/capture/state

POST /v1/capture/upload?kind=document_front

POST /v1/capture/submit

Accepted kinds are document_front, document_back, selfie and liveness_frame. Uploads must be JPEG, PNG or WebP, no larger than 8 MiB, and follow the step order of the session.

Retrieve and cancel

GET /v1/verifications/:id

GET /v1/verifications?external_reference=…

POST /v1/verifications/:id/cancel

The reference lookup needs an exact external reference and is not a list API. A completed verification cannot be cancelled. Use signed webhook events for result updates rather than a recurring refresh loop.

Signed webhooks

The backend sends identity-entry-signature as t=<seconds>,v1=<hex>. The HMAC-SHA256 input is the timestamp, a period and the exact raw request body.

HMAC-SHA256(webhook_secret, timestamp + "." + raw_body)

identity-entry-signature: t=1790000000,v1=<hex digest>

Check the timestamp and compare signatures in constant time before acting on an event. The verification helper uses a 300-second tolerance, and failed deliveries are retried from the queue.

Outcomes and limits

verified, manual_review and rejected are policy decisions, shown in the workspace as Pass, Caution and Fail. Capture and processing have states in between, and sessions can expire or be cancelled.

Missing evidence follows the uncertainty setting in your policy. Responses include the identity fields your policy keeps, never internal scores or model reasons.

Open developer tools

Access

People verify once (ID, face and liveness) and then walk in by their face. An entry list is an event, a building or a departure; each has doors and passes, one per person. Each person on a list uses one Access check, package access, $2 per person.

POST /v1/entry-lists

GET /v1/entry-lists?kind=event

GET /v1/entry-lists/:id

PATCH /v1/entry-lists/:id

POST /v1/entry-lists/:id/passes

GET /v1/entry-lists/:id/passes?q=…

PATCH /v1/entry-lists/:id/passes/:pass

POST /v1/entry-lists/:id/passes/:pass/enrollment-link

POST /v1/entry-lists/:id/doors

POST /v1/entry-lists/:id/doors/:door/link

GET /v1/entry-lists/:id/checkins-csv

POST /v1/entry-lists/:id/checkins/:checkin/void

curl -X POST "$IDENTITY_API/v1/entry-lists" \
  -H "Authorization: Bearer $IDENTITY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "event",
    "name": "Riverside Night Market",
    "starts_at": "2026-11-07T18:00:00-05:00",
    "return_url": "https://tickets.example.test/registered",
    "code_mode": false,
    "reentry": "none"
  }'

Add people at ticket purchase, up to 100 per request, or as CSV in a csv field. Each pass returns an enrollment_url for your confirmation email or a button on your own page. A person already enrolled with your account is enrolled on the new list at once. After their ID check passes they are sent to the list's return_url with ie_pass, ie_ref and ie_status=enrolled, so your flow continues.

curl -X POST "$IDENTITY_API/v1/entry-lists/lst_…/passes" \
  -H "Authorization: Bearer $IDENTITY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "passes": [
    { "name": "Ines Varga", "email": "ines@example.test",
      "ticket_code": "GA-104", "external_ref": "order_1042", "guests": 0 }
  ] }'

{ "created": [{ "id": "pas_…", "status": "invited",
    "enrollment_url": "https://app.identityentry.com/enroll#enr_…" }],
  "errors": [], "balance": 1499 }

Re-entry is none (once, or once per day when dates lists the valid days), unlimited (buildings) or limited with max_entries. Passes can carry a ticket code, guests, a zone, a validity window and a building schedule. Transfer a pass with transfer_to: the old face stops working and the new holder enrolls with a new link. Under 18s are not enrolled; add them as guests on an adult's pass.

Staff open the door app from a door's signed link or QR code on their own phone or tablet. The camera matches each face against that list only and answers green (go in), amber (already in, wrong entrance or day, enrollment pending) or red (see staff). Nothing is stored from a door scan except the result. Webhooks: identity.enrollment.completed, identity.checkin.created, identity.checkin.deleted, plus identity.pass.created and identity.pass.updated.

{ "type": "identity.checkin.created",
  "data": { "list_id": "lst_…", "pass_id": "pas_…", "external_ref": "order_1042",
            "ticket_code": "GA-104", "direction": "in", "party_size": 1,
            "door_id": "dor_…", "manual": false } }

MCP and API access

The API and the MCP server need an Identity Entry account with Shield ($100 a month) or $100 or more of Verify or Access. Without one, every call answers 402 with account_required and the sign-up link. Create an account at identityentry.com/signup.

POST https://api.identityentry.com/mcp

Add https://api.identityentry.com/mcp as a remote MCP server in your agent. It signs you in with your Identity Entry account through OAuth, then lists its tools: create_verification, get_verification, find_verification, list_verifications, cancel_verification, create_checkout_session, get_checkout_session, get_pricing and the Shield evidence tools. Every tool works only on your own account.

The REST API uses your API key from developer tools as Authorization: Bearer. The Checkout script on your store and your buyers' verify pages need no key and keep working for your buyers.

Start checking IDs with confidence.

Run a check on yourself first and see exactly what your customers will see.

Get started