KYC (Know Your Customer) Guide
KYC is a process to verify user identity, ensuring compliance with regulations and preventing fraud or illegal activities. It involves validating personal information and documents.
Remember that to perform KYC for a Subaccount, simply pass the subAccountId field as a request parameter.
KYC Level 1 - API
This guide outlines the multi-step process for completing KYC Level 1 by uploading identity documents and a selfie. This flow is ideal for handling user documents securely.
The process consists of three main steps:
- Requesting secure URLs to upload the documents.
- Uploading the document files.
- Submitting the KYC request with the uploaded document information.
Step 1: Request Document Upload URL - Selfie and Document
First, you need to request a secure pre-signed URL to upload your document. This endpoint will generate a link for you to send the file.
HTTP POST Request:
https://api.sandbox.avenia.io:10952/v2/documents/
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| documentType | string | Yes | The type of document to be uploaded. Supported values: ID, DRIVERS-LICENSE, PASSPORT, SELFIE, SELFIE-FROM-LIVENESS. |
| isDoubleSided | boolean | No | If true, the API will return two URLs for uploading the front and back of the document. Defaults to false. |
Sample JSON Body:
{
"documentType": "DRIVERS-LICENSE",
"isDoubleSided": true
}
JSON Response
If isDoubleSided is false or not provided:
{
"id": "46225dda-6371-4b1c-a777-eac36ec402af",
"uploadURLFront": "https://s3.amazonaws.com/kyc-uploads/46225dda-6371-4b1c-a777-eac36ec402af-front?AWSAccessKeyId=..."
}
If isDoubleSided is true:
{
"id": "46225dda-6371-4b1c-a777-eac36ec402af",
"uploadURLFront": "https://s3.amazonaws.com/kyc-uploads/46225dda-6371-4b1c-a777-eac36ec402af-front?AWSAccessKeyId=...",
"uploadURLBack": "https://s3.amazonaws.com/kyc-uploads/46225dda-6371-4b1c-a777-eac36ec402af-back?AWSAccessKeyId=..."
}
if documentType is SELFIE-FROM-LIVENESS:
{
"id": "c03b56e9-5c7d-444f-b90d-5aa2b28b8d9d",
"sessionId": "41909959-4796-4619-9bad-e96415fd72ce",
"livenessUrl": "https://app.avenia.io/liveness/41909959-4796-4619-9bad-e96415fd72ce?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTY1MDU1MTEsImlhdCI6MTc1NjUwNTIxMSwic2Vzc2lvbklkIjoiNDE5MDk5NTktNDc5Ni00NjE5LTliYWQtZTk2NDE1ZmQ3MmNlIiwic3ViIjoiYzAzYjU2ZTktNWM3ZC00NDRmLWI5MGQtNWFhMmIyOGI4ZDlkIn0.DRudCz4dyk5gf4bdA-g5z7wkjSf8A64B8KkiclHM1p4",
"validateLivenessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTY1MDU1MTEsImlhdCI6MTc1NjUwNTIxMSwic2Vzc2lvbklkIjoiNDE5MDk5NTktNDc5Ni00NjE5LTliYWQtZTk2NDE1ZmQ3MmNlIiwic3ViIjoiYzAzYjU2ZTktNWM3ZC00NDRmLWI5MGQtNWFhMmIyOGI4ZDlkIn0.DRudCz4dyk5gf4bdA-g5z7wkjSf8A64B8KkiclHM1p4"
}
Now you must perform the liveness check via the livenessUrl link.
cURL Example:
curl -X POST "https://api.sandbox.avenia.io:10952/v2/documents/" \
-H "Authorization: Bearer eyJhdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{ "documentType": "DRIVERS-LICENSE", "isDoubleSided": true }'
To successfully complete KYC Level 1, you must submit both a selfie and a valid document (ID, Driver's License, or Passport).
Make sure to save the id returned in this step for each uploaded document. You will need it to submit the final KYC request.
Step 2: Upload Document Files
Once you have the pre-signed URL(s) from Step 1, you must upload the corresponding document file(s) to each link.
For each URL (uploadURLFront and uploadURLBack), make a PUT request with the binary data of your image. This request must include the If-None-Match: * header.
HTTP PUT Request
Use the uploadURL... returned in Step 1 as the endpoint for your PUT request.
Headers
| Header | Value | Required | Description |
|---|---|---|---|
| If-None-Match | * | Yes | This header is required for the upload request. |
| Content-Type | file mime type | Yes | The MIME type of your file. Accepted formats are PNG, JPEG, and PDF. |
cURL Example
Here’s how to upload the front side of a document:
curl -X PUT "https://s3.amazonaws.com/kyc-uploads/46225dda-6371-4b1c-a777-eac36ec402af-front?AWSAccessKeyId=..." \
-H "Content-Type: image/jpeg" \
-H "If-None-Match: *" \
--data-binary "@/path/to/your/document-front.jpg"
Remember to perform this upload for each link you received. If you requested a double-sided upload, you must make separate PUT requests for uploadURLFront and uploadURLBack.
Step 3: Submit KYC Level 1 Request
After successfully uploading your selfie and document, the final step is to submit the KYC request with your personal information and the document IDs obtained in Step 1.
HTTP POST Request:
https://api.sandbox.avenia.io:10952/v2/kyc/new-level-1/api
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| fullName | string | Yes | The complete name of the individual. |
| dateOfBirth | string | Yes | The date of birth (Format: YYYY-MM-DD). |
| countryOfTaxId | string | Yes | The country where the tax identification number was issued. |
| taxIdNumber | string | Yes | The tax identification number. |
| string | Yes | The email address. | |
| phone | string | No | The phone number. |
| country | string | Yes | The country of residence. |
| state | string | Yes | The state/province of residence. |
| city | string | Yes | The city of residence. |
| zipCode | string | Yes | The postal code. |
| streetAddress | string | Yes | The street address. |
| uploadedSelfieId | string | Yes | The id returned in Step 1 for the selfie upload. |
| uploadedDocumentId | string | Yes | The id returned in Step 1 for the document (ID, Passport, etc.). |
| sandboxReject | boolean | No | Set to true to simulate a failed KYC attempt in the sandbox environment. |
- Country codes must follow the ISO 3166-1 alpha-3 standard (e.g.,
BRAfor Brazil). - State codes must follow the state or province code standard (e.g.,
SPfor São Paulo).
Sample JSON Body:
{
"fullName": "John Doe",
"dateOfBirth": "1990-01-15",
"countryOfTaxId": "BRA",
"taxIdNumber": "12345678900",
"email": "john.doe@example.com",
"country": "BRA",
"state": "SP",
"city": "Sample City",
"zipCode": "12345-678",
"streetAddress": "123 Main Street",
"uploadedSelfieId": "46225dda-6371-4b1c-a777-eac36ec402af",
"uploadedDocumentId": "a4b2015b-6ace-4c31-bd58-02fe28251582"
}
cURL Example:
curl -X POST "https://api.sandbox.avenia.io:10952/v2/kyc/new-level-1/api" \
-H "Authorization: Bearer eyJhdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{ ... }'
JSON Response:
{
"id": "4422b3ae-e2ee-44ed-abdf-ab9f682b30d3"
}
If you have webhooks configured, you will receive notifications regarding the status of your KYC Level 1 submission.
KYC Level 1 - Web SDK
This guide outlines how to use the Web SDK flow to complete KYC Level 1 verification. This approach is ideal when you want to offload the verification process to a secure, dedicated web interface managed by our platform.
HTTP POST Request:
https://api.sandbox.avenia.io:10952/v2/kyc/new-level-1/web-sdk
To perform KYC for a Subaccount, simply pass the subAccountId field as a request parameter.
Request Body
{
"redirectUrl": "https://example.com/kyc-complete"
}
Fields
| Field | Type | Required | Description |
|---|---|---|---|
| redirectUrl | string | No | URL where users will be redirected after completing or canceling the KYC process. If not provided, users will remain on the verification page. |
JSON Response
{
"attemptId": "550e8400-e29b-41d4-a716-446655440000",
"kycUrl": "https://sumsub.com/websdk/..."
}
Response Fields Explained
| Field | Type | Description |
|---|---|---|
| attemptId | string | Unique identifier for this KYC attempt. |
| kycUrl | string | URL to redirect the user to complete KYC verification. |
cURL Example
curl -X POST "https://api.sandbox.avenia.io:10952/v2/kyc/new-level-1/web-sdk" \
-H "Authorization: Bearer eyJhdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{
"redirectUrl": "https://yourapp.com/kyc-complete"
}'
Usage Flow
- Generate Link: Call the endpoint with optional
redirectUrl - Redirect User: Direct the user to the returned
kycUrl - User Completes Verification: User completes the verification process in the web interface
- Redirect Handling: If
redirectUrlwas provided, user is redirected back after completion
Once the user completes the process through the provided URL, you will receive status updates via webhooks if they are configured for your account with the KYC events. You can also poll for the status using the attemptId.
List All Document Statuses
You can retrieve a paginated list of all document uploads. The list can be filtered by creation date and document type.
To perform this operation on behalf of a subaccount, provide the subAccountId in the request.
HTTP GET Request:
https://api.sandbox.avenia.io:10952/v2/documents/
Query Parameters
| Parameter | Type | Description |
|---|---|---|
createdAtAfter | string | (Optional) Filters for documents created after this timestamp (ISO 8601). |
createdAtBefore | string | (Optional) Filters for documents created before this timestamp (ISO 8601). |
documentType | string | (Optional) Filters by a specific document type (e.g., PASSPORT). |
cursor | string | (Optional) A cursor for navigating to the next page of results. |
Sample JSON Response
The response includes an array of documents and a cursor string for pagination.
"documents": [
{
"id": "46225dda-6371-4b1c-a777-eac36ec402af",
"documentType": "SELFIE",
"uploadURLFront": "https://s3.amazonaws.com/kyc-uploads/46225dda-6371-4b1c-a777-eac36ec402af-Front?...",
"uploadStatusFront": "COMPLETED",
"uploadErrorFront": "",
"uploadURLBack": "",
"uploadStatusBack": "",
"uploadErrorBack": "",
"ready": true,
"createdAt": "2025-07-22T17:07:31.367323Z",
"updatedAt": "2025-07-22T17:07:41.473617Z"
},
{
"id": "a4b2015b-6ace-4c31-bd58-02fe28251582",
"documentType": "PASSPORT",
"uploadURLFront": "https://s3.amazonaws.com/kyc-uploads/a4b2015b-6ace-4c31-bd58-02fe28251582-Front?...",
"uploadStatusFront": "COMPLETED",
"uploadErrorFront": "",
"uploadURLBack": "",
"uploadStatusBack": "",
"uploadErrorBack": "",
"ready": true,
"createdAt": "2025-07-22T17:05:45.9915Z",
"updatedAt": "2025-07-22T17:05:56.090998Z"
}
],
"cursor": "NjEtMTc1MzIwMzc4NzE3MQ=="
}
Get Document Status by ID
You can check the status of a single document by providing its ID.
HTTP GET Request:
https://api.sandbox.avenia.io:10952/v2/documents/{documentId}
Path Parameters
| Parameter | Type | Description |
|---|---|---|
documentId | string | The ID of the document, obtained from Step 1. |
Response Fields
The response contains the current state of the document.
| Field | Type | Description |
|---|---|---|
id | string | The unique identifier of the document. |
documentType | string | The type of document (e.g., PASSPORT, SELFIE). |
uploadURLFront | string | The pre-signed URL for uploading the front of the document. |
uploadStatusFront | string | The status of the front upload. Possible values: PENDING, PROCESSING, COMPLETED, EXPIRED. |
uploadErrorFront | string | An error message if the front upload failed. |
uploadURLBack | string | The pre-signed URL for the back of the document. Only present for double-sided documents. |
uploadStatusBack | string | The status of the back upload. Possible values: PENDING, PROCESSING, COMPLETED, EXPIRED. |
uploadErrorBack | string | An error message if the back upload failed. |
ready | boolean | If true, the document's id can be used in the POST /v2/kyc/new-level-1/api request. |
createdAt | string | The timestamp when the document request was created. |
updatedAt | string | The timestamp of the last update. |
Sample JSON Response
{
"document": {
"id": "9e37f9a8-611a-4cad-99fb-dd13268bdf4b",
"documentType": "PASSPORT",
"uploadURLFront": "https://s3.amazonaws.com/kyc-uploads/9e37f9a8-611a-4cad-99fb-dd13268bdf4b-Front?...",
"uploadStatusFront": "COMPLETED",
"uploadErrorFront": "",
"uploadURLBack": "",
"uploadStatusBack": "",
"uploadErrorBack": "",
"ready": true,
"createdAt": "2025-07-22T17:03:07.17181Z",
"updatedAt": "2025-07-22T17:03:27.445025Z"
}
}
cURL Example
curl -X GET "https://api.sandbox.avenia.io:10952/v2/documents/9e37f9a8-611a-4cad-99fb-dd13268bdf4b" \
-H "Authorization: Bearer eyJhdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
List All KYC Attempts
You can retrieve a paginated history of all KYC attempts for your account or subaccount. The list can be filtered by date, level, status, and result.
HTTP GET Request:
https://api.sandbox.avenia.io:10952/v2/kyc/attempts/
Query Parameters
| Parameter | Type | Description |
|---|---|---|
createdAtAfter | string | (Optional) Filters for attempts created after this timestamp (ISO 8601). |
createdAtBefore | string | (Optional) Filters for attempts created before this timestamp (ISO 8601). |
levelName | string | (Optional) Filters by a specific KYC level (e.g., level-1). |
status | string | (Optional) Filters by status. Values: PENDING, PROCESSING, COMPLETED, EXPIRED. |
result | string | (Optional) Filters by result. Values: APPROVED, REJECTED. |
cursor | string | (Optional) A cursor for navigating to the next page of results. |
Sample JSON Response
{
"attempts": [
{
"id": "4422b3ae-e2ee-44ed-abdf-ab9f682b30d3",
"levelName": "level-1",
"submissionData": { "...": "..." },
"status": "COMPLETED",
"result": "APPROVED",
"resultMessage": "",
"rejectionLabels": [],
"retryable": false,
"createdAt": "2025-07-22T17:36:03.630248Z",
"updatedAt": "2025-07-22T17:36:03.630248Z"
},
{
"id": "e36733f7-182b-4828-9b67-d5be4c9d90db",
"levelName": "level-1",
"submissionData": { "...": "..." },
"status": "COMPLETED",
"result": "REJECTED",
"resultMessage": "birthdate does not match",
"rejectionLabels": ["BIRTHDATE_MISMATCH"],
"retryable": true,
"createdAt": "2025-07-22T17:31:31.348369Z",
"updatedAt": "2025-07-22T17:31:31.348369Z"
}
],
"cursor": "MTQzLTE3NTMyMDQ2ODk0MjE="
}
Get KYC Attempt by ID
Retrieve a specific KYC attempt by its unique ID.
HTTP GET Request:
https://api.sandbox.avenia.io:10952/v2/kyc/attempts/{attemptId}
Path Parameters
| Parameter | Type | Description |
|---|---|---|
attemptId | string | The ID of the KYC attempt to retrieve. |
Sample JSON Response
{
"attempt": {
"id": "e36733f7-182b-4828-9b67-d5be4c9d90db",
"levelName": "level-1",
"submissionData": {
"city": "SP",
"email": "johndoe@example.com",
"state": "BR-SP",
"fullName": "John Doe",
"dateOfBirth": "1998-08-16T00:00:00Z",
"taxIdNumber": "12345678900",
"..." : "..."
},
"status": "COMPLETED",
"result": "REJECTED",
"resultMessage": "birthdate does not match",
"rejectionLabels": ["BIRTHDATE_MISMATCH"],
"retryable": true,
"createdAt": "2025-07-22T17:31:31.348369Z",
"updatedAt": "2025-07-22T17:31:31.348369Z"
}
}
Response Fields Explained
| Field | Description |
|---|---|
id | The unique ID of the KYC attempt. |
levelName | The KYC level attempted (e.g., level-1). |
submissionData | An object containing the data submitted by the user. |
status | The processing status: PENDING, PROCESSING, COMPLETED, EXPIRED. |
result | The final outcome: APPROVED or REJECTED. |
resultMessage | A message providing details on the result, especially for rejections. |
rejectionLabels | An array of machine-readable labels categorizing the rejection reasons. Empty array when approved. See Rejection Labels for possible values. |
retryable | A boolean indicating if the user can attempt this KYC level again. |
createdAt | The timestamp when the attempt was created. |
updatedAt | The timestamp of the last update. |
Rejection Labels
When a KYC attempt is rejected, the rejectionLabels field provides machine-readable labels that categorize the rejection reasons. These labels allow you to programmatically handle different rejection scenarios.
| Label | Description |
|---|---|
OBIT_INDICATION | The individual has an obituary indication on record. |
NAME_MISMATCH | The provided name does not match official records. |
BIRTHDATE_MISMATCH | The provided date of birth does not match official records. |
TAX_ID_NOT_FOUND | The provided tax identification number was not found. |
TAX_ID_IRREGULAR | The tax identification number has an irregular status. |
UNDERAGE | The individual is under the minimum required age. |
PEP | The individual is a Politically Exposed Person. |
SANCTIONS | The individual is on a current sanctions list. |
KYC_STATUS_FAILED | The identity verification could not be completed. |
CRIMINAL_LAWSUITS | Criminal lawsuits were detected for the individual. |
EXCESSIVE_LAWSUITS | An excessive number of lawsuits were detected. |
DOCUMENT_UNREADABLE | The submitted document could not be read or processed. |
DOCUMENT_NAME_MISMATCH | The name on the document does not match the provided name. |
INCONCLUSIVE | The verification was inconclusive. Please contact support. |
COMPROMISED_PERSONS | Identity could not be verified due to compromised person records. |
ADVERSE_MEDIA | Adverse media findings were detected. |
CRIMINAL | Criminal records were found. |
DOCUMENT_IRREGULARITY | The submitted document has irregularities. |
SELFIE_MISMATCH | The selfie does not match the document photo. |
FRAUDULENT_LIVENESS | The liveness verification detected fraudulent behavior. |
NOT_DOCUMENT | The submitted file is not a valid identity document. |
FACE_MATCH_FAILED | The selfie does not match the face on the submitted document. |
SOURCE_FACE_CONFIDENCE_TOO_LOW | The face in the source image could not be detected with sufficient confidence. |
IMAGE_QUALITY_INSUFFICIENT | The image quality is too low for face comparison. |
FACE_POSE_NOT_SUITABLE | The face pose in the image is not suitable for verification. |
FACE_PARTIALLY_OBSTRUCTED | The face in the image is partially obstructed. |
NO_FACE_DETECTED | No face was detected in the submitted image. |
IMAGE_TOO_BLURRY | The submitted image is too blurry for verification. |
IMAGE_OVEREXPOSED | The submitted image is too bright for verification. |
IMAGE_UNDEREXPOSED | The submitted image is too dark for verification. |
DICT_MARK | The user is considered high risk by Brazilian Financial Institutions. |
A single KYC attempt may have multiple rejection labels if more than one issue was detected. The resultMessage field provides a human-readable description of the primary rejection reason.
Result Messages
When a KYC attempt is rejected, the resultMessage field contains a human-readable description of the primary rejection reason. Below is the complete list of possible messages.
Identity & Document Verification
| Result Message | Description |
|---|---|
name does not match | The provided name does not match official records. |
birthdate does not match | The provided date of birth does not match official records. |
tax id does not exist | The provided tax identification number was not found. |
tax id situation is irregular or it doesn't exist | The tax identification number has an irregular or inactive status. |
user is underage | The individual does not meet the minimum age requirement. |
user has obit indication | The individual has an obituary indication on record. |
no info was found on the provided picture | The submitted document could not be read or processed. |
document name does not match user name | The name on the submitted document does not match the provided name. |
Compliance
| Result Message | Description |
|---|---|
politically exposed person | The individual is classified as a Politically Exposed Person (PEP). |
currently sanctioned | The individual appears on a current sanctions list. |
criminal lawsuits detected | Criminal lawsuits were detected for the individual. |
adverse media found | Adverse media findings were detected. |
criminal records found | Criminal records were found for the individual. |
rejected due to compliance reasons | The verification was rejected due to internal compliance policies. |
Selfie & Face Verification
| Result Message | Description |
|---|---|
selfie does not match document | The selfie photo does not match the face on the submitted document. |
face not clearly detected in source image | The face in the source image could not be detected with sufficient confidence. |
image quality too low for face comparison | The submitted image quality is insufficient for face verification. |
face pose not suitable for comparison | The face pose in the image is not suitable for verification. |
face partially obstructed in image | The face in the image is partially obstructed or covered. |
no face detected in image | No face was detected in the submitted image. |
image too blurry for verification | The submitted image is too blurry to process. |
image too bright for verification | The submitted image is overexposed. |
image too dark for verification | The submitted image is underexposed. |
liveness verification failed | The liveness check detected fraudulent behavior. |
Document Validation
| Result Message | Description |
|---|---|
identity could not be verified | The identity verification could not be completed. |
document could not be verified | The submitted document has irregularities or could not be validated. |
invalid document submitted | The submitted file is not a valid identity document. |
Other
| Result Message | Description |
|---|---|
inconclusive: KYC verification could not be completed | The verification process was inconclusive. A new attempt may be possible. |
inconclusive: please contact us | The verification was inconclusive. Please contact support for assistance. |
please contact us for more information | Additional review is required. Please contact support. |
Use rejectionLabels for programmatic handling of rejection reasons, and resultMessage for displaying user-friendly feedback. The rejectionLabels field provides more granular categorization, while resultMessage is a single human-readable string.