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

# Managed KYC

> Reap runs identity verification through an embedded provider SDK and delivers the outcome to your webhook endpoint.

Managed KYC is one of Reap's verification methods, and applies if your project is configured for it. With Managed KYC, Reap runs the identity verification: you embed a provider SDK in your app, the user completes their checks, and the outcome arrives by webhook. You never handle identity documents directly.

This guide takes you from a new user to an `APPROVED` one, ready for account creation. See the [KYC overview](/compliance/kyc/overview) for the shared status model and how methods are assigned, or [Sumsub Token Sharing](/compliance/kyc/sumsub-token-sharing) for the alternative method.

***

## How it works

Reap integrates with a third-party identity verification provider. Today this is [Sumsub](https://sumsub.com); the integration is provider-agnostic and we may add others in the future.
When you advance a user's application, Reap returns a short-lived SDK token.
Your backend fetches this token and passes it to your frontend, which uses it to launch the Sumsub SDK inside your app.

* The user uploads their documents and completes liveness checks in the SDK.
* Reap receives the result from the provider and updates the user application status.
* You listen for webhooks to keep your system in sync.

```mermaid theme={null}
sequenceDiagram
    participant BE as Your backend
    participant Reap as Reap API
    participant FE as Your frontend
    participant SDK as Verification SDK

    BE->>Reap: POST /users/:id/application
    Reap-->>BE: nextAction.sdkToken
    BE-->>FE: sdkToken
    FE->>SDK: Launch SDK with token
    SDK-->>SDK: User completes verification
    Reap-->>BE: USER_APPLICATION_STATUS_UPDATED webhook
```

***

## What users are asked to provide

During verification, the user is guided through a set of checks. The exact steps depend on the user's country of residence and risk profile.

Typical checks include:

| Check                | Description                                                                             |
| -------------------- | --------------------------------------------------------------------------------------- |
| Government-issued ID | Passport, national ID card, or driver's licence. Both sides may be required.            |
| Nationality          | Captured from the document and user input to determine eligibility and screening rules. |
| Residential address  | Collected as part of the profile.                                                       |
| Liveness check       | Selfie or short video to confirm the document matches a live person.                    |

Capture and storage happen on the verification provider's infrastructure.

***

## Integrate

<Note>
  Managed KYC spans both your backend and your frontend. Your backend handles all Reap API calls and receives webhooks. Your frontend launches the Sumsub SDK using the SDK token your backend fetches.
</Note>

<Steps>
  <Step title="Initiate KYC (backend)">
    Call [Advance the user application](/api-reference/users/advance-the-user-application) with the `userId` from [Create a user](/api-reference/users/create-user). The request body is optional for Managed KYC - it defaults to `method: MANAGED_KYC`, so you can omit it. The response returns an SDK token at `nextAction.sdkToken`. Return it to your frontend to launch the verification SDK.
  </Step>

  <Step title="Launch the Sumsub SDK (frontend)">
    Pass that SDK token to the Sumsub WebSDK in your app.
    The SDK guides the user through document capture, liveness checks, and submission.

    Follow the [Sumsub WebSDK integration guide](https://docs.sumsub.com/docs/get-started-with-web-sdk) for setup.
    For mobile apps, refer to the Sumsub iOS or Android SDK docs.

    Keep your UI in a "verification in progress" state until your backend receives a webhook confirming the outcome.
  </Step>

  <Step title="Handle the webhook (backend)">
    When verification completes, Reap sends a `USER_APPLICATION_STATUS_UPDATED` event to your webhook endpoint.
    See the [USER\_APPLICATION\_STATUS\_UPDATED event reference](/api-reference/user-application-status-updated) for the full payload schema.

    Handle the `application.status` in the event:

    * `APPROVED`: user is verified. Proceed to account creation.
    * `REJECTED`: permanently rejected. Surface `application.rejectionReason` to the user. Do not re-initiate.
    * `RETRY_REQUIRED`: user can try again. Surface `application.rejectionReason` and go back to Step 1.
  </Step>

  <Step title="Handle retries (backend + frontend)">
    If `application.status` is `RETRY_REQUIRED`, call [Advance the user application](/api-reference/users/advance-the-user-application) again to get a new token, then pass it to your frontend to relaunch the SDK.

    Use `application.rejectionReason` from the webhook to explain what the user needs to correct before they go through the SDK again.
  </Step>
</Steps>

***

## Rejection reasons

If a user's application is `REJECTED` or `RETRY_REQUIRED`, the `rejectionReason` field explains why. Common examples include:

| Example reason      | What it might mean                            | Typical action                                   |
| ------------------- | --------------------------------------------- | ------------------------------------------------ |
| Document expired    | The submitted ID document is no longer valid  | Ask the user to resubmit with a valid document   |
| Document unreadable | Image quality was too low to process          | Ask the user to retake photos in better lighting |
| Face mismatch       | Liveness selfie did not match the ID document | Ask the user to redo the liveness check          |

The exact wording of `rejectionReason` comes from the provider or from Reap's compliance review. Present it in your UI in a way that is clear to your users.

<Note>
  A `REJECTED` status can also stem from an [unsupported jurisdiction](/compliance/kyc/overview#unsupported-jurisdictions). Unlike the examples above, this case is non-retriable - the user cannot resolve it by resubmitting documents.
</Note>

***

## Testing in sandbox

In the sandbox environment, use the simulation endpoint to trigger `USER_APPLICATION_STATUS_UPDATED` webhooks without running real identity checks.
The update is processed asynchronously. Wait for the webhook rather than polling.
See [Simulate user application status](/api-reference/simulation/simulate-user-application-status) in the API reference for the full request schema.

### Scenario 1: Happy path

1. [Create a user](/api-reference/users/create-user)
2. [Advance the user application](/api-reference/users/advance-the-user-application)
3. [Simulate user application status](/api-reference/simulation/simulate-user-application-status) with `{ "status": "APPROVED" }`
4. Confirm webhook received with `status: "APPROVED"`
5. [Create an account](/api-reference/accounts/create-account)

### Scenario 2: Retry required, then approved

1. [Create a user](/api-reference/users/create-user)
2. [Advance the user application](/api-reference/users/advance-the-user-application)
3. [Simulate user application status](/api-reference/simulation/simulate-user-application-status) with `{ "status": "RETRY_REQUIRED" }`
4. Confirm webhook received with `status: "RETRY_REQUIRED"`, surface `rejectionReason` in your UI
5. [Advance the user application](/api-reference/users/advance-the-user-application) again
6. [Simulate user application status](/api-reference/simulation/simulate-user-application-status) with `{ "status": "APPROVED" }`
7. Confirm webhook received with `status: "APPROVED"`
8. [Create an account](/api-reference/accounts/create-account)
