Universal KYC
Deliver a complete and end-to-end KYC workflow through a single unified API which seamlessly verifying cardholder identity and enabling instant approval for card issuance.
Overview
This flow enables completion of the end-to-end entity onboarding and card issuance process as follows:
- Create the entity profile in the system using a standardised JSON structure capturing core user details and identifiers.
- Submit the completed KYC payload including ID and proof of address documents for verification through the configured KYC provider.
- Receive the approval decision and retrieve the signed KYC payload for approved applications.
- The signed payload is used to initiate card creation through the card issuance flow.
Prerequisites
- Compliance approval from Reap for the use of Universal KYC for the program.
For questions regarding the Universal KYC approval process, please contact your account manager for assistance.
- An established KYC provider is already in place.
- Agreement that Reap retains the final approval authority for card issuance under its non-reliance model.
This guide contains two post-approval paths:
- Non-BIN sponsorship clients: must complete Step 6 (Fetch the Signed Payload) and Step 7 (Create Card).
- BIN sponsorship clients (for example, Bybit): do not need to complete Steps 6 and 7. They may use the verified KYC information directly in their own downstream card issuance flow after KYC is approved.
Step 1: Register and Create Entity
Reap requires an internal record (an Entity) to attach KYC requirements, documents, and decisions. The externalId links the cardholder record to Reap.
Call the Create Entity Endpoint
Use POST /entity to create and register an entity for the cardholder in Reap’s system for KYC processing.
Sample Request (cURL):
curl --request POST \
--url https://sandbox-compliance.api.reap.global/entity \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'x-reap-api-key: ********' \
--data '
{
"externalId": "CUSTOMER-DEMO-10001",
"type": "INDIVIDUAL"
}
'Key Input:
externalId: Unique ID to identify the cardholder (defined and managed in your system)type: Type of entity being created (Must be set toINDIVIDUAL)
Sample Response:
{
"id": "5f54bcf9-5a21-4f76-a819-6a65a8c238b8",
"externalId": "CUSTOMER-TEST-0000307",
"businessId": "e10e9f95-f256-4c47-bcf6-a6029e09c3aa",
"type": "INDIVIDUAL"
}Key Output:
id: Unique identifier generated by Reap for the created entity (Used asentityIdin subsequent API calls)externalId: The external reference ID provided during entity creationbusinessId: Unique identifier for the associated business accounttype: Type of entity created
Step 2: Submit KYC Details
Universal KYC requires KYC details to be submitted in a standardised schema so requirements can be evaluated consistently across different providers.
Canonical KYC Payload Structure
The Canonical KYC payload must follow the Universal KYC schema and adhere to the required structure shown in the readable object format below:
{
"externalUserId": "demo2-universal-kyc-ingestinon-entity-1x2",
"provider":
{
"name": "sumsub",
"status": "APPROVED",
"data":
[
{
"applicantId": "7c9e4a1f2b6d8e3a5c0f9b12",
"levelName": "poa_idv_level_v1",
"verificationStatus": "reviewed",
"verifiedAt": "2025-01-15T10:22:11Z",
"webhook":
{
"eventType": "applicantReviewed",
"receivedAt": "2025-01-15T10:22:14Z",
"payload":
{
"reviewStatus": "completed",
"reviewResult":
{
"reviewAnswer": "GREEN"
}
}
},
"metadata":
{
"sumsubCorrelationId": "9f3c2a7b-1d4e-4c8f-a2b6-5e7d9c1f0a3b"
}
}
]
},
"identity":
{
"firstName": "Jack",
"middleName": "Sam",
"lastName": "Ong",
"fullName": "Jack Sam Ong",
"dob": "1994-06-18",
"nationality": "CAN"
},
"document":
[
{
"type": "PASSPORT",
"number": "K1234567",
"country": "CAN",
"issuingDate": "2019-03-10",
"expiryDate": "2029-03-09"
}
],
"address":
{
"country": "CAN",
"postCode": "M5V 3L9",
"town": "Toronto",
"street": "King Street West",
"subStreet": "Downtown",
"state": "ON",
"buildingName": "TIFF Bell Lightbox",
"flatNumber": "1208",
"buildingNumber": "350",
"formattedAddress": "Unit 1208, 350 King Street West, Toronto, ON M5V 3L9, Canada"
},
"liveness":
{
"result": "APPROVED",
"checkedAt": "2025-01-15T10:19:40Z"
}
}
cardProcessorPublicTokenis only required when the client is under BIN sponsorship.
The following table defines the canonical Universal KYC payload structure. All fields must adhere to the specified data types, formats, and validation rules. Nested fields are represented using dot notation, and arrays are indicated using [] in Table 1. below:
| Variable Name | Details |
|---|---|
| externalUserId | Required. String. External user identifier from client system. |
| cardProcessorPublicToken | Optional. String (max 500 chars). Card processor token. |
| provider | Required. Object. |
| provider.name | Required. String (1–50). Example: sumsub, jumio. |
| provider.status | Required. Enum: APPROVED, REJECTED, WARNING, NOT_EXECUTED. |
| provider.data | Required. Array<object>. Provider-specific payload (any shape allowed). |
| provider.data[] | Required. Object. Free-form provider data. No fixed schema enforced. |
| identity | Required. Object. |
| identity.firstName | Required. String (1–100). |
| identity.middleName | Optional. String (≤100). |
| identity.lastName | Optional. String (≤100). |
| identity.fullName | Required. String (1–200). Full legal name per document/provider. |
| identity.dob | Required. String. Format: YYYY-MM-DD. |
| identity.nationality | Required. String. ISO 3166-1 alpha-3 (auto uppercased). |
| document | Required. Array<object>. Minimum 1 document required. |
| document[] | Required. Object. |
| document[].type | Required. Enum: PASSPORT, ID_CARD, DRIVERS_LICENCE, RESIDENCE_PERMIT. |
| document[].number | Required. String (1–50). |
| document[].country | Required. String. ISO 3166-1 alpha-3 (issuing country). |
| document[].issuingDate | Required. String. Format: YYYY-MM-DD. |
| document[].expiryDate | Optional. String. Format: YYYY-MM-DD. |
| address | Required. Object. |
| address.country | Required. String. ISO 3166-1 alpha-3. |
| address.postCode | Required. String (1–20). |
| address.town | Optional. String (≤100). |
| address.street | Required. String (1–200). |
| address.subStreet | Optional. String (≤200). |
| address.state | Optional. String (≤100). |
| address.buildingName | Optional. String (≤100). |
| address.flatNumber | Optional. String (≤20). |
| address.buildingNumber | Optional. String (≤20). |
| address.formattedAddress | Optional. String (≤500). |
| liveness | Required. Object. |
| liveness.result | Required. Enum: APPROVED, REJECTED, WARNING, NOT_EXECUTED. |
| liveness.checkedAt | Conditionally Required. ISO-8601 datetime (e.g. 2026-02-24T10:15:30Z). Required unless result = NOT_EXECUTED. |
Table 1. Universal KYC Schema – Canonical Payload Structure
Call the Submit Requirement Endpoint
Use POST /entity/entityId/requirement and pass the canonical KYC payload in the value field as a string to attach the standardised KYC result to the entity.
Sample Request (cURL):
curl --request POST \
--url https://sandbox-compliance.api.reap.global/entity/5f54bcf9-5a21-4f76-a819-6a65a8c238b8/requirement \
--header 'Accept: application/json' \
--header 'content-type: application/json' \
--header 'x-reap-api-key: ********' \
--data '{
"requirementSlug": "ukyc-canonical-kyc-data",
"value": "{\"externalUserId\":\"demo2-universal-kyc-ingestinon-entity-1x2\",\"provider\":{\"name\":\"sumsub\",\"status\":\"APPROVED\",\"data\":[{\"applicantId\":\"7c9e4a1f2b6d8e3a5c0f9b12\",\"levelName\":\"poa_idv_level_v1\",\"verificationStatus\":\"reviewed\",\"verifiedAt\":\"2025-01-15T10:22:11Z\",\"webhook\":{\"eventType\":\"applicantReviewed\",\"receivedAt\":\"2025-01-15T10:22:14Z\",\"payload\":{\"reviewStatus\":\"completed\",\"reviewResult\":{\"reviewAnswer\":\"GREEN\"}}},\"metadata\":{\"sumsubCorrelationId\":\"9f3c2a7b-1d4e-4c8f-a2b6-5e7d9c1f0a3b\"}}]}},\"identity\":{\"firstName\":\"Jack\",\"middleName\":\"Sam\",\"lastName\":\"Ong\",\"fullName\":\"Jack Sam Ong\",\"dob\":\"1994-06-18\",\"nationality\":\"CAN\"},\"document\":[{\"type\":\"PASSPORT\",\"number\":\"K1234567\",\"country\":\"CAN\",\"issuingDate\":\"2019-03-10\",\"expiryDate\":\"2029-03-09\"}],\"address\":{\"country\":\"CAN\",\"postCode\":\"M5V 3L9\",\"town\":\"Toronto\",\"street\":\"King Street West\",\"subStreet\":\"Downtown\",\"state\":\"ON\",\"buildingName\":\"TIFF Bell Lightbox\",\"flatNumber\":\"1208\",\"buildingNumber\":\"350\",\"formattedAddress\":\"Unit 1208, 350 King Street West, Toronto, ON M5V 3L9, Canada\"},\"liveness\":{\"result\":\"APPROVED\",\"checkedAt\":\"2025-01-15T10:19:40Z\"}}"
}'Key Input:
entityId: Unique ID of the entity created in Step 1.requirementSlug: Identifier of the requirement being fulfilled. For Universal KYC canonical submission, use the following fixed key:ukyc-canonical-kyc-data.- value: Canonical KYC payload submitted in standardised schema formating as a string.
The
valuefield must contain the canonical KYC payload serialised as a properly escaped JSON string that strictly follows the Universal KYC schema
Step 3: Submit Identity Document
Uploading the identity document ensures that verifiable evidence of the check is retained, supporting audit requirements and downstream compliance reviews tied to the Entity.
Call the Identity Document Upload Endpoint
Use POST /entity/entityId/requirement to upload the file to the ukyc-id-document requirement slug and file path.
Sample Request (cURL):
curl --request POST \
--url https://sandbox-compliance.api.reap.global/entity/5f54bcf9-5a21-4f76-a819-6a65a8c238b8/requirement-slug/ukyc-id-document/upload \
--header 'Accept: application/json' \
--header 'Content-Type: multipart/form-data' \
--header 'x-reap-api-key: ********' \
--form 'files=@"passport.pdf"'
Key Input:
entityId: Unique ID of the entity created in Step 1files: Identity document file submitted as multipart/form-data
filesupload requirements: Maximum file size: 10 MB Supported file formats: JPG, JPEG, PNG, PDF
Step 4: Submit Proof of Address Document
Proof of address is commonly required for KYC/KYB completeness. Submitting it via the dedicated requirement slug ensures the evidence is correctly classified and evaluated.
Call the Proof of Address Upload Endpoint
Use POST /entity/entityId/requirement to upload the file to the kyc-proof-of-address-document requirement slug, and pass a file path.
Sample Request (cURL):
curl --request POST \
--url https://sandbox-compliance.api.reap.global/entity/5f54bcf9-5a21-4f76-a819-6a65a8c238b8/requirement-slug/ukyc-proof-of-address-document/upload \
--header 'Accept: application/json' \
--header 'Content-Type: multipart/form-data' \
--header 'x-reap-api-key: ********' \
--form 'files=@"utilitybill.pdf"'
Key Input:
entityId: Unique ID of the entity created in Step 1files: Proof of address document submitted as multipart/form-data
filesupload requirements: Maximum file size: 10 MBSupported file formats: JPG, JPEG, PNG, PDF
Step 5: KYC Decision
Once all required information and supporting documents have been successfully submitted, the application will enter the final KYC review stage.
At this stage, a final decision state must be attained before proceeding further in the card issuance flow.
Only applications in an Approved state can proceed to Step 6 (Signed Payload Retrieval)
Sample Decision Webhook
The KYC decision is communicated via webhook notification.
{
"eventName": "card_issuance_api_access_updated",
"eventType": "account_status_change",
"data": {
"eventId": "938c65f7-2aad-494d-b488-5256c4cfc370",
"message": "User profile approved - card generation enabled",
"entityId": "6ac28264-c21b-4757-b141-1efce00adce6",
"timestamp": "2026-01-27T13:27:51.027Z",
"status": "APPROVED"
}
}{
"eventName": "card_issuance_api_access_updated",
"eventType": "account_status_change",
"data": {
"eventId": "fc7b8d1d-9e08-4c61-bef2-3ce4e6162dcf",
"message": "Universal KYC requirement rejected",
"entityId": "6c539925-f00c-4b11-bbc8-7edec5bb69b1",
"status": "REJECTED",
"moderationComment": "Country of residence (IND) is prohibited",
"rejectLabels": [
"PROHIBITED_RESIDENCE"
],
"reviewRejectType": "FINAL",
"timestamp": "2026-01-27T13:29:58.336Z"
}
}| Webhook Desision | Notes |
|---|---|
| Approved | Cardholder has passed KYC checks and can proceed to create a card |
| Rejected | Cardholder has not passed KYC checks and not allowed to create a card. You may resubmit requirements and documents to try again later. |
Step 6: Fetch the Signed Payload
The signed payload is a portable and tamper-proof representation of an approved KYC application. It serves as the authorisation evidence for proceeding with card issuance.
Call the Signed Payload Endpoint
Use GET /entity/entityId/signed-payload to retrieve the signed payload associated with the approved KYC application. Ensure the correct featureSlug is provided to specify the intended use case.
Sample Request (cURL):
curl --request GET \
--url https://sandbox-compliance.api.reap.global/entity/5f54bcf9-5a21-4f76-a819-6a65a8c238b8/signed-payload?featureSlug=universal-kyc-card-issuance-kyc-api \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'featureSlug: universal-kyc-card-issuance-kyc-api' \
--header 'x-reap-api-key: ********'
Key Input:
entityId: Unique ID of the entity created in Step 1featureSlug: Feature identifier as a fixed header value:universal-kyc-card-issuance-kyc-api
Sample Response:
{
"firstName": "Jack",
"lastName": "Sam Ong",
"dob": "1994-06-18",
"idDocumentType": "Passport",
"idDocumentNumber": "K1234567",
"residentialAddress":
{
"line1": "Flat 1208, 350, TIFF Bell Lightbox, King Street West",
"line2": "Downtown",
"city": "Toronto",
"country": "CAN",
"postalCode": "M5V 3L9"
},
"expiresAt": "2026-03-10T09:18:51.998Z",
"signature": "bd6565bfb621f6321095e7dc574ea52b3829e29a732440170794fabfc8dec..."
}Key Output:
firstName: Verified first name from the approved KYC record.lastName: Verified last name from the approved KYC record.dob: Date of birth in YYYY-MM-DD format.residentialAddress: Verified residential address (line1, line2, city, country, postalCode).idDocumentType: Type of government-issued ID used for verification.idDocumentNumber: Verified ID document number.expiresAt: Expiry timestamp of the signed payload (ISO 8601).signature: Cryptographic signature ensuring payload integrity and authenticity.
Step 7: Create Card
The output from Step 6 must be passed into the Create Card endpoint when creating a card.
Call the Create Card Endpoint
Use POST /cards to create the card and include the signed payload in the request body.
Sample Request (cURL):
curl --request POST \
--url https://sandbox-compliance.api.reap.global/cards \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Accept-Version: v2.0' \
--header 'x-reap-api-key: ********' \
--data '{
"...": "...",
"kyc": {
"firstName": "Jack",
"lastName": "Sam Ong",
"dob": "1994-06-18",
"idDocumentType": "Passport",
"idDocumentNumber": "K1234567",
"residentialAddress": {
"line1": "Flat 1208, 350, TIFF Bell Lightbox, King Street West",
"line2": "Downtown",
"city": "Toronto",
"country": "CAN",
"postalCode": "M5V 3L9"
},
"expiresAt": "2026-03-10T09:18:51.998Z",
"signature": "bd6565bfb621f6321095e7dc574ea52b3829e29a732440170794fabfc8dec..."
},
"...": "..."
}'Key Input:
firstName: Verified first name from the approved KYC record.lastName: Verified last name from the approved KYC record.dob: Date of birth in YYYY-MM-DD format.residentialAddress: Verified residential address (line1, line2, city, country, postalCode).idDocumentType: Type of government-issued ID used for verification.idDocumentNumber: Verified ID document number.expiresAt: Expiry timestamp of the signed payload (ISO 8601 format).signature: Signed JWT returned from the signed-payload endpoint, ensuring payload integrity and KYC approval.
Sample Response:
{
"id": "fa1bcdae-c101-4986-b385-8083fb43a7ab"
}Key Output:
id: Unique identifier of the successfully created card.
Refer to the official Create Card documentation for the full request schema and parameters:
👉 https://reap.readme.io/docs/create-cards
Demo
For a fully interactive demo, see below:
Updated 14 days ago
