Skip to main content

Embed: Hosted KYC

Hosted KYC lets you verify a user through a hosted UI. Create or update the user first, start a hosted verification, send the user to the hosted UI, then reconcile the final status through verification, user, and webhook endpoints.

note

Hosted KYC is asynchronous. Treat the start response as launch material for the hosted UI, not as a final verification decision.

How it works​

A typical Hosted KYC integration follows five steps:

  1. Create or update the user and store the user's IIBAN.
  2. Start Hosted KYC for that user.
  3. Send the user to the hosted UI with the returned launch fields or a one-time link.
  4. Resume the same hosted verification if the user returns to an interrupted flow.
  5. Reconcile status with webhooks, hosted verification listing, and the user endpoint.

API surfaces​

Use the API surface your integration already uses.

API surfaceStart Hosted KYCUser identifier
Embed RESTPOST /b2b/verifications/{user}/start/hosteduser path parameter
Embed v1POST /private/StartHostedVerificationuser query parameter

Both surfaces return the same hosted launch fields and hosted verification status model.

Step 1: Create or update the user​

Before starting Hosted KYC, create the user and provide the profile fields required for onboarding. Hosted KYC uses the user's existing profile. Do not send collected evidence or verification results in the hosted-start request.

Use these endpoints before starting verification:

API surfaceCreateUpdateRead
Embed RESTPOST /b2b/usersPATCH /b2b/users/{user}GET /b2b/users/{user}
Embed v1POST /private/CreateUserPOST /private/UpdateUserGET /private/GetUser

For Embed REST, if the user has no non-CONCAT client identifier or tax ID, set declare_no_client_identifier to true in the Create User or Update User request. You can include a CONCAT client_identifier in the same request. If you omit client_identifier, include full_name, date_of_birth, and at least one value in nationalities so Payward can generate the CONCAT identifier.

Step 2: Start Hosted KYC​

For Embed REST, call:

curl -X POST "https://nexus.kraken.com/b2b/verifications/$USER_IIBAN/start/hosted" \
-H "API-Key: $EMBED_API_KEY" \
-H "API-Nonce: $EMBED_API_NONCE" \
-H "API-Sign: $EMBED_API_SIGN" \
-H "Payward-Version: 2025-04-15" \
-H "Content-Type: application/json" \
-d '{}'

For Embed v1, call:

curl -X POST "https://api.kraken.com/0/private/StartHostedVerification?user=$USER_IIBAN" \
-H "API-Key: $EMBED_API_KEY" \
-H "API-Sign: $EMBED_API_SIGN" \
-H "Content-Type: application/json" \
-d '{"nonce":1616492376594}'

The response includes the public verification ID and hosted UI launch fields:

{
"result": {
"verification_id": "PVABCDE-FGHIJ-KLMNOP",
"inquiry_id": "inq_test_handle",
"session_token": "sess_test",
"environment_id": "env_test_handle"
}
}

Store verification_id. You need it to create one-time links, resume the hosted flow, reconcile status, and troubleshoot the user's hosted verification.

FieldDescription
verification_idPublic ID for this hosted verification
inquiry_idHosted verification flow identifier
session_tokenShort-lived launch token for the hosted UI
environment_idHosted UI environment identifier returned with the launch token

Step 3: Send the user to the hosted UI​

Use the launch method agreed during onboarding.

For an embedded launch, use session_token and environment_id from the hosted-start or resume response. Treat session_token as short-lived and do not store it as a long-term credential.

For a redirect or shareable link, create a one-time link for the existing verification.

Embed REST:

curl -X POST "https://nexus.kraken.com/b2b/verifications/$USER_IIBAN/$VERIFICATION_ID/otl" \
-H "API-Key: $EMBED_API_KEY" \
-H "API-Nonce: $EMBED_API_NONCE" \
-H "API-Sign: $EMBED_API_SIGN" \
-H "Payward-Version: 2025-04-15"

Embed v1:

curl -X POST "https://api.kraken.com/0/private/CreateHostedVerificationLink?user=$USER_IIBAN&verification_id=$VERIFICATION_ID" \
-H "API-Key: $EMBED_API_KEY" \
-H "API-Sign: $EMBED_API_SIGN" \
-H "Content-Type: application/json" \
-d '{"nonce":1616492376595}'

The response includes a full URL and a shortened URL:

{
"result": {
"url": "https://verify.example.com/verify?code=us1-handle",
"url_short": "https://verify.example.com/v/HANDLE"
}
}

Send the user to url or url_short. One-time links are temporary. Create a fresh link if the user needs to return later.

Step 4: Resume an interrupted flow​

If the user returns to an existing hosted verification, resume that verification instead of starting a duplicate one.

Embed REST:

curl -X POST "https://nexus.kraken.com/b2b/verifications/$USER_IIBAN/$VERIFICATION_ID/resume" \
-H "API-Key: $EMBED_API_KEY" \
-H "API-Nonce: $EMBED_API_NONCE" \
-H "API-Sign: $EMBED_API_SIGN" \
-H "Payward-Version: 2025-04-15"

Embed v1:

curl -X POST "https://api.kraken.com/0/private/ResumeHostedVerification?user=$USER_IIBAN&verification_id=$VERIFICATION_ID" \
-H "API-Key: $EMBED_API_KEY" \
-H "API-Sign: $EMBED_API_SIGN" \
-H "Content-Type: application/json" \
-d '{"nonce":1616492376596}'

The response returns fresh hosted UI launch fields:

{
"result": {
"inquiry_id": "inq_test_handle",
"session_token": "sess_test",
"environment_id": "env_test_handle"
}
}

Use the returned launch fields for embedded flows. If you need a URL, call the one-time link endpoint after resuming.

Step 5: Reconcile status​

Hosted KYC does not finish in the start response. Reconcile status from webhooks and the latest API state.

Use GET /b2b/verifications/{user} or GET /private/ListVerifications to list verification attempts:

{
"result": {
"verifications": [
{
"verification_id": "PVABCDE-FGHIJ-KLMNOP",
"types": [
"proof_of_identity",
"proof_of_address",
"proof_of_liveness"
],
"method": "hosted",
"status": "pending",
"created_at": "2026-05-20T14:30:00Z",
"updated_at": "2026-05-20T14:45:00Z"
}
]
}
}

Use the verification status together with the user endpoint:

StatusWhat it meansWhat to do
startedThe hosted verification was createdSend the user to the hosted UI
pendingThe verification is still in progressWait for an update, or resume the flow if the user returns
completedThe hosted verification finished successfullyFetch the user and confirm the final user status before enabling activity
failedThe hosted verification did not completeFetch the user and verification state to determine the next available step

The reasons field only appears when a verification status is failed.

Webhook events​

Register webhooks for user lifecycle events so your system does not need to poll continuously. Webhook events are signals to fetch the latest state, not the complete state by themselves.

EventMeaningRecommended action
user.verification_neededThe user must complete an additional verification step before continuingFetch the user and verification state, then send the user back to Hosted KYC
user.verification_failedThe user's verification attempt failedFetch the user and verification state to determine whether another step is needed
user.verifiedThe user has been verified and can trade on the platformFetch the user, update your local status, and enable eligible activity
user.closedThe user's account has been permanently closedStop account activity and update your local status
user.disabledThe user's account has been disabledStop account activity and wait for the latest user state

Webhook delivery can be repeated. Deduplicate events, return a 2xx response only after accepting the event, and fetch the latest user and verification state before changing what the user can do.

Retry guidance​

Use the hosted-start endpoint to create a hosted verification. Do not call it repeatedly to refresh a session or link.

Use these follow-up endpoints for the same verification_id:

NeedEmbed RESTEmbed v1
Create a fresh one-time linkPOST /b2b/verifications/{user}/{verification_id}/otlPOST /private/CreateHostedVerificationLink
Refresh launch fieldsPOST /b2b/verifications/{user}/{verification_id}/resumePOST /private/ResumeHostedVerification
List verification attemptsGET /b2b/verifications/{user}GET /private/ListVerifications
Check user stateGET /b2b/users/{user}GET /private/GetUser

Only start a new hosted verification after a previous attempt reaches a terminal state and your integration allows another attempt.