> ## Documentation Index
> Fetch the complete documentation index at: https://docs.services.payward.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Hosted KYC

> Use the hosted KYC flow to verify users through a Payward-managed hosted UI.

Hosted KYC lets you verify a user through a Payward-managed hosted UI. You 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.

Use the [Backend verification API][backend-verification-api] instead when your backend already collects document or liveness evidence.

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

## How it works

A typical Hosted KYC integration follows five steps:

<Steps>
  <Step title="Create or update the user">
    Create the Payward user and provide the profile fields required for onboarding.
  </Step>

  <Step title="Start Hosted KYC">
    Call [`POST /v1/users/{user_id}/verifications/start/hosted`][start-verification-from-hosted-flow] with the user ID
    in the `user_id` path parameter.
  </Step>

  <Step title="Send the user to the hosted UI">
    Launch the hosted UI with the returned launch fields, or create a one-time link and redirect the user to it.
  </Step>

  <Step title="Handle interruptions">
    Resume the same hosted verification when the user returns to an existing flow.
  </Step>

  <Step title="Reconcile status">
    Use [webhooks][register-webhook], the verification endpoints, and [Get User][get-user] to decide what the user can
    do next.
  </Step>
</Steps>

## Base URL

```text theme={null}
https://api.services.payward.com
```

## Authentication

All requests require three headers:

| Header      | Description                                   |
| ----------- | --------------------------------------------- |
| `API-Key`   | Your public API key                           |
| `API-Nonce` | Monotonically increasing integer nonce        |
| `API-Sign`  | HMAC signature computed with your private key |

See [Authentication](/tabs/developer-documentation/get-started/authentication) for how to generate the signature.

## 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 Payward profile. Do not send collected evidence or verification results in the hosted-start request.

Use these endpoints before starting verification:

| Endpoint                                   | Use it to                  |
| ------------------------------------------ | -------------------------- |
| [`POST /v1/users`][create-user]            | Create a user              |
| [`PATCH /v1/users/{user_id}`][update-user] | Update an existing user    |
| [`GET /v1/users/{user_id}`][get-user]      | Read the latest user state |

Store the user ID. The hosted verification endpoints use it as the `user_id` path parameter.

## Step 2 - Start Hosted KYC

Call [Start verification from hosted flow][start-verification-from-hosted-flow] when the user is ready to verify:

```text theme={null}
POST /v1/users/{user_id}/verifications/start/hosted
```

The request body is empty:

```bash theme={null}
curl -X POST "https://api.services.payward.com/v1/users/$USER_ID/verifications/start/hosted" \
  -H "API-Key: $PWS_API_KEY" \
  -H "API-Nonce: $PWS_API_NONCE" \
  -H "API-Sign: $PWS_API_SIGN" \
  -H "Content-Type: application/json" \
  -d '{}'
```

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

```json theme={null}
{
  "data": {
    "verification_id": "PVABCDE-FGHIJ-KLMNOP",
    "inquiry_id": "hosted_verification_test",
    "session_token": "hosted_session_test",
    "environment_id": "hosted_ui_test"
  }
}
```

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

| Field             | Description                                                     |
| ----------------- | --------------------------------------------------------------- |
| `verification_id` | Public ID for this hosted verification                          |
| `inquiry_id`      | Opaque hosted verification identifier                           |
| `session_token`   | Short-lived launch token for the hosted UI                      |
| `environment_id`  | Hosted 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][create-one-time-link-for-hosted-verification] for the existing verification:

```text theme={null}
POST /v1/users/{user_id}/verifications/{verification_id}/otl
```

```bash theme={null}
curl -X POST "https://api.services.payward.com/v1/users/$USER_ID/verifications/$VERIFICATION_ID/otl" \
  -H "API-Key: $PWS_API_KEY" \
  -H "API-Nonce: $PWS_API_NONCE" \
  -H "API-Sign: $PWS_API_SIGN"
```

The response includes a full URL and a shortened URL:

```json theme={null}
{
  "data": {
    "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][resume-hosted-verification] instead of starting a duplicate one:

```text theme={null}
POST /v1/users/{user_id}/verifications/{verification_id}/resume
```

```bash theme={null}
curl -X POST "https://api.services.payward.com/v1/users/$USER_ID/verifications/$VERIFICATION_ID/resume" \
  -H "API-Key: $PWS_API_KEY" \
  -H "API-Nonce: $PWS_API_NONCE" \
  -H "API-Sign: $PWS_API_SIGN"
```

The response returns fresh hosted UI launch fields:

```json theme={null}
{
  "data": {
    "inquiry_id": "hosted_verification_test",
    "session_token": "hosted_session_test",
    "environment_id": "hosted_ui_test"
  }
}
```

Use the returned launch fields for embedded flows. If you need a URL, call [Create one-time link for hosted verification][create-one-time-link-for-hosted-verification] after resuming.

## Step 5 - Reconcile status

Hosted KYC does not finish in the start response. Reconcile status from [webhooks][register-webhook] and the latest API state.

Use [`GET /v1/users/{user_id}/verifications/{verification_id}`][get-verification] to fetch the latest state for one hosted verification:

```bash theme={null}
curl -X GET "https://api.services.payward.com/v1/users/$USER_ID/verifications/$VERIFICATION_ID" \
  -H "API-Key: $PWS_API_KEY" \
  -H "API-Nonce: $PWS_API_NONCE" \
  -H "API-Sign: $PWS_API_SIGN"
```

If you do not have the verification ID, use [`GET /v1/users/{user_id}/verifications`][list-verifications] to list hosted verification attempts:

```bash theme={null}
curl -X GET "https://api.services.payward.com/v1/users/$USER_ID/verifications" \
  -H "API-Key: $PWS_API_KEY" \
  -H "API-Nonce: $PWS_API_NONCE" \
  -H "API-Sign: $PWS_API_SIGN"
```

Example response:

```json theme={null}
{
  "data": {
    "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"
      }
    ]
  }
}
```

Hosted verification status responses use `method: "hosted"` and include each covered document role in `types`.

Use the verification status together with [Get User][get-user]:

| Status      | What it means                                 | What to do                                                                 |
| ----------- | --------------------------------------------- | -------------------------------------------------------------------------- |
| `started`   | The hosted verification was created           | Send the user to the hosted UI                                             |
| `pending`   | The verification is still in progress         | Wait for an update, or resume the flow if the user returns                 |
| `completed` | The hosted verification finished successfully | Fetch the user and confirm the final user status before enabling activity  |
| `failed`    | The hosted verification did not complete      | Fetch 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][register-webhook] for user lifecycle events so your system does not need to poll continuously after a final user-state change. Webhook events are signals to fetch the latest state, not the complete state by themselves.

| Event           | Meaning                                                  | Recommended action                                                     |
| --------------- | -------------------------------------------------------- | ---------------------------------------------------------------------- |
| `user.verified` | The user has been verified and can trade on the platform | Fetch the user, update your local status, and enable eligible activity |
| `user.closed`   | The user's account has been permanently closed           | Stop account activity and update your local status                     |
| `user.disabled` | The user's account has been disabled                     | Stop account activity and wait for the latest user state               |

Webhook delivery can be repeated. Deduplicate events by `event_id`, 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 [Start verification from hosted flow][start-verification-from-hosted-flow] 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`:

| Need                         | Endpoint                                                                                                       |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------- |
| Create a fresh one-time link | [`POST /v1/users/{user_id}/verifications/{verification_id}/otl`][create-one-time-link-for-hosted-verification] |
| Refresh launch fields        | [`POST /v1/users/{user_id}/verifications/{verification_id}/resume`][resume-hosted-verification]                |
| Check verification state     | [`GET /v1/users/{user_id}/verifications/{verification_id}`][get-verification]                                  |
| List verification attempts   | [`GET /v1/users/{user_id}/verifications`][list-verifications]                                                  |
| Check user state             | [`GET /v1/users/{user_id}`][get-user]                                                                          |

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

## API reference

| Endpoint                                                                                                       | Reference                                                                                    |
| -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| [`POST /v1/users`][create-user]                                                                                | [Create User][create-user]                                                                   |
| [`PATCH /v1/users/{user_id}`][update-user]                                                                     | [Update User][update-user]                                                                   |
| [`GET /v1/users/{user_id}`][get-user]                                                                          | [Get User][get-user]                                                                         |
| [`POST /v1/users/{user_id}/verifications/start/hosted`][start-verification-from-hosted-flow]                   | [Start verification from hosted flow][start-verification-from-hosted-flow]                   |
| [`POST /v1/users/{user_id}/verifications/{verification_id}/otl`][create-one-time-link-for-hosted-verification] | [Create one-time link for hosted verification][create-one-time-link-for-hosted-verification] |
| [`POST /v1/users/{user_id}/verifications/{verification_id}/resume`][resume-hosted-verification]                | [Resume hosted verification][resume-hosted-verification]                                     |
| [`GET /v1/users/{user_id}/verifications/{verification_id}`][get-verification]                                  | [Get verification][get-verification]                                                         |
| [`GET /v1/users/{user_id}/verifications`][list-verifications]                                                  | [List verifications][list-verifications]                                                     |
| [`POST /v1/webhooks`][register-webhook]                                                                        | [Register Webhook][register-webhook]                                                         |

[backend-verification-api]: /tabs/developer-documentation/verifications/backend-verification-api

[create-one-time-link-for-hosted-verification]: /api-reference/verifications/create-one-time-link-for-hosted-verification

[create-user]: /api-reference/users/create-user

[get-user]: /api-reference/users/get-user

[get-verification]: /api-reference/verifications/get-verification

[list-verifications]: /api-reference/verifications/list-verifications

[register-webhook]: /api-reference/webhooks/register-webhook

[resume-hosted-verification]: /api-reference/verifications/resume-hosted-verification

[start-verification-from-hosted-flow]: /api-reference/verifications/start-verification-from-hosted-flow

[update-user]: /api-reference/users/update-user
