Skip to main content
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 for the shared status model and how methods are assigned, or Sumsub Token Sharing for the alternative method.

How it works

Reap integrates with a third-party identity verification provider. Today this is Sumsub; the integration is provider-agnostic and we may add others in the future. When you advance a user’s application, Reap returns an SDK token. The token is a Sumsub WebSDK access token, and it is valid for 10 minutes. Sumsub’s iOS and Android SDKs take the same access 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.

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: Capture and storage happen on the verification provider’s infrastructure.

Integrate

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.
1

Initiate KYC (backend)

Call Advance the user application with the userId from Create a 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.
2

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.If the token expires while the user is still in the SDK, Sumsub calls your expiration handler for a replacement. That works only while the application is NOT_STARTED or RETRY_REQUIRED. Have the handler ask your backend to advance the application again and return the new nextAction.sdkToken. If you send an Idempotency-Key, use a new key. The same key replays the first response, which still carries the expired token.Once the application is IN_REVIEW, advance does not return a token. The user has to finish any remaining stages in the SDK session that is already open.Follow the Sumsub WebSDK integration guide for setup. For mobile apps, refer to the Sumsub iOS or Android SDK docs.
Verification can run in several stages. Some users are asked for proof of address after they submit their ID and liveness check. Keep the SDK open until the user finishes every stage.With the WebSDK, close the SDK on idCheck.onApplicantVerificationCompleted. Do not close it on idCheck.onApplicantSubmitted, which fires after each stage. On mobile, do not dismiss the SDK on the first submission event.If you close the SDK early, the user never sees the proof of address step. The application can still move to IN_REVIEW, but it cannot be approved until the missing step is complete.
Keep your UI in a “verification in progress” state until your backend receives a webhook confirming the outcome.
3

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 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.
4

Handle retries (backend + frontend)

If application.status is RETRY_REQUIRED, call Advance the user application again to get a new token, then pass it to your frontend to relaunch the SDK. If you send an Idempotency-Key, use a new key so the call is not a replay of the earlier token.Use application.rejectionLabels from the webhook to work out what the user needs to correct before they go through the SDK again. See Rejection reasons.

Rejection reasons

If a user’s application is REJECTED or RETRY_REQUIRED, two fields explain why:
  • rejectionReason is a short message from the compliance review that you can show to the user. It is often generic.
  • rejectionLabels lists the specific reject codes. Use them to tell the user what to fix.
Common codes include: See Rejection labels for the full list. It can grow, so handle codes you do not recognize.
rejectionLabels is for your internal use only. Do not display the codes to the end user or share them outside your organization. Some codes flag suspected fraud. Translate them into your own guidance instead.
A REJECTED status can also stem from an unsupported jurisdiction. Unlike the examples above, this case is non-retriable - the user cannot resolve it by resubmitting documents.

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 in the API reference for the full request schema.

Scenario 1: Happy path

  1. Create a user
  2. Advance the user application
  3. Simulate user application status with { "status": "APPROVED" }
  4. Confirm webhook received with status: "APPROVED"
  5. Create an account

Scenario 2: Retry required, then approved

  1. Create a user
  2. Advance the user application
  3. 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 again
  6. Simulate user application status with { "status": "APPROVED" }
  7. Confirm webhook received with status: "APPROVED"
  8. Create an account