Following the acquisition, Onfido is now known as Entrust.Read more
Onfido LogoOnfido Logo

Developers

Biometric Passkey: Core API integration

Introduction

This guide is for engineers integrating your backend with the Biometric Passkey Core API. It covers the prerequisites, supported integration flows and the API contract concepts shared by every flow, webhook delivery, error handling, observability, and versioning.

The Core API is the API your backend calls. The Management API is a separate operations API used by your operations teams and is covered in Biometric Passkey: Dashboard and API management.

Please note: The Biometric Passkey API is exclusively for the management of biometric passkey credentials and is distinct and separate from the Entrust IDV API. For integrating with the Entrust IDV API, please refer to our documentation here.

Before you begin

Confirm the following before you start server-side integration:

  • A Biometric Passkey backend is deployed in your infrastructure with TLS-terminating ingress that limits inbound access to your backend and the IDV webhook source. See Biometric Passkey: Deployment.
  • Confirm your platform team has deployed the Core API with the required runtime configuration before sending traffic to it. This guide names the integration-facing values that shape API behavior; the deployment guide covers release bundles, chart values, runtime Secrets, and infrastructure setup. See Configuration values used by Core API flows.
  • Your application has a registered passkey relying party (RP), owned by your backend or your IDP. Biometric Passkey does not act as the RP and does not perform WebAuthn cryptographic verification.
  • Your backend has a stable per-user identifier that you will pass as external_user_id. The value is opaque to Biometric Passkey and must use URL-safe characters only: A-Z, a-z, 0-9, ., _, ~, and -. If your canonical user identifier uses other characters, map it to a stable URL-safe surrogate before calling the Core API.
  • Your mobile applications have integrated the Biometric Passkey SDK. The SDK and any browser client talk to your backend, not to the Core API directly. See Biometric Passkey: SDK integration.

Integration architecture

For the component model, ownership split, and the diagram, see Integration overview: Integration architecture.

API basics

Request and response conventions

ItemDetails
TransportAll request and response bodies are JSON. Timestamps are RFC 3339 UTC strings.
IdentifiersYour application supplies a stable URL-safe per-user identifier (external_user_id); the Core API mints a per-flow session identifier when a new flow is opened. Treat all identifiers as opaque strings.
Opaque tokensThe Core API issues short-lived tokens to bind specific transitions inside a flow (finalize_token, handoff_token, continuation_token, recovery_token). Treat returned tokens as opaque; do not parse, log, or persist them beyond the in-flight flow. Lifetimes are listed under Token lifetimes.
State machinesEach flow advances by explicit calls; sessions expire automatically per TTL.

Request headers

  • X-Correlation-ID (optional, recommended) — an opaque identifier you assign to each end-user action. Biometric Passkey records it on backend logs and audit events so a single failure can be traced across your edge, your backend, and the management dashboard.
  • Idempotency-Key (optional) — an opaque caller-chosen identifier accepted only by the flow-opening (start) endpoints. On those endpoints, Biometric Passkey combines the key with the request's business context to recognise a retry and return the existing in-flight attempt or session instead of opening a duplicate. Other endpoints replay through the path-bound session identifier or the flow state machine.

Configuration values used by Core API flows

The Core API request and response contract is independent of the deployment mechanism. Before you call the API, confirm these integration-facing values with the team that operates your Biometric Passkey backend:

AreaValue to confirmIntegration impact
Core API originHTTPS origin for your deployed Core APIYour backend sends all /api/internal/v1/... requests to this origin. Browser and mobile clients do not call the Core API directly.
Registration workflow IDPublished Entrust Identity Verification workflow used for enrollmentRegistration start requests use this workflow to perform identity verification and produce the encrypted biometric token stored for later checks.
Step-up workflow IDPublished Entrust Identity Verification workflow used for high-assurance authenticationStep-up start requests use this workflow for live biometric verification against the stored encrypted biometric token.
Recovery workflow IDPublished Entrust Identity Verification workflow used during account recoveryRecovery requests use this workflow to verify the recovering user before replacement credential creation.
IDV webhook routeProvider callback route for identity verification resultsFlow status can remain pending until webhook delivery succeeds. Your backend does not call this route; it polls the flow status endpoints documented below.

For the deployment-time configuration and infrastructure settings behind these values, see Biometric Passkey: Deployment.

Errors and retries

All errors return the same envelope:

json
1{
2 "error": {
3 "code": "string",
4 "message": "string",
5 "retryable": false,
6 "details": { "field": "string" }
7 }
8}

error.details is optional. When present, it is a flat map of string values. Use it to identify the offending field name or a short machine-readable hint to your operators; do not rely on nested structures.

StatusTypical causesRecommended action
400 validationMissing field, malformed payload, invalid request body, or schema validation failureFix the client; do not retry the same request unchanged.
403 forbiddenCaller ownership, auth context, or recovery-token context is not authorized for the requested resourceCheck the user and flow binding; do not blindly retry.
404 not foundThe referenced session or user does not existVerify the identifier; do not retry.
408 timeoutThe request timed out or was canceled before completionRetry the same logical request.
409 conflictToken already consumed, state transition not legal, expired session, or retryable wait state such as WORKFLOW_NOT_COMPLETED or RESOURCE_BUSYBranch on error.code and error.retryable. Retry only when retryable is true; otherwise inspect state or restart the affected flow.
422 unprocessablePayload is well-formed but fails flow-specific semantic validation, such as an invalid passkey bundle, applicant input, workflow input, or prior-biometric inputFix the supplied data or issue a fresh passkey bundle; do not retry the same payload unchanged.
429 rate limitedExcessive request rate on recovery start or recovery IDV start (RECOVERY_RATE_LIMITED). Apply any broader request-rate policy at your ingress.Honor Retry-After; back off and retry.
500 internalUnhandled server-side error inside the Core API, including temporary webhook processing delayRetry with exponential backoff, preserving Idempotency-Key when the original request carried one.
502 upstreamThe identity verification provider is unavailable or returned an unexpected responseRetry with exponential backoff. Persistent 502 is an operational incident, not a client bug.

The error.retryable boolean is the authoritative signal for safe retry. When retryable is true, retry with the same payload. Preserve the same Idempotency-Key only on endpoints that accept the header; path-bound session endpoints replay through the session identifier and flow state machine.

Two flow-specific cases are worth handling explicitly:

  • Enrollment and recovery conflicts: a user can have at most one active enrollment attempt and at most one active recovery attempt at the same time, and recovery start is blocked while enrollment is in flight for the same user. Duplicate enrollment starts are rejected unless you replay the original start with the same Idempotency-Key. Recovery start does not accept Idempotency-Key; if an active recovery attempt already exists for the same user, Biometric Passkey returns 200 OK with that attempt and a fresh replay of the same recovery_token. If recovery is blocked by an active enrollment attempt, the backend returns HTTP 409 with error.code = "REGISTRATION_ATTEMPT_CONFLICT". Step-up authentication, both in-app and cross-platform, is not affected because sessions are scoped per request context, not per user.
  • Reserved identity verification workflow input: the encrypted_biometric_token key inside workflow_input.custom_data is reserved by the Biometric Passkey backend, which supplies that workflow input on your behalf from either the prior_biometric field at registration time or the user's stored biometric reference for step-up and recovery. If your request sets workflow_input.custom_data.encrypted_biometric_token, the backend rejects it with HTTP 422 and error.code = "IDV_WORKFLOW_INPUT_INVALID". Remove the key from your request payload and let the backend populate it.

Webhook delivery

Identity verification runs asynchronously. The identity verification provider delivers result events to your Biometric Passkey backend, which validates and processes them to advance flow status. Your backend does not implement or call this webhook; it is reached only by the provider.

What this means for your integration:

  • You do not handle the webhook. When a result arrives, the affected flow advances on its own to its identity verification completed or failed state.
  • Observe results by polling the per-flow status endpoint listed under Integration walkthrough. Polling is safe and idempotent; preserve X-Correlation-ID across polls to keep traces joinable.
  • Flow status can remain pending until a result is delivered, so treat status transitions as eventual rather than immediate.

Webhook signature verification and the provider-event freshness window are configured at deployment time. See Biometric Passkey: Deployment.

Logging, correlation, and observability

For every Core API request your backend issues:

  • Send a single X-Correlation-ID per logical end-user action. Reuse it across all backend requests, polling calls, and webhook handlers that belong to the same flow.
  • Log the request method, path, response status, error.code (if any), and the correlation identifier. Do not log any field named token or ending in _token, SDK IDV tokens, EBT ciphertext, WebAuthn payloads, or signatures.
  • Preserve the correlation identifier through your edge logs so a single user-visible failure can be traced end-to-end from your edge to the Core API to the identity verification provider and to the management dashboard.

Versioning and deprecation

The Core API uses a versioned path prefix that is decoupled from the deployment release cadence.

  • The backend integration API is exposed under the path prefix /api/internal/v1. Every endpoint documented in the endpoint groups below lives under this prefix. In this prefix, internal means browser and mobile clients do not call these endpoints directly; your backend is the caller.
  • Treat the hosted OpenAPI reference for your deployed release as the contract source. Your client must tolerate unknown response fields and unknown error codes by falling back to error.retryable.
  • Pin your client to a single path prefix per environment. Confirm the supported prefix and any migration guidance for your release with your Entrust contact.
  • GET /api/health is the liveness and health endpoint. GET /api/version returns the running server's build information for identifying which version a deployment is serving.

For supported backend release lines, SDK compatibility, upgrade planning, and the compatibility matrix, see Biometric Passkey: Version policy.

Integration walkthrough

This section covers the four flows your backend integrates against the Core API: registration, in-app step-up, cross-platform step-up, and account recovery. Each subsection has a sequence diagram, the endpoints your backend calls, the steps in order, and the failure paths to handle.

How every flow is shaped

All four flows follow the same pattern, so it is worth reading this once before the individual flows:

  • Your backend is the only caller of the Core API. Your app and the SDK talk to your backend; they never call the Core API directly. Your backend forwards challenges and tokens out to the device and forwards the device's results back to the Core API.
  • Your IDP owns the passkey; the Core API binds identity to it. The Core API is not a WebAuthn relying party and performs no WebAuthn cryptographic verification. Your IDP issues the challenge and verifies the attestation or assertion. The Core API ties an identity verification result to that passkey operation.
  • Identity verification is asynchronous. The SDK captures identity on the device against Entrust Identity Verification. The provider returns the result to the Core API separately, and the flow advances on its own. Your backend observes progress by polling the flow's status endpoint; it never handles the provider callback.
  • Completion is a prepare → commit → finalize handshake. prepare-complete binds the device's attestation or assertion and returns a short-lived finalize_token. Your backend commits on your IDP, then calls finalize (or abort). These last calls usually run inside a single backend operation.

Every identifier and token below is opaque. Never parse, log in plaintext, or persist a token beyond the in-flight flow. Reuse external_user_id (your stable per-user identifier) across all flows for a given user; treat every Core-minted identifier (registration_attempt_id, km_passkey_session_id, cross_platform_session_id, recovery_attempt_id) as a per-flow handle.

Token lifetimes

TokenLifetimeSingle-useNotes
finalize_token5 minutesYesReturned by prepare-complete; consumed by finalize or abort.
handoff_token10 minutesYesReturned by cross-platform start; consumed by resume. Omitted on a start replay, so persist it when first issued.
recovery_token10 minutes (recovery attempt TTL)NoReusable within the attempt; survives the continuation exchange.
continuation_token10 minutes (recovery attempt TTL)NoReusable across recovery registration/start and prepare-complete within the attempt.

Sessions and attempts expire on their own TTL: a cross-platform session lives 15 minutes and a recovery attempt lives 10 minutes. Registration and step-up attempts expire at the expires_at your IDP sets on the passkey bundle.

Registration

Enroll a user: verify their identity with a document and face capture, create a passkey, and bind the two together. Registration runs on a mobile device because it needs document and biometric capture.

Registration flow: backend orchestrates IDV verification and credential creation, then finalizes to bind the passkey to the verified identity.

Steps

  1. Open the attempt. Ask your IDP for a passkey registration challenge, then call POST /registrations/start with the user's external_user_id, the applicant fields your identity verification workflow requires (at a minimum first_name and last_name), and the IDP-issued passkey_registration bundle (challenge, user_handle, rp_id, expires_at). The Core API opens the attempt and returns registration_attempt_id and an IDV token. Forward the IDV token and the IDP's publicKeyCreationOptions to your app. Send an Idempotency-Key so a network retry returns the same attempt instead of opening a duplicate. To re-enroll a user whose encrypted biometric token your backend already holds, also set prior_biometric.encrypted_biometric_token on this request; never set workflow_input.custom_data.encrypted_biometric_token, which the Core API reserves.
  2. Verify identity and create the passkey on the device. The SDK consumes the IDV token, captures the document and face against Entrust Identity Verification, and runs the WebAuthn ceremony locally. When the workflow completes, the provider notifies the Core API, which stores the user's biometric reference and advances the attempt to idv_completed. The SDK returns the attestation_object and client_data_json to your backend. You may poll GET /registrations/{id}, but you do not have to — the next step reports a clear error if the result has not arrived yet.
  3. Bind the credential. Call POST /registrations/{id}/prepare-complete with the attestation. The Core API extracts and stores the WebAuthn credential_id, binds it to the attempt, and returns a finalize_token valid for 5 minutes.
  4. Commit and finalize. Commit the passkey on your IDP, then call POST /registrations/{id}/finalize with the finalize_token to activate the credential. On IDP commit failure, call POST /registrations/{id}/abort with the same finalize_token and an error_code; the attempt ends in idp_commit_failed. To close an attempt the user backs out of before prepare-complete, call POST /registrations/{id}/cancel.

The attempt advances idv_in_progressidv_completedidp_commit_pendingcompleted. Failure surfaces as idp_commit_failed, failed, cancelled, or expired.

Endpoints

MethodEndpointWhen your backend calls it
POSTStart a registration attemptAlways, once per attempt
GETGet registration statusOptional, to poll progress
POSTPrepare registration completionAlways, after the SDK returns the attestation
POSTFinalize registrationOn IDP commit success
POSTAbort prepared registrationOn IDP commit failure after prepare-complete
POSTCancel registrationOptional, when the user backs out before prepare-complete

Failure handling

TriggerWhat to doResulting state
User backs out before prepare-completeCancel registrationcancelled
Identity verification fails or returns an unapproved resultNothing; the attempt fails on its ownfailed with an error_code reflecting the outcome
finalize returns ENCRYPTED_BIOMETRIC_TOKEN_MISSING (409)Do not retry the token. Reconcile identity verification delivery and start a new attempt if enrollment should continue.failed; the prepared credential is marked registration_failed
IDP commit fails after prepare-completeAbort prepared registrationidp_commit_failed
finalize_token reused or staleDo not retry blindly; fetch status and reconcileFINALIZE_TOKEN_INVALID (409)
Attempt TTL elapsesNothingexpired

In-app step-up

Re-verify an already-enrolled user for a high-assurance action inside your mobile app: a live face capture against the user's stored biometric reference, plus a fresh WebAuthn assertion.

In-app step-up flow: backend starts a step-up session, the app signs the challenge, and the backend finalizes to obtain the authentication assertion.

Steps

  1. Open the session. Ask your IDP for a passkey authentication challenge, then call POST /step-up/auth-sessions/start with the user's external_user_id and the passkey_authentication bundle (challenge, rp_id, expires_at). The Core API returns km_passkey_session_id. The user must already have an enrolled credential; if not, start returns 404 PASSKEY_NOT_FOUND and you must route them through registration. Forward the session id and the IDP's publicKeyRequestOptions to your app.
  2. Start identity verification. The SDK computes a credential_id_hint (the credential it will use) and a client_data_hash (over the exact client data it will later sign) and returns both to your backend. Call POST /step-up/auth-sessions/{id}/idv/start with those two values. The Core API supplies the user's stored biometric reference to the workflow and returns an IDV token for the SDK. If the user has no usable biometric reference, this returns ENCRYPTED_BIOMETRIC_TOKEN_MISSING (409) and you must route them to recovery.
  3. Capture and sign on the device. The SDK runs the live face capture against Entrust Identity Verification and the WebAuthn ceremony, then returns the assertion (client_data_json, authenticator_data, signature) to your backend.
  4. Bind, verify, and finalize. Call POST /step-up/auth-sessions/{id}/prepare-complete with the assertion to get a finalize_token (valid 5 minutes). Verify the assertion on your IDP, then call POST /step-up/auth-sessions/{id}/finalize to mark the step-up completed. On IDP failure, call POST /step-up/auth-sessions/{id}/abort with the same finalize_token and an error_code; the session ends in failed.

The session advances createdidv_in_progressidv_completedauth_finalizingcompleted. Failure surfaces as failed, cancelled, or expired.

Endpoints

MethodEndpointWhen your backend calls it
POSTStart a step-up auth sessionAlways, once per session
POSTStart in-app step-up IDVAlways, to obtain the IDV token
GETGet step-up auth session statusOptional, to poll progress
POSTPrepare step-up completionAlways, after the SDK returns the assertion
POSTFinalize step-up authenticationOn IDP verification success
POSTAbort prepared step-up authenticationOn IDP verification failure after prepare-complete

Failure handling

TriggerWhat to doResulting state
User has no usable biometric referenceRoute the user to recoveryidv/start returns ENCRYPTED_BIOMETRIC_TOKEN_MISSING (409)
Identity verification failsNothing; the session fails on its ownfailed
Credential hint malformed or unknownDo not retry the same values; recompute from the actual SDK outputidv/start returns INVALID_INPUT (400) or PASSKEY_NOT_FOUND (404)
Client-data hash does not match the later assertionRestart with a fresh challengeprepare-complete returns CLIENT_DATA_CONTINUITY_MISMATCH (409)
IDP assertion verification failsAbort prepared step-up authenticationfailed
finalize_token reused or staleDo not retry blindly; fetch status and reconcileFINALIZE_TOKEN_INVALID (409)
Session TTL elapsesNothingexpired

Cross-platform step-up

Step up a high-assurance action that starts in a browser or desktop session where there is no camera. Your backend hands the action off to the user's enrolled mobile device, which performs the same step-up as above; the browser learns the outcome by polling.

Cross-platform step-up flow: web requests a handoff, the mobile app resumes the session, and the web side polls until completion.

Steps

  1. Open the session and deliver the handoff token. From the browser side, call POST /cross-platform-sessions/start with the user's external_user_id and a web_context (session_id required, optional actor_context_id) that binds the session to the originating browser session. The Core API returns cross_platform_session_id and a single-use handoff_token (valid 10 minutes). Persist the handoff token when first issued — a start replay from the same browser context returns the existing session but omits the token. Deliver the token to the user's enrolled mobile device through a channel of your choice (push, QR, or deep link).
  2. Poll status from the browser. While the user picks up their phone, the browser polls your backend, which calls POST /cross-platform-sessions/{id}/status with the same external_user_id and web_context the session was created with. The Core API re-validates ownership on every poll and collapses all in-progress states into pending, surfacing only the terminal states completed, failed, expired, and cancelled. Both session expiry and handoff-token expiry surface as expired.
  3. Resume on mobile. When the user opens the handoff on the device, the mobile app returns the handoff_token to your backend. Call POST /cross-platform-sessions/resume with the token. The Core API consumes it (single-use), moves the session to mobile_resumed, and returns the continuation context. The rest of the flow runs on the mobile device.
  4. Run the mobile step-up. Ask your IDP for an authentication challenge, then call POST /cross-platform-sessions/{id}/auth-sessions/start with the passkey_authentication bundle. This call takes no external_user_id or web_context — the Core API derives the owner from the session — and returns a km_passkey_session_id. The SDK computes credential_id_hint and client_data_hash; call POST /cross-platform-sessions/{id}/idv/start with km_passkey_session_id, credential_id_hint, and client_data_hash to get the IDV token. The SDK runs the live face capture and the WebAuthn ceremony and returns the assertion. On these cross-platform endpoints, km_passkey_session_id travels in the request body, not the path.
  5. Bind, verify, and finalize. Call POST /cross-platform-sessions/{id}/prepare-complete with the assertion to get a finalize_token. Verify the assertion on your IDP, then call POST /cross-platform-sessions/{id}/finalize; on IDP failure call POST /cross-platform-sessions/{id}/abort with the same finalize_token and an error_code. The browser's next status poll then surfaces the terminal state. To close a session the user backs out of before prepare-complete, call POST /cross-platform-sessions/{id}/cancel.

The session advances createdhandoff_issuedmobile_resumedidv_in_progressidv_completedauth_finalizingcompleted. Failure surfaces as failed, expired, or cancelled.

Endpoints

MethodEndpointWhen your backend calls it
POSTStart a cross-platform sessionAlways, once per session
POSTGet cross-platform session statusAlways, while the browser awaits completion
POSTResume cross-platform session on mobileAlways, once, on mobile pickup
POSTStart cross-platform auth sessionAlways, after resume
POSTStart cross-platform IDVAlways, after auth-sessions/start
POSTPrepare cross-platform completionAlways, after the SDK returns the assertion
POSTFinalize cross-platform authenticationOn IDP verification success
POSTAbort prepared cross-platform authenticationOn IDP verification failure after prepare-complete
POSTCancel cross-platform sessionOptional, when the user backs out before prepare-complete

Failure handling

TriggerWhat to doResulting state
User does not pick up the handoff before TTLNothingSession and handoff token both expired; the poll surfaces expired
Handoff token already consumed (replay)Nothing; the original resume stays in effectresume returns a conflict
User has no usable biometric referenceRoute the user to recoveryThe mobile leg cannot continue; branch on the returned error.code
User rejects the action on the device before prepare-completeCancel cross-platform sessioncancelled
IDP assertion verification failsAbort prepared cross-platform authenticationfailed
finalize_token reused or staleDo not retry blindly; fetch status and reconcileFINALIZE_TOKEN_INVALID (409)

Account recovery

Restore access for a user who lost their device: re-verify them with a live face capture against their stored biometric reference, then enroll a replacement passkey. Recovery starts from your own lower-assurance recovery channel.

Account recovery flow: backend orchestrates IDV verification, then re-runs registration to mint a replacement credential.

Steps

  1. Open the attempt. Identify the recovering user through your own recovery channel first; do not call the Core API until you have one authoritative external_user_id. Call POST /recovery-attempts/start with that external_user_id. The Core API checks the user exists, has an active credential, and has a usable biometric reference, then returns recovery_attempt_id and a recovery_token. If the user or active credential is missing it returns 404 PASSKEY_NOT_FOUND; if there is no usable biometric reference it returns RECOVERY_EBT_UNAVAILABLE (409). In either case, route the user to fresh enrollment or operator remediation. The Core API selects the stored biometric reference internally — you do not supply a credential or biometric selector.
  2. Verify identity. Call POST /recovery-attempts/{id}/idv/start with the recovery_token to get the IDV token. (Recovery takes the recovery_token here instead of a credential hint and client-data hash, because there is no assertion to bind yet.) The SDK runs a live face capture against Entrust Identity Verification; on success the attempt moves to idv_verified. Your backend never sees the biometric reference in plaintext.
  3. Exchange the continuation token and open the replacement registration. Once the attempt reaches idv_verified, call POST /recovery-attempts/{id}/continuation/exchange with the recovery_token. The Core API echoes the authoritative external_user_id and issues a continuation_token; the exchange does not invalidate the recovery_token, and a replay returns the existing continuation_token. Ask your IDP for a replacement registration challenge, then call POST /recovery-attempts/{id}/registration/start with the continuation_token and the passkey_registration bundle. The attempt moves to registration_in_progress and the SDK creates the new passkey on the device.
  4. Bind, commit, and finalize, with optional retry. Call POST /recovery-attempts/{id}/prepare-complete with the continuation_token and the attestation to get a finalize_token. Commit the replacement on your IDP, then call POST /recovery-attempts/{id}/finalize. On IDP failure, call POST /recovery-attempts/{id}/abort with an error_code (and the finalize_token if one was issued); the attempt rewinds to idv_verified, so you can call registration/start again with the same continuation_token to retry without repeating the face capture. After finalize succeeds, use the Management endpoints to revoke the user's prior credentials if your policy requires it.

The attempt advances createdidv_in_progressidv_verifiedregistration_in_progressidp_commit_pendingcompleted. Failure surfaces as failed, cancelled, or expired. Unlike the other flows, recovery abort is a non-terminal rewind, not a terminal state.

Endpoints

MethodEndpointWhen your backend calls it
POSTStart a recovery attemptAlways, once per attempt
GETGet recovery attempt statusOptional, to poll progress
POSTStart recovery IDVAlways, to obtain the IDV token
POSTExchange recovery continuationAlways, after IDV reaches idv_verified
POSTStart recovery registrationAlways, with continuation_token
POSTPrepare recovery completionAlways, after the SDK returns the attestation
POSTFinalize recoveryOn IDP commit success
POSTAbort prepared recovery registrationOn IDP commit failure after prepare-complete
POSTCancel recovery attemptOptional, when the user backs out before prepare-complete

Failure handling

TriggerWhat to doResulting state
User or active credential is missingRoute the user to fresh enrollmentstart returns PASSKEY_NOT_FOUND (404)
Active credential exists but no usable biometric referenceRoute the user to fresh enrollment or remediationstart returns RECOVERY_EBT_UNAVAILABLE (409)
Recovery identity verification failsNothing; the attempt fails on its ownfailed
Invalid, unknown, or expired recovery tokenDo not retry; fetch status and reconcileRECOVERY_TOKEN_INVALID (403)
Invalid, unknown, or expired continuation tokenDo not retry; fetch status and reconcileCONTINUATION_TOKEN_INVALID (409)
IDP commit fails after prepare-completeAbort prepared recovery registrationRewinds to idv_verified; retry with the same continuation_token
finalize_token reused or staleDo not retry blindly; fetch status and reconcileFINALIZE_TOKEN_INVALID (409)
User backs out before prepare-completeCancel recovery attemptcancelled
Attempt TTL elapsesNothingexpired

Registration endpoints

These endpoints cover the initial enrollment flow: starting a registration attempt, polling status, preparing the IDP-side passkey completion, finalizing (or aborting) the prepared completion, and cancelling an in-flight attempt.

Start a registration attempt

POST
/api/internal/v1/registrations/start

Starts a new enrollment attempt for a user. Your backend supplies the IDP-issued passkey registration challenge bundle and the user's applicant profile. Biometric Passkey records the attempt, starts the identity verification session against Entrust Identity Verification, and returns a registration_attempt_id your backend uses for the rest of the flow.

Use this endpoint when your application has decided to enroll a new user (or to add a new device-bound credential for an existing user) and your backend or IDP has already generated the passkey registration challenge.

Request headers

HeaderRequiredDescription
Idempotency-KeyRecommendedRequired for safe retry. Reuse the same key when retrying the same logical attempt.
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Request body

ParameterTypeRequiredDescription
external_user_idstringyesYour stable per-user identifier. Opaque to Biometric Passkey.
applicantobjectyesApplicant profile fields (first_name, last_name, optional dob, email, phone_number, address) forwarded to Entrust Identity Verification.
passkey_registrationobjectyesIDP-issued passkey registration challenge bundle: challenge, user_handle, rp_id, expires_at.
workflow_inputobjectoptionalForwarded to the Entrust Identity Verification workflow run. May carry custom_data and tags.
deviceobjectoptionalMobile device metadata (platform, device_label).
prior_biometricobjectoptionalPointer to a prior biometric reference, when re-enrolling an existing user.

Response

Returns 201 Created on a new attempt; returns 200 OK when an active attempt can replay the original IDV start bundle for the same retry context.

AttributeTypeDescription
registration_attempt_iduuidOpaque attempt identifier. Use in all subsequent calls in this flow.
statusenumOne of created, idv_in_progress, idv_completed, idp_commit_pending, idp_commit_failed, completed, failed, cancelled, expired, cleaned_up.
idvobjecttoken and workflow_run_id for the in-flight Entrust Identity Verification workflow run. The SDK consumes token to drive the on-device capture.
expires_atstring (date-time)Attempt TTL. After this time the attempt transitions to expired automatically.

Errors

StatusDescription
400Missing or malformed input.
409A conflicting active attempt exists, or an active attempt cannot replay its IDV start bundle for the same retry context.
422The passkey_registration bundle is inconsistent (for example, expires_at is in the past).
502Entrust Identity Verification was unreachable; safe to retry with the same Idempotency-Key.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Start a registration attempt
1POST /api/internal/v1/registrations/start HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5Idempotency-Key: <UNIQUE_IDEMPOTENCY_KEY>
6X-Correlation-ID: <YOUR_CORRELATION_ID>
7
8{
9 "external_user_id": "u_8c1f0a3e",
10 "applicant": {
11 "first_name": "Jane",
12 "last_name": "Doe",
13 "dob": "1981-12-10",
14 "email": "jane.doe@example.com"
15 },
16 "passkey_registration": {
17 "challenge": "<BASE64URL_CHALLENGE>",
18 "user_handle": "<BASE64URL_USER_HANDLE>",
19 "rp_id": "passkeys.example.com",
20 "expires_at": "2026-05-27T12:05:00Z"
21 },
22 "device": {
23 "platform": "ios",
24 "device_label": "iPhone 15"
25 }
26}

Get registration status

GET
/api/internal/v1/registrations/{registration_attempt_id}

Returns the current state of a registration attempt. Use this endpoint to poll attempt progress while the on-device identity verification is running, to confirm a terminal state after the SDK reports completion, or to read the bound credential_id after the attempt finishes.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
registration_attempt_iduuidThe attempt identifier returned by Start a registration attempt.

Response

Returns 200 OK with the current attempt snapshot.

AttributeTypeDescription
registration_attempt_iduuidEchoes the path parameter.
external_user_idstringThe user this attempt belongs to.
statusenumOne of created, idv_in_progress, idv_completed, idp_commit_pending, idp_commit_failed, completed, failed, cancelled, expired, cleaned_up.
workflow_run_idstring | nullEntrust Identity Verification workflow run identifier, when started.
credential_idstring | nullWebAuthn/passkey credential bound at completion. Does not identify or scope the user's EBT.
error_codestring | nullSet on terminal failure states.
expires_atstring (date-time)Attempt TTL.
updated_atstring (date-time)Last modification timestamp on the attempt.

Errors

StatusDescription
404No registration attempt with this registration_attempt_id exists.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Get registration status
1GET /api/internal/v1/registrations/<REGISTRATION_ATTEMPT_ID> HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4X-Correlation-ID: <YOUR_CORRELATION_ID>

Prepare registration completion

POST
/api/internal/v1/registrations/{registration_attempt_id}/prepare-complete

Submits the WebAuthn attestation captured on device. Biometric Passkey records the attestation against the attempt, transitions the attempt to idp_commit_pending, and returns a one-time finalize_token that the matching finalize or abort request must consume.

Call this endpoint once your mobile app has returned the authenticator attestation and your backend is ready to prepare the IDP commit. If the same prepare-complete request is retried while its token remains valid, Biometric Passkey returns the existing finalize_token when the WebAuthn binding is unchanged. Complete the attempt by calling finalize on IDP success or abort on IDP failure.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
registration_attempt_iduuidThe attempt identifier returned by Start a registration attempt.

Request body

ParameterTypeRequiredDescription
attestation_objectstringyesThe raw attestation object from the authenticator (unpadded base64url).
client_data_jsonstringyesUnpadded base64url encoding of the raw clientDataJSON bytes.

Response

Returns 200 OK with the issued finalize_token and the updated attempt status.

AttributeTypeDescription
registration_attempt_iduuidEchoes the path parameter.
statusenumTypically idp_commit_pending after a successful prepare-complete.
finalize_tokenstringOpaque one-time token consumed by the matching finalize or abort request.
expires_atstring (date-time)Finalize-token expiry. The finalize_token is invalidated at this time.

Errors

StatusDescription
404No registration attempt with this registration_attempt_id exists.
409The attempt is not in a state that accepts a prepare-complete (for example, it is already finalized, aborted, or expired).

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Prepare registration completion
1POST /api/internal/v1/registrations/<REGISTRATION_ATTEMPT_ID>/prepare-complete HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "attestation_object": "<BASE64URL_ATTESTATION_OBJECT>",
9 "client_data_json": "<BASE64URL_CLIENT_DATA_JSON>"
10}

Finalize registration

POST
/api/internal/v1/registrations/{registration_attempt_id}/finalize

Completes the Biometric Passkey side of a prepared registration once your IDP has accepted the passkey registration. The first successful finalize consumes the finalize_token issued by prepare-complete and transitions the attempt to completed.

Call this endpoint after your IDP has committed the credential on its side. If the IDP commit fails instead, call abort with the same finalize_token. Retrying after the attempt is terminal returns the current terminal snapshot.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
registration_attempt_iduuidThe attempt identifier returned by Start a registration attempt.

Request body

ParameterTypeRequiredDescription
finalize_tokenstringyesThe one-time token returned by prepare-complete.

Response

Returns 200 OK once the attempt has been transitioned to completed.

AttributeTypeDescription
registration_attempt_iduuidEchoes the path parameter.
statusenumcompleted on success.
credential_idstring | nullWebAuthn/passkey credential bound to the user at completion. Does not identify or scope the user's EBT.
completed_atstring (date-time) | nullCompletion timestamp.

Errors

StatusDescription
404No registration attempt with this registration_attempt_id exists.
409The attempt is not prepared, the finalize_token is unknown, invalid, or expired, or the current state cannot be finalized.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Finalize registration
1POST /api/internal/v1/registrations/<REGISTRATION_ATTEMPT_ID>/finalize HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "finalize_token": "<OPAQUE_FINALIZE_TOKEN>"
9}

Abort prepared registration

POST
/api/internal/v1/registrations/{registration_attempt_id}/abort

Closes a prepared registration attempt when your IDP fails to commit the passkey on its side. The first successful abort releases the finalize_token issued by prepare-complete and transitions the attempt to idp_commit_failed with the supplied error_code.

Use this endpoint after a successful prepare-complete when you need to record an IDP commit failure. If the IDP commit succeeds instead, call finalize with the same finalize_token. To close an in-flight attempt without recording an IDP commit failure, use cancel.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
registration_attempt_iduuidThe attempt identifier returned by Start a registration attempt.

Request body

ParameterTypeRequiredDescription
finalize_tokenstringyesThe one-time token returned by prepare-complete.
error_codestringyesA short machine-readable reason your backend recorded for the IDP commit failure.

Response

Returns 200 OK with the current attempt status; typically idp_commit_failed after the first successful abort.

AttributeTypeDescription
registration_attempt_iduuidEchoes the path parameter.
statusenumTypically idp_commit_failed after a successful abort.

Errors

Errors return the standard error envelope. Branch on error.code; consult error.retryable.

Abort prepared registration
1POST /api/internal/v1/registrations/<REGISTRATION_ATTEMPT_ID>/abort HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "finalize_token": "<OPAQUE_FINALIZE_TOKEN>",
9 "error_code": "idp_commit_failed"
10}

Cancel registration

POST
/api/internal/v1/registrations/{registration_attempt_id}/cancel

Cancels an in-progress registration attempt. Use this endpoint when the user backs out of the enrollment, when your application decides to abandon the attempt, or when your backend detects an upstream condition that makes finishing the attempt unsafe.

First successful cancel wins; subsequent cancel retries return the prior terminal result, so this endpoint is safe to call as part of cleanup. If a finalize token has already been issued, cancel releases it and marks the attempt cancelled; use abort instead when you need to record an IDP commit failure.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
registration_attempt_iduuidThe attempt identifier returned by Start a registration attempt.

Response

Returns 200 OK with the attempt's terminal status. Cancel takes no request body.

AttributeTypeDescription
registration_attempt_iduuidEchoes the path parameter.
statusenumTypically cancelled on the first successful cancel; subsequent calls return the prior terminal status.

Errors

Errors return the standard error envelope. Branch on error.code; consult error.retryable.

Cancel registration
1POST /api/internal/v1/registrations/<REGISTRATION_ATTEMPT_ID>/cancel HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4X-Correlation-ID: <YOUR_CORRELATION_ID>

In-app step-up endpoints

This group covers step-up authentication that happens entirely on the user's mobile device: starting a step-up auth session, starting step-up IDV, polling session status, preparing the IDP-side assertion completion, and finalizing or aborting the prepared completion.

Start a step-up auth session

POST
/api/internal/v1/step-up/auth-sessions/start

Starts an in-app step-up authentication session for an enrolled user. Your backend supplies the IDP-issued passkey assertion challenge bundle; Biometric Passkey creates a step-up session, returns a km_passkey_session_id, and your backend then drives the biometric verification and the assertion completion against this session.

Use this endpoint when your application has decided that a user action requires a high-value step-up, and your backend or IDP has already generated the passkey assertion challenge.

Request headers

HeaderRequiredDescription
Idempotency-KeyRecommendedRequired for safe retry. Reuse the same key when retrying the same logical step-up.
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Request body

ParameterTypeRequiredDescription
external_user_idstringyesYour stable per-user identifier. Must already be enrolled.
passkey_authenticationobjectyesIDP-issued passkey assertion challenge bundle: challenge, rp_id, expires_at.
workflow_inputobjectoptionalForwarded to the Entrust Identity Verification workflow run. May carry custom_data and tags.

Response

Returns 201 Created on a new session; returns 200 OK on an idempotent replay.

AttributeTypeDescription
km_passkey_session_iduuidOpaque session identifier. Use in all subsequent calls in this flow.
statusenumOne of created, idv_in_progress, idv_completed, auth_finalizing, completed, failed, cancelled, expired.
expires_atstring (date-time)Session TTL. After this time the session transitions to expired automatically.

Errors

StatusDescription
400Missing or malformed input.
404The user identified by external_user_id is not enrolled.
409An existing active session cannot be replayed in this request context.
422The passkey_authentication bundle is inconsistent.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Start a step-up auth session
1POST /api/internal/v1/step-up/auth-sessions/start HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5Idempotency-Key: <UNIQUE_IDEMPOTENCY_KEY>
6X-Correlation-ID: <YOUR_CORRELATION_ID>
7
8{
9 "external_user_id": "u_8c1f0a3e",
10 "passkey_authentication": {
11 "challenge": "<BASE64URL_CHALLENGE>",
12 "rp_id": "passkeys.example.com",
13 "expires_at": "2026-05-27T12:05:00Z"
14 },
15 "workflow_input": {
16 "tags": ["step-up", "transfer-authorization"]
17 }
18}

Start in-app step-up IDV

POST
/api/internal/v1/step-up/auth-sessions/{km_passkey_session_id}/idv/start

Starts the on-device biometric verification subphase for an active step-up auth session. Your backend supplies the selected WebAuthn credential identifier and the matching client_data_hash; Biometric Passkey returns an Entrust Identity Verification SDK token your backend forwards to the SDK to drive the biometric capture.

Call this endpoint after the user has selected a passkey credential and the authenticator has produced the client_data_hash for the assertion. On success the session transitions to idv_in_progress.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
km_passkey_session_iduuidThe session identifier returned by Start a step-up auth session.

Request body

ParameterTypeRequiredDescription
credential_id_hintstringyesWebAuthn/passkey credential selector for the assertion flow. Does not identify or scope the user's EBT.
client_data_hashstringyesUnpadded base64url encoding of the SHA-256 of the raw clientDataJSON bytes.

Response

Returns 200 OK with the SDK token and the updated session status.

AttributeTypeDescription
km_passkey_session_iduuidEchoes the path parameter.
statusenumTypically idv_in_progress after a successful start.
credential_idstringThe credential selected for the assertion flow. Does not identify or scope the user's EBT.
idvobjecttoken and workflow_run_id for the in-flight Entrust Identity Verification workflow run.
expires_atstring (date-time)Session TTL.

Errors

StatusDescription
400Missing or malformed input.
404No step-up auth session with this km_passkey_session_id exists, or the selected credential is not found or is not active for the session user.
409The session is not in a state that accepts IDV start, no usable EBT is available, or the session binding is incompatible.
502Entrust Identity Verification was unreachable; safe to retry.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Start in-app step-up IDV
1POST /api/internal/v1/step-up/auth-sessions/<BIOMETRIC_PASSKEY_SESSION_ID>/idv/start HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "credential_id_hint": "<WEBAUTHN_CREDENTIAL_ID>",
9 "client_data_hash": "<BASE64URL_SHA256_CLIENT_DATA_JSON>"
10}

Get step-up auth session status

GET
/api/internal/v1/step-up/auth-sessions/{km_passkey_session_id}

Returns the current state of a step-up auth session. Use this endpoint to poll session progress while the on-device biometric verification is running, or to read the bound credential_id after the session finishes.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
km_passkey_session_iduuidThe session identifier returned by Start a step-up auth session.

Response

Returns 200 OK with the current session snapshot.

AttributeTypeDescription
km_passkey_session_iduuidEchoes the path parameter.
external_user_idstringThe user this session belongs to.
statusenumOne of created, idv_in_progress, idv_completed, auth_finalizing, completed, failed, cancelled, expired.
workflow_run_idstring | nullEntrust Identity Verification workflow run identifier, when started.
credential_idstring | nullWebAuthn/passkey credential used for the assertion. Does not identify or scope the user's EBT.
error_codestring | nullSet on terminal failure states.
expires_atstring (date-time)Session TTL.
updated_atstring (date-time)Last modification timestamp on the session.

Errors

StatusDescription
404No step-up auth session with this km_passkey_session_id exists.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Get step-up auth session status
1GET /api/internal/v1/step-up/auth-sessions/<BIOMETRIC_PASSKEY_SESSION_ID> HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4X-Correlation-ID: <YOUR_CORRELATION_ID>

Prepare step-up completion

POST
/api/internal/v1/step-up/auth-sessions/{km_passkey_session_id}/prepare-complete

Submits the WebAuthn assertion captured on device for an active step-up auth session. Biometric Passkey records the assertion, transitions the session to auth_finalizing, and returns a one-time finalize_token for the matching finalize or abort request.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
km_passkey_session_iduuidThe session identifier returned by Start a step-up auth session.

Request body

ParameterTypeRequiredDescription
credential_idstringyesWebAuthn/passkey credential returned by the authenticator. Must match the credential selected at IDV start. Does not identify or scope the user's EBT.
client_data_jsonstringyesUnpadded base64url encoding of the raw clientDataJSON bytes.
authenticator_datastringyesUnpadded base64url encoding of the raw authenticator data.
signaturestringyesUnpadded base64url encoding of the raw assertion signature.

Response

Returns 200 OK with the issued finalize_token and the updated session status.

AttributeTypeDescription
km_passkey_session_iduuidEchoes the path parameter.
statusenumTypically auth_finalizing after a successful prepare-complete.
finalize_tokenstringOpaque one-time token consumed by the matching finalize or abort request.
expires_atstring (date-time)Finalize-token expiry. The finalize_token is invalidated at this time.

Errors

StatusDescription
404No step-up auth session with this km_passkey_session_id exists.
409The session is not in a state that accepts a prepare-complete, or the assertion does not match the credential and client-data binding established at IDV start.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Prepare step-up completion
1POST /api/internal/v1/step-up/auth-sessions/<BIOMETRIC_PASSKEY_SESSION_ID>/prepare-complete HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "credential_id": "<WEBAUTHN_CREDENTIAL_ID>",
9 "client_data_json": "<BASE64URL_CLIENT_DATA_JSON>",
10 "authenticator_data": "<BASE64URL_AUTHENTICATOR_DATA>",
11 "signature": "<BASE64URL_ASSERTION_SIGNATURE>"
12}

Finalize step-up authentication

POST
/api/internal/v1/step-up/auth-sessions/{km_passkey_session_id}/finalize

Completes the Biometric Passkey side of a prepared step-up authentication once your IDP has accepted the assertion. The first successful finalize consumes the finalize_token issued by prepare-complete and transitions the session to completed.

Call this endpoint after your IDP has accepted the assertion on its side. If the IDP rejects the assertion instead, call abort with the same finalize_token. Retrying after the session is terminal returns the current terminal snapshot.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
km_passkey_session_iduuidThe session identifier returned by Start a step-up auth session.

Request body

ParameterTypeRequiredDescription
finalize_tokenstringyesThe one-time token returned by prepare-complete.
credential_idstringyesWebAuthn/passkey credential used for the completed assertion. Must match the credential selected at IDV start.

Response

Returns 200 OK once the session has been transitioned to completed.

AttributeTypeDescription
km_passkey_session_iduuidEchoes the path parameter.
statusenumcompleted on success.
credential_idstringWebAuthn/passkey credential used for the completed assertion. Does not identify or scope the user's EBT.
completed_atstring (date-time) | nullCompletion timestamp.

Errors

StatusDescription
404No step-up auth session with this km_passkey_session_id exists.
409The session is not prepared, the finalize_token is unknown, invalid, or expired, or the current state cannot be finalized.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Finalize step-up authentication
1POST /api/internal/v1/step-up/auth-sessions/<BIOMETRIC_PASSKEY_SESSION_ID>/finalize HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "finalize_token": "<OPAQUE_FINALIZE_TOKEN>",
9 "credential_id": "<WEBAUTHN_CREDENTIAL_ID>"
10}

Abort prepared step-up authentication

POST
/api/internal/v1/step-up/auth-sessions/{km_passkey_session_id}/abort

Closes a prepared step-up auth session when your IDP rejects the assertion on its side, or when your backend otherwise needs to fail the session after prepare-complete. Releases the finalize_token issued by prepare-complete and transitions the session to failed with the supplied error_code.

Use this endpoint only after a successful prepare-complete. To finalize a successfully accepted assertion instead, call finalize with the same finalize_token.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
km_passkey_session_iduuidThe session identifier returned by Start a step-up auth session.

Request body

ParameterTypeRequiredDescription
finalize_tokenstringyesThe one-time token returned by prepare-complete.
error_codestringyesA short machine-readable reason your backend recorded for the IDP rejection.

Response

Returns 200 OK with the session's terminal status.

AttributeTypeDescription
km_passkey_session_iduuidEchoes the path parameter.
statusenumTypically failed after a successful abort.

Errors

Errors return the standard error envelope. Branch on error.code; consult error.retryable.

Abort prepared step-up authentication
1POST /api/internal/v1/step-up/auth-sessions/<BIOMETRIC_PASSKEY_SESSION_ID>/abort HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "finalize_token": "<OPAQUE_FINALIZE_TOKEN>",
9 "error_code": "idp_assertion_rejected"
10}

Cross-platform step-up endpoints

This group covers step-up authentication that starts in a web browser and hands off to a mobile device for the biometric assertion: starting and polling the cross-platform session, resuming on mobile via the handoff token, starting the mobile auth session and IDV, preparing and finalizing (or aborting) the IDP-side completion, and cancelling the browser/mobile handoff.

Start a cross-platform session

POST
/api/internal/v1/cross-platform-sessions/start

Creates a browser/mobile handoff session for a known Biometric Passkey user and issues a one-time handoff_token your backend embeds in the mobile resume callback. Biometric Passkey binds the session to the stable browser ownership tuple (external_user_id, web_context) so that retries from the same browser context replay the same session deterministically. The active passkey and EBT checks happen later, when the mobile authentication and IDV subphases start.

Call this endpoint from the browser-side flow as soon as your application has decided that a user action requires a cross-platform step-up. If an active session already exists for the same external_user_id and web_context, Biometric Passkey returns 200 OK with the existing cross_platform_session_id; the handoff_token is omitted on replay. If your backend no longer has the original handoff token, cancel the session or let it expire before starting a new one.

Request headers

HeaderRequiredDescription
Idempotency-KeyRecommendedAccepted for safe retry. Replay is anchored to the (external_user_id, web_context) tuple rather than to the header alone.
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Request body

ParameterTypeRequiredDescription
external_user_idstringyesYour stable per-user identifier. The user must already exist in Biometric Passkey.
web_contextobjectyesStable browser ownership tuple. Carries session_id and optional actor_context_id.
continuation_contextstringoptionalOpaque caller-owned continuation data echoed back later only to your backend on prepare-complete and resume.

Response

Returns 201 Created on a new session; returns 200 OK on a replay of an existing active session.

AttributeTypeDescription
cross_platform_session_iduuidOpaque session identifier. Use in all subsequent calls in this flow.
statusenumOne of created, handoff_issued, mobile_resumed, idv_in_progress, idv_completed, auth_finalizing, completed, failed, expired, cancelled.
handoff_tokenstringOpaque one-time mobile handoff token. Present only on newly created sessions; omitted on replay.
expires_atstring (date-time)Session TTL. After this time the session transitions to expired automatically.

Errors

StatusDescription
400Missing or malformed input.
403The supplied ownership context is not valid for the session or user; this can include an unknown external_user_id.
409The stable browser tuple matches an active session but the supplied continuation context is incompatible.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Start a cross-platform session
1POST /api/internal/v1/cross-platform-sessions/start HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5Idempotency-Key: <YOUR_IDEMPOTENCY_KEY>
6X-Correlation-ID: <YOUR_CORRELATION_ID>
7
8{
9 "external_user_id": "u_8c1f0a3e",
10 "web_context": {
11 "session_id": "<YOUR_BROWSER_SESSION_ID>",
12 "actor_context_id": "<YOUR_ACTOR_CONTEXT_ID>"
13 },
14 "continuation_context": "<OPAQUE_CONTINUATION_CONTEXT>"
15}

Get cross-platform session status

POST
/api/internal/v1/cross-platform-sessions/{cross_platform_session_id}/status

Returns the coarse browser-polling state of a cross-platform session. Use this endpoint to drive the browser-side polling UI while the user completes the biometric assertion on the mobile device. The returned status is intentionally coarse: expired covers both overall session expiry and handoff-token expiry before consumption.

This endpoint is scoped to the browser ownership tuple: the request body must echo the external_user_id and web_context that the session was created with.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
cross_platform_session_iduuidThe session identifier returned by Start a cross-platform session.

Request body

ParameterTypeRequiredDescription
external_user_idstringyesMust match the external_user_id the session was created with.
web_contextobjectyesMust match the web_context the session was created with.

Response

Returns 200 OK with the current poll snapshot.

AttributeTypeDescription
cross_platform_session_iduuidEchoes the path parameter.
statusenumCoarse poll state: pending, completed, failed, expired, cancelled.
expires_atstring (date-time)Cross-platform session TTL.
updated_atstring (date-time)Last modification timestamp on the session.

Errors

StatusDescription
400Missing or malformed input.
403The supplied external_user_id or web_context does not match the session's ownership tuple.
404No cross-platform session with this cross_platform_session_id exists.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Get cross-platform session status
1POST /api/internal/v1/cross-platform-sessions/<CROSS_PLATFORM_SESSION_ID>/status HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "external_user_id": "u_8c1f0a3e",
9 "web_context": {
10 "session_id": "<YOUR_BROWSER_SESSION_ID>",
11 "actor_context_id": "<YOUR_ACTOR_CONTEXT_ID>"
12 }
13}

Resume cross-platform session on mobile

POST
/api/internal/v1/cross-platform-sessions/resume

Resumes a cross-platform session on the mobile device after your mobile callback has carried the one-time handoff_token from the browser leg. Biometric Passkey consumes the handoff token, binds the session to the resuming mobile context, and, when previously stored, echoes the opaque continuation_context back to your backend.

Treat the handoff token as a one-time exchange from your mobile-side backend. The first successful resume consumes the token; later calls with the same, expired, or unknown token are rejected.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Request body

ParameterTypeRequiredDescription
handoff_tokenstringyesThe one-time token returned by Start a cross-platform session.

Response

Returns 200 OK with the resumed session snapshot.

AttributeTypeDescription
cross_platform_session_iduuidCross-platform session bound to the resumed mobile context.
statusenumTypically mobile_resumed after a successful resume.
expires_atstring (date-time)Cross-platform session TTL.
continuation_contextstringOptional opaque caller-owned continuation data previously stored on the session.

Errors

StatusDescription
400Missing or malformed handoff_token.
409The handoff token is unknown, already consumed, or expired.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Resume cross-platform session on mobile
1POST /api/internal/v1/cross-platform-sessions/resume HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "handoff_token": "<OPAQUE_HANDOFF_TOKEN>"
9}

Start cross-platform auth session

POST
/api/internal/v1/cross-platform-sessions/{cross_platform_session_id}/auth-sessions/start

Starts the mobile-side step-up auth session once the cross-platform session has been resumed on mobile and your backend or IDP has produced the passkey assertion challenge bundle. Biometric Passkey derives the owner directly from the cross_platform_session_id; the caller does not re-assert external_user_id on this call.

Call this endpoint after Resume cross-platform session on mobile and after your mobile callback indicates that the real IDP assertion may start. Idempotency-Key is accepted; replay still follows the underlying step-up session reuse rules when the (user_id, challenge_hash) tuple is compatible.

Request headers

HeaderRequiredDescription
Idempotency-KeyRecommendedRequired for safe retry. Reuse the same key when retrying the same logical step-up.
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
cross_platform_session_iduuidThe session identifier returned by Start a cross-platform session.

Request body

ParameterTypeRequiredDescription
passkey_authenticationobjectyesIDP-issued passkey assertion challenge bundle: challenge, rp_id, expires_at.
workflow_inputobjectoptionalForwarded to the Entrust Identity Verification workflow run. May carry custom_data and tags.

Response

Returns 201 Created on a new auth session; returns 200 OK on an idempotent replay.

AttributeTypeDescription
cross_platform_session_iduuidEchoes the path parameter.
km_passkey_session_iduuidThe underlying step-up session identifier used for the subsequent IDV, prepare-complete, finalize, and abort calls.
statusenumTypically mobile_resumed immediately after a successful auth-session start.
expires_atstring (date-time)Underlying step-up auth session expiry.

Errors

StatusDescription
400Missing or malformed input.
403The caller is not authorized for this session.
404No cross-platform session with this cross_platform_session_id exists.
409The session is not in a state that accepts an auth-session start, or the underlying step-up replay context is incompatible.
422The passkey_authentication bundle is inconsistent.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Start cross-platform auth session
1POST /api/internal/v1/cross-platform-sessions/<CROSS_PLATFORM_SESSION_ID>/auth-sessions/start HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5Idempotency-Key: <YOUR_IDEMPOTENCY_KEY>
6X-Correlation-ID: <YOUR_CORRELATION_ID>
7
8{
9 "workflow_input": {
10 "custom_data": { "transaction_id": "txn_91a2" },
11 "tags": ["high-value"]
12 },
13 "passkey_authentication": {
14 "challenge": "<BASE64URL_ASSERTION_CHALLENGE>",
15 "rp_id": "auth.example.com",
16 "expires_at": "2026-05-27T13:05:00Z"
17 }
18}

Start cross-platform IDV

POST
/api/internal/v1/cross-platform-sessions/{cross_platform_session_id}/idv/start

Starts the on-device biometric verification subphase for the mobile leg of a cross-platform session. Your backend supplies the selected WebAuthn credential identifier and the matching client_data_hash; Biometric Passkey returns an Entrust Identity Verification SDK token your backend forwards to the SDK to drive the biometric capture.

Call this endpoint after Start cross-platform auth session and after the user has selected a passkey credential on the mobile device. On success the cross-platform session transitions to idv_in_progress.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
cross_platform_session_iduuidThe session identifier returned by Start a cross-platform session.

Request body

ParameterTypeRequiredDescription
km_passkey_session_iduuidyesThe underlying step-up session identifier returned by Start cross-platform auth session.
credential_id_hintstringyesWebAuthn/passkey credential selector for the assertion flow. Does not identify or scope the user's EBT.
client_data_hashstringyesUnpadded base64url encoding of the SHA-256 of the raw clientDataJSON bytes.

Response

Returns 200 OK with the SDK token and the updated session status.

AttributeTypeDescription
cross_platform_session_iduuidEchoes the path parameter.
km_passkey_session_iduuidEchoes the underlying step-up session identifier.
statusenumTypically idv_in_progress after a successful start.
credential_idstringThe credential selected for the assertion flow. Does not identify or scope the user's EBT.
idvobjecttoken and workflow_run_id for the in-flight Entrust Identity Verification workflow run.
expires_atstring (date-time)Underlying step-up auth session expiry.

Errors

StatusDescription
400Missing or malformed input.
404No cross-platform session with this cross_platform_session_id exists, or the selected credential is not found or is not active for the session user.
409The session is not in a state that accepts IDV start, no usable EBT is available, or the session binding is incompatible.
502Entrust Identity Verification was unreachable; safe to retry.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Start cross-platform IDV
1POST /api/internal/v1/cross-platform-sessions/<CROSS_PLATFORM_SESSION_ID>/idv/start HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "km_passkey_session_id": "3a5b7c9d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
9 "credential_id_hint": "<WEBAUTHN_CREDENTIAL_ID>",
10 "client_data_hash": "<BASE64URL_SHA256_CLIENT_DATA_JSON>"
11}

Prepare cross-platform completion

POST
/api/internal/v1/cross-platform-sessions/{cross_platform_session_id}/prepare-complete

Submits the WebAuthn assertion captured on the mobile device for an active cross-platform session. Biometric Passkey records the assertion, transitions the session to auth_finalizing, returns a one-time finalize_token for the matching finalize or abort request, and, when previously stored, echoes the opaque continuation_context back to your backend.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
cross_platform_session_iduuidThe session identifier returned by Start a cross-platform session.

Request body

ParameterTypeRequiredDescription
km_passkey_session_iduuidyesThe underlying step-up session identifier returned by Start cross-platform auth session.
credential_idstringyesWebAuthn/passkey credential returned by the authenticator. Must match the credential selected at IDV start.
client_data_jsonstringyesUnpadded base64url encoding of the raw clientDataJSON bytes.
authenticator_datastringyesUnpadded base64url encoding of the raw authenticator data.
signaturestringyesUnpadded base64url encoding of the raw assertion signature.

Response

Returns 200 OK with the issued finalize_token and the updated session status.

AttributeTypeDescription
cross_platform_session_iduuidEchoes the path parameter.
km_passkey_session_iduuidEchoes the underlying step-up session identifier.
statusenumTypically auth_finalizing after a successful prepare-complete.
finalize_tokenstringOpaque one-time token consumed by the matching finalize or abort request.
expires_atstring (date-time)Finalize-token expiry. The finalize_token is invalidated at this time.
continuation_contextstringOptional opaque caller-owned continuation data previously stored on the session.

Errors

StatusDescription
404No cross-platform session with this cross_platform_session_id exists.
409The session is not in a state that accepts a prepare-complete, or the assertion does not match the credential and client-data binding established at IDV start.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Prepare cross-platform completion
1POST /api/internal/v1/cross-platform-sessions/<CROSS_PLATFORM_SESSION_ID>/prepare-complete HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "km_passkey_session_id": "3a5b7c9d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
9 "credential_id": "<WEBAUTHN_CREDENTIAL_ID>",
10 "client_data_json": "<BASE64URL_CLIENT_DATA_JSON>",
11 "authenticator_data": "<BASE64URL_AUTHENTICATOR_DATA>",
12 "signature": "<BASE64URL_ASSERTION_SIGNATURE>"
13}

Finalize cross-platform authentication

POST
/api/internal/v1/cross-platform-sessions/{cross_platform_session_id}/finalize

Completes the Biometric Passkey side of a prepared cross-platform authentication once your IDP has accepted the assertion. The first successful finalize consumes the finalize_token issued by prepare-cross-platform-completion and transitions the cross-platform session to completed.

Call this endpoint after your IDP has accepted the assertion on its side. If the IDP rejects the assertion instead, call abort with the same finalize_token. Retrying after the session is terminal returns the current terminal snapshot.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
cross_platform_session_iduuidThe session identifier returned by Start a cross-platform session.

Request body

ParameterTypeRequiredDescription
km_passkey_session_iduuidyesThe underlying step-up session identifier returned by Start cross-platform auth session.
finalize_tokenstringyesThe one-time token returned by prepare-cross-platform-completion.
credential_idstringyesWebAuthn/passkey credential used for the completed assertion. Must match the credential selected at IDV start.

Response

Returns 200 OK once the cross-platform session has been transitioned to completed.

AttributeTypeDescription
cross_platform_session_iduuidEchoes the path parameter.
km_passkey_session_iduuidEchoes the underlying step-up session identifier.
statusenumcompleted on success.
completed_atstring (date-time) | nullCompletion timestamp.

Errors

Errors return the standard error envelope. Branch on error.code; consult error.retryable.

Finalize cross-platform authentication
1POST /api/internal/v1/cross-platform-sessions/<CROSS_PLATFORM_SESSION_ID>/finalize HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "km_passkey_session_id": "3a5b7c9d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
9 "finalize_token": "<OPAQUE_FINALIZE_TOKEN>",
10 "credential_id": "<WEBAUTHN_CREDENTIAL_ID>"
11}

Abort prepared cross-platform authentication

POST
/api/internal/v1/cross-platform-sessions/{cross_platform_session_id}/abort

Closes a prepared cross-platform session when your IDP rejects the assertion on its side, or when your backend otherwise needs to fail the session after prepare-complete. Releases the finalize_token issued by prepare-cross-platform-completion and transitions the session to failed with the supplied error_code.

Use this endpoint only after a successful prepare-complete. To finalize a successfully accepted assertion instead, call finalize with the same finalize_token.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
cross_platform_session_iduuidThe session identifier returned by Start a cross-platform session.

Request body

ParameterTypeRequiredDescription
km_passkey_session_iduuidyesThe underlying step-up session identifier returned by Start cross-platform auth session.
finalize_tokenstringyesThe one-time token returned by prepare-cross-platform-completion.
error_codestringyesA short machine-readable reason your backend recorded for the IDP rejection.

Response

Returns 200 OK with the session's terminal status.

AttributeTypeDescription
cross_platform_session_iduuidEchoes the path parameter.
km_passkey_session_iduuidEchoes the underlying step-up session identifier.
statusenumTypically failed after a successful abort.

Errors

Errors return the standard error envelope. Branch on error.code; consult error.retryable.

Abort prepared cross-platform authentication
1POST /api/internal/v1/cross-platform-sessions/<CROSS_PLATFORM_SESSION_ID>/abort HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "km_passkey_session_id": "3a5b7c9d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
9 "finalize_token": "<OPAQUE_FINALIZE_TOKEN>",
10 "error_code": "idp_assertion_rejected"
11}

Cancel cross-platform session

POST
/api/internal/v1/cross-platform-sessions/{cross_platform_session_id}/cancel

Cancels the browser/mobile handoff for the current browser context. Use this endpoint when the user backs out of the browser-side flow, when your application decides to retire the cross-platform session, or when the browser context is being torn down. This call is scoped to the browser ownership tuple: the request body must echo the external_user_id and web_context the session was created with.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
cross_platform_session_iduuidThe session identifier returned by Start a cross-platform session.

Request body

ParameterTypeRequiredDescription
external_user_idstringyesMust match the external_user_id the session was created with.
web_contextobjectyesMust match the web_context the session was created with.

Response

Returns 200 OK with the session's terminal status.

AttributeTypeDescription
cross_platform_session_iduuidEchoes the path parameter.
statusenumTypically cancelled after a successful cancel.

Errors

StatusDescription
400Missing or malformed input.
403The supplied external_user_id or web_context does not match the session's ownership tuple.
404No cross-platform session with this cross_platform_session_id exists.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Cancel cross-platform session
1POST /api/internal/v1/cross-platform-sessions/<CROSS_PLATFORM_SESSION_ID>/cancel HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "external_user_id": "u_8c1f0a3e",
9 "web_context": {
10 "session_id": "<YOUR_BROWSER_SESSION_ID>",
11 "actor_context_id": "<YOUR_ACTOR_CONTEXT_ID>"
12 }
13}

Recovery endpoints

These endpoints drive the logged-out-device recovery flow: starting a recovery attempt for a known user, polling status, starting recovery IDV, exchanging the recovery token for a post-IDV continuation token, binding a replacement passkey registration, preparing and finalizing (or aborting) the IDP-side completion, and cancelling an in-flight attempt.

Start a recovery attempt

POST
/api/internal/v1/recovery-attempts/start

Starts or replays a logged-out-device recovery attempt for an already-enrolled user identified by external_user_id. Biometric Passkey creates the attempt, returns an opaque recovery_token your backend uses to start recovery identity verification and exchange continuation context, and returns the attempt and registration TTLs. This endpoint does not accept Idempotency-Key; replay is anchored to the active recovery attempt for the same user.

Use this endpoint when a previously enrolled user signs in on a new device and must re-establish a passkey credential before they can step up. If an active recovery attempt already exists for the same user, Biometric Passkey returns 200 OK with the existing attempt and a fresh replay of the same recovery_token.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Request body

ParameterTypeRequiredDescription
external_user_idstringyesYour stable per-user identifier. Must already be enrolled.

Response

Returns 201 Created for a new attempt; returns 200 OK on replay of an active attempt for the same user.

AttributeTypeDescription
recovery_attempt_iduuidOpaque attempt identifier. Use in all subsequent calls in this flow.
statusenumOne of created, idv_in_progress, idv_verified, registration_in_progress, idp_commit_pending, completed, failed, cancelled, expired.
recovery_tokenstringOpaque token your backend uses with recovery IDV start and continuation exchange. Do not forward it to the SDK; recovery IDV start returns the SDK idv.token.
attempt_expires_atstring (date-time)Overall attempt TTL.
passkey_registration_expires_atstring (date-time) | nullPasskey-registration subphase TTL; null until the registration subphase has started.

Errors

StatusDescription
400Missing or malformed input.
404No Biometric Passkey user or active credential exists for the supplied external_user_id.
409An active credential exists but no usable EBT is available for recovery, or enrollment is already in flight for the same user.
429The user has exceeded the recovery-attempt rate or abuse limit; consult the Retry-After header.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Start a recovery attempt
1POST /api/internal/v1/recovery-attempts/start HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "external_user_id": "u_8c1f0a3e"
9}

Get recovery attempt status

GET
/api/internal/v1/recovery-attempts/{recovery_attempt_id}

Returns the current state of a recovery attempt. Use this endpoint to poll attempt progress while recovery identity verification is running, or to read the replacement credential identifier after the attempt finishes.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
recovery_attempt_iduuidThe attempt identifier returned by Start a recovery attempt.

Response

Returns 200 OK with the current attempt snapshot.

AttributeTypeDescription
recovery_attempt_iduuidEchoes the path parameter.
external_user_idstringThe user this attempt belongs to.
statusenumOne of created, idv_in_progress, idv_verified, registration_in_progress, idp_commit_pending, completed, failed, cancelled, expired.
replacement_biometric_passkey_credential_iduuid | nullIdentifier of the replacement credential bound at completion.
workflow_run_idstring | nullEntrust Identity Verification workflow run identifier, when started.
error_codestring | nullSet on terminal failure states.
created_atstring (date-time)Attempt creation timestamp.
attempt_expires_atstring (date-time)Overall attempt TTL.
passkey_registration_expires_atstring (date-time) | nullPasskey-registration subphase TTL.
completed_atstring (date-time) | nullCompletion timestamp on terminal success.
updated_atstring (date-time)Last modification timestamp on the attempt.

Errors

StatusDescription
404No recovery attempt with this recovery_attempt_id exists.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Get recovery attempt status
1GET /api/internal/v1/recovery-attempts/<RECOVERY_ATTEMPT_ID> HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4X-Correlation-ID: <YOUR_CORRELATION_ID>

Start recovery IDV

POST
/api/internal/v1/recovery-attempts/{recovery_attempt_id}/idv/start

Exchanges the recovery_token issued at Start a recovery attempt for an Entrust Identity Verification SDK token. Your backend forwards the SDK token to the mobile SDK, which then drives the on-device recovery identity verification capture.

Call this endpoint once you have received the recovery_token and your application is ready to start the on-device capture. The attempt must be in a state that accepts IDV start; on first success the attempt transitions to idv_in_progress. If the same call is retried while the attempt is already idv_in_progress and the SDK token remains available, Biometric Passkey returns the existing SDK token.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
recovery_attempt_iduuidThe attempt identifier returned by Start a recovery attempt.

Request body

ParameterTypeRequiredDescription
recovery_tokenstringyesThe opaque token returned by Start a recovery attempt.

Response

Returns 200 OK with the SDK token and the updated attempt status.

AttributeTypeDescription
recovery_attempt_iduuidEchoes the path parameter.
statusenumTypically idv_in_progress after a successful start.
idvobjecttoken and workflow_run_id for the in-flight Entrust Identity Verification workflow run.
attempt_expires_atstring (date-time)Overall attempt TTL.

Errors

StatusDescription
400Missing or malformed input.
403The supplied recovery_token does not match the attempt or has been revoked.
404No recovery attempt with this recovery_attempt_id exists.
409The attempt is not in a state that accepts or replays an IDV start, the replay SDK token is unavailable, the stored EBT is missing, or the provider applicant binding is missing.
429Rate or abuse limit exceeded; consult the Retry-After header.
502Entrust Identity Verification was unreachable; safe to retry.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Start recovery IDV
1POST /api/internal/v1/recovery-attempts/<RECOVERY_ATTEMPT_ID>/idv/start HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "recovery_token": "<OPAQUE_RECOVERY_TOKEN>"
9}

Exchange recovery continuation

POST
/api/internal/v1/recovery-attempts/{recovery_attempt_id}/continuation/exchange

Exchanges the original recovery_token for an opaque post-IDV continuation_token once recovery identity verification has succeeded. The exchange also returns the authoritative external_user_id, which your backend uses to scope ownership before it issues the replacement passkey registration challenge.

Call this endpoint after the SDK signals that recovery IDV is complete. If an exchange has already happened, the same continuation_token is returned with 200 OK, so the call is safe to replay.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
recovery_attempt_iduuidThe attempt identifier returned by Start a recovery attempt.

Request body

ParameterTypeRequiredDescription
recovery_tokenstringyesThe opaque token returned by Start a recovery attempt.

Response

Returns 201 Created when the continuation token is issued for the first time; returns 200 OK on replay of an already-issued continuation token.

AttributeTypeDescription
recovery_attempt_iduuidEchoes the path parameter.
external_user_idstringAuthoritative user identifier for owner resolution on the next subphase.
continuation_tokenstringOpaque post-IDV token used by Start recovery registration and Prepare recovery completion.
statusenumTypically idv_verified after a successful exchange.
attempt_expires_atstring (date-time)Overall attempt TTL.

Errors

StatusDescription
400Missing or malformed input.
403The supplied recovery_token does not match the attempt or has been revoked.
404No recovery attempt with this recovery_attempt_id exists.
409The attempt has not yet completed recovery IDV, or has reached a terminal state.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Exchange recovery continuation
1POST /api/internal/v1/recovery-attempts/<RECOVERY_ATTEMPT_ID>/continuation/exchange HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "recovery_token": "<OPAQUE_RECOVERY_TOKEN>"
9}

Start recovery registration

POST
/api/internal/v1/recovery-attempts/{recovery_attempt_id}/registration/start

Binds the replacement passkey registration challenge to the recovery attempt after recovery identity verification has succeeded. Your backend supplies the IDP-issued passkey registration bundle and the post-IDV continuation_token; Biometric Passkey records the binding and returns a placeholder replacement_biometric_passkey_credential_id for the subsequent prepare-complete and finalize calls.

Call this endpoint after Exchange recovery continuation. On replay of an active recovery registration subphase, the same response is returned with 200 OK.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
recovery_attempt_iduuidThe attempt identifier returned by Start a recovery attempt.

Request body

ParameterTypeRequiredDescription
continuation_tokenstringyesThe opaque post-IDV token returned by Exchange recovery continuation.
passkey_registrationobjectyesIDP-issued passkey registration challenge bundle: challenge, user_handle, rp_id, expires_at.
deviceobjectoptionalMobile device metadata (platform, device_label).

Response

Returns 201 Created for the first successful start; returns 200 OK when the active recovery registration subphase is replayed.

AttributeTypeDescription
recovery_attempt_iduuidEchoes the path parameter.
replacement_biometric_passkey_credential_iduuidPlaceholder identifier reserved for the replacement credential.
continuation_tokenstringEchoes the supplied continuation_token for traceability.
statusenumTypically registration_in_progress after a successful start.
attempt_expires_atstring (date-time)Overall attempt TTL.
passkey_registration_expires_atstring (date-time)Passkey-registration subphase TTL.

Errors

StatusDescription
400Missing or malformed input.
404No recovery attempt with this recovery_attempt_id exists.
409The attempt is not in a state that accepts a registration start.
422The passkey_registration bundle is inconsistent (for example, expires_at is in the past).

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Start recovery registration
1POST /api/internal/v1/recovery-attempts/<RECOVERY_ATTEMPT_ID>/registration/start HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "continuation_token": "<OPAQUE_CONTINUATION_TOKEN>",
9 "passkey_registration": {
10 "challenge": "<BASE64URL_CHALLENGE>",
11 "user_handle": "<BASE64URL_USER_HANDLE>",
12 "rp_id": "passkeys.example.com",
13 "expires_at": "2026-05-27T13:05:00Z"
14 },
15 "device": {
16 "platform": "ios",
17 "device_label": "iPhone 15"
18 }
19}

Prepare recovery completion

POST
/api/internal/v1/recovery-attempts/{recovery_attempt_id}/prepare-complete

Submits the WebAuthn attestation captured on device for the replacement credential. Biometric Passkey transitions the attempt to idp_commit_pending and returns a one-time finalize_token for the matching finalize or abort request.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
recovery_attempt_iduuidThe attempt identifier returned by Start a recovery attempt.

Request body

ParameterTypeRequiredDescription
continuation_tokenstringyesThe opaque post-IDV token returned by Exchange recovery continuation.
attestation_objectstringyesThe raw attestation object from the authenticator (unpadded base64url).
client_data_jsonstringyesUnpadded base64url encoding of the raw clientDataJSON bytes.

Response

Returns 200 OK with the issued finalize_token and the updated attempt status.

AttributeTypeDescription
recovery_attempt_iduuidEchoes the path parameter.
statusenumTypically idp_commit_pending after a successful prepare-complete.
finalize_tokenstringOpaque one-time token consumed by the matching finalize or abort request.
attempt_expires_atstring (date-time)Overall attempt TTL.
passkey_registration_expires_atstring (date-time)Passkey-registration subphase TTL.

Errors

StatusDescription
400Missing or malformed input.
404No recovery attempt with this recovery_attempt_id exists.
409The attempt is not in a state that accepts a prepare-complete.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Prepare recovery completion
1POST /api/internal/v1/recovery-attempts/<RECOVERY_ATTEMPT_ID>/prepare-complete HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "continuation_token": "<OPAQUE_CONTINUATION_TOKEN>",
9 "attestation_object": "<BASE64URL_ATTESTATION_OBJECT>",
10 "client_data_json": "<BASE64URL_CLIENT_DATA_JSON>"
11}

Finalize recovery

POST
/api/internal/v1/recovery-attempts/{recovery_attempt_id}/finalize

Completes the Biometric Passkey side of a prepared recovery registration once your IDP has accepted the replacement passkey registration. The first successful finalize consumes the finalize_token issued by prepare-complete and transitions the attempt to completed.

Call this endpoint after your IDP has committed the replacement credential on its side. If the IDP commit fails instead, call abort with the same finalize_token. Retrying after the attempt is completed returns the completed snapshot.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
recovery_attempt_iduuidThe attempt identifier returned by Start a recovery attempt.

Request body

ParameterTypeRequiredDescription
finalize_tokenstringyesThe one-time token returned by prepare-complete.

Response

Returns 200 OK once the attempt has been transitioned to completed.

AttributeTypeDescription
recovery_attempt_iduuidEchoes the path parameter.
statusenumcompleted on success.
credential_idstring | nullReplacement WebAuthn/passkey credential bound to the user at completion. Does not identify or scope the user's EBT.
completed_atstring (date-time) | nullCompletion timestamp.

Errors

StatusDescription
400Missing or malformed input.
404No recovery attempt with this recovery_attempt_id exists.
409The attempt is not prepared, the finalize_token is unknown, invalid, or expired, or the current state cannot be finalized.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Finalize recovery
1POST /api/internal/v1/recovery-attempts/<RECOVERY_ATTEMPT_ID>/finalize HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "finalize_token": "<OPAQUE_FINALIZE_TOKEN>"
9}

Abort prepared recovery registration

POST
/api/internal/v1/recovery-attempts/{recovery_attempt_id}/abort

Aborts the replacement passkey registration subphase when your IDP fails to commit the replacement passkey on its side. Biometric Passkey releases any issued finalize token, resets the pending replacement credential binding, records the supplied error_code, and returns the recovery attempt to idv_verified so a new replacement registration can be started.

Use this endpoint after the recovery registration subphase has started when you want to keep the verified recovery attempt and retry replacement registration. If a valid finalize token has been issued, include it on the abort request. If the IDP commit succeeds instead, call finalize with that finalize_token. To close the whole recovery attempt, use cancel.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
recovery_attempt_iduuidThe attempt identifier returned by Start a recovery attempt.

Request body

ParameterTypeRequiredDescription
finalize_tokenstringoptionalThe one-time token returned by prepare-complete, when present.
error_codestringyesA short machine-readable reason your backend recorded for the IDP commit failure.

Response

Returns 200 OK with the current attempt status after the registration subphase is rewound.

AttributeTypeDescription
recovery_attempt_iduuidEchoes the path parameter.
statusenumTypically idv_verified after a successful abort.
attempt_expires_atstring (date-time)Overall attempt TTL.
passkey_registration_expires_atstring (date-time) | nullPasskey-registration subphase TTL.

Errors

StatusDescription
400Missing or malformed input.
404No recovery attempt with this recovery_attempt_id exists.
409The attempt is not in a state that accepts an abort.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Abort prepared recovery registration
1POST /api/internal/v1/recovery-attempts/<RECOVERY_ATTEMPT_ID>/abort HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "finalize_token": "<OPAQUE_FINALIZE_TOKEN>",
9 "error_code": "idp_commit_failed"
10}

Cancel recovery attempt

POST
/api/internal/v1/recovery-attempts/{recovery_attempt_id}/cancel

Cancels the whole in-progress recovery attempt. First successful cancel wins; later cancel retries return the prior terminal result, so this endpoint is safe to call as part of cleanup. Use abort instead when you want to keep the verified recovery attempt and retry replacement registration.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
recovery_attempt_iduuidThe attempt identifier returned by Start a recovery attempt.

Response

Returns 200 OK with the attempt's terminal status. Cancel takes no request body.

AttributeTypeDescription
recovery_attempt_iduuidEchoes the path parameter.
statusenumTypically cancelled on the first successful cancel; subsequent calls return the prior terminal status.
attempt_expires_atstring (date-time)Overall attempt TTL.
passkey_registration_expires_atstring (date-time) | nullPasskey-registration subphase TTL.
completed_atstring (date-time) | nullCompletion timestamp when the attempt has reached a terminal success state on replay.

Errors

StatusDescription
404No recovery attempt with this recovery_attempt_id exists.
409A conflicting cancel or terminal transition is already in flight.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Cancel recovery attempt
1POST /api/internal/v1/recovery-attempts/<RECOVERY_ATTEMPT_ID>/cancel HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4X-Correlation-ID: <YOUR_CORRELATION_ID>

User endpoints

The User endpoints let your backend read or repair the Biometric Passkey user profile and its provider-applicant binding outside of an enrollment or recovery flow.

Get user by external user ID

GET
/api/internal/v1/users/{external_user_id}

Returns the Biometric Passkey user profile and the current provider-applicant binding snapshot for the user identified by your stable external_user_id. Use this endpoint to confirm a user is enrolled before driving a step-up flow, or to read the bound applicant identifiers for support tooling.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
external_user_idstringYour stable per-user identifier.

Response

Returns 200 OK when the user is known to Biometric Passkey.

AttributeTypeDescription
external_user_idstringEchoes the path parameter.
first_namestringCurrent applicant first name as last bound.
last_namestringCurrent applicant last name as last bound.
idv_applicantobject | nullCurrent provider-applicant binding summary (provider_applicant_id, first_name, last_name) when bound; null if no provider applicant exists yet.
created_atstring (date-time)User record creation timestamp.
updated_atstring (date-time)Last modification timestamp on the user record or its provider-applicant binding.

Errors

StatusDescription
400The external_user_id path parameter is missing or malformed.
404No Biometric Passkey user exists for the supplied external_user_id.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Get user by external user ID
1GET /api/internal/v1/users/u_8c1f0a3e HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4X-Correlation-ID: <YOUR_CORRELATION_ID>

Update provider applicant

PUT
/api/internal/v1/users/{external_user_id}/applicant

Repairs or enriches the existing provider applicant bound to the user identified by external_user_id. Use this endpoint to correct an applicant field (for example a misspelled name or an updated address) without starting a new enrollment or recovery flow. Biometric Passkey forwards the patch to Entrust Identity Verification for the bound provider applicant.

Only the fields you include in applicant are modified; omitted fields are left untouched. This endpoint does not create a new applicant or rebind the user; if the user has no provider applicant yet, you must enroll or recover the user first.

Request headers

HeaderRequiredDescription
X-Correlation-IDRecommendedSingle end-to-end correlation identifier for the logical user action.

Path parameters

ParameterTypeDescription
external_user_idstringYour stable per-user identifier.

Request body

ParameterTypeRequiredDescription
applicantobjectyesPatch object. Any subset of first_name, last_name, dob, email, phone_number, address. Omitted fields are left untouched.

Response

Returns 200 OK once the patch has been accepted and forwarded to the provider applicant.

AttributeTypeDescription
external_user_idstringEchoes the path parameter.
statusenumAlways updated.
updated_atstring (date-time)Timestamp of the applied update.

Errors

StatusDescription
400The path parameter or patch body is malformed.
404No Biometric Passkey user exists for the supplied external_user_id.
409The user has no provider applicant bound yet, or a conflicting update is already in flight.
422The patch contains values that fail provider-side validation.
502Entrust Identity Verification was unreachable; safe to retry.

All errors return the standard error envelope. Branch on error.code; consult error.retryable.

Update provider applicant
1PUT /api/internal/v1/users/u_8c1f0a3e/applicant HTTP/1.1
2Host: <YOUR_BIOMETRIC_PASSKEY_BASE_URL>
3Authorization: Bearer <YOUR_SERVICE_CREDENTIAL>
4Content-Type: application/json
5X-Correlation-ID: <YOUR_CORRELATION_ID>
6
7{
8 "applicant": {
9 "email": "jane.doe@example.com",
10 "phone_number": "+441632960123",
11 "address": {
12 "line1": "10 Downing Street",
13 "town": "London",
14 "postcode": "SW1A 2AA",
15 "country": "GBR"
16 }
17 }
18}

Table of contents