Skip to main content

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.

info

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:

  1. Requesting secure URLs to upload the documents.
  2. Uploading the document files.
  3. 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

FieldTypeRequiredDescription
documentTypestringYesThe type of document to be uploaded. Supported values: ID, DRIVERS-LICENSE, PASSPORT, SELFIE, SELFIE-FROM-LIVENESS.
isDoubleSidedbooleanNoIf 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 }'
info

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

HeaderValueRequiredDescription
If-None-Match*YesThis header is required for the upload request.
Content-Typefile mime typeYesThe 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"
tip

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

FieldTypeRequiredDescription
fullNamestringYesThe complete name of the individual.
dateOfBirthstringYesThe date of birth (Format: YYYY-MM-DD).
countryOfTaxIdstringYesThe country where the tax identification number was issued.
taxIdNumberstringYesThe tax identification number.
emailstringYesThe email address.
phonestringNoThe phone number.
countrystringYesThe country of residence.
statestringYesThe state/province of residence.
citystringYesThe city of residence.
zipCodestringYesThe postal code.
streetAddressstringYesThe street address.
uploadedSelfieIdstringYesThe id returned in Step 1 for the selfie upload.
uploadedDocumentIdstringYesThe id returned in Step 1 for the document (ID, Passport, etc.).
sandboxRejectbooleanNoSet to true to simulate a failed KYC attempt in the sandbox environment.
info
  • Country codes must follow the ISO 3166-1 alpha-3 standard (e.g., BRA for Brazil).
  • State codes must follow the state or province code standard (e.g., SP for 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"
}
info

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
info

To perform KYC for a Subaccount, simply pass the subAccountId field as a request parameter.

Request Body

{
"redirectUrl": "https://example.com/kyc-complete"
}

Fields

FieldTypeRequiredDescription
redirectUrlstringNoURL 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

FieldTypeDescription
attemptIdstringUnique identifier for this KYC attempt.
kycUrlstringURL 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

  1. Generate Link: Call the endpoint with optional redirectUrl
  2. Redirect User: Direct the user to the returned kycUrl
  3. User Completes Verification: User completes the verification process in the web interface
  4. Redirect Handling: If redirectUrl was provided, user is redirected back after completion
info

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.

info

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

ParameterTypeDescription
createdAtAfterstring(Optional) Filters for documents created after this timestamp (ISO 8601).
createdAtBeforestring(Optional) Filters for documents created before this timestamp (ISO 8601).
documentTypestring(Optional) Filters by a specific document type (e.g., PASSPORT).
cursorstring(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

ParameterTypeDescription
documentIdstringThe ID of the document, obtained from Step 1.

Response Fields

The response contains the current state of the document.

FieldTypeDescription
idstringThe unique identifier of the document.
documentTypestringThe type of document (e.g., PASSPORT, SELFIE).
uploadURLFrontstringThe pre-signed URL for uploading the front of the document.
uploadStatusFrontstringThe status of the front upload. Possible values: PENDING, PROCESSING, COMPLETED, EXPIRED.
uploadErrorFrontstringAn error message if the front upload failed.
uploadURLBackstringThe pre-signed URL for the back of the document. Only present for double-sided documents.
uploadStatusBackstringThe status of the back upload. Possible values: PENDING, PROCESSING, COMPLETED, EXPIRED.
uploadErrorBackstringAn error message if the back upload failed.
readybooleanIf true, the document's id can be used in the POST /v2/kyc/new-level-1/api request.
createdAtstringThe timestamp when the document request was created.
updatedAtstringThe 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

ParameterTypeDescription
createdAtAfterstring(Optional) Filters for attempts created after this timestamp (ISO 8601).
createdAtBeforestring(Optional) Filters for attempts created before this timestamp (ISO 8601).
levelNamestring(Optional) Filters by a specific KYC level (e.g., level-1).
statusstring(Optional) Filters by status. Values: PENDING, PROCESSING, COMPLETED, EXPIRED.
resultstring(Optional) Filters by result. Values: APPROVED, REJECTED.
cursorstring(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

ParameterTypeDescription
attemptIdstringThe 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

FieldDescription
idThe unique ID of the KYC attempt.
levelNameThe KYC level attempted (e.g., level-1).
submissionDataAn object containing the data submitted by the user.
statusThe processing status: PENDING, PROCESSING, COMPLETED, EXPIRED.
resultThe final outcome: APPROVED or REJECTED.
resultMessageA message providing details on the result, especially for rejections.
rejectionLabelsAn array of machine-readable labels categorizing the rejection reasons. Empty array when approved. See Rejection Labels for possible values.
retryableA boolean indicating if the user can attempt this KYC level again.
createdAtThe timestamp when the attempt was created.
updatedAtThe 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.

LabelDescription
OBIT_INDICATIONThe individual has an obituary indication on record.
NAME_MISMATCHThe provided name does not match official records.
BIRTHDATE_MISMATCHThe provided date of birth does not match official records.
TAX_ID_NOT_FOUNDThe provided tax identification number was not found.
TAX_ID_IRREGULARThe tax identification number has an irregular status.
UNDERAGEThe individual is under the minimum required age.
PEPThe individual is a Politically Exposed Person.
SANCTIONSThe individual is on a current sanctions list.
KYC_STATUS_FAILEDThe identity verification could not be completed.
CRIMINAL_LAWSUITSCriminal lawsuits were detected for the individual.
EXCESSIVE_LAWSUITSAn excessive number of lawsuits were detected.
DOCUMENT_UNREADABLEThe submitted document could not be read or processed.
DOCUMENT_NAME_MISMATCHThe name on the document does not match the provided name.
INCONCLUSIVEThe verification was inconclusive. Please contact support.
COMPROMISED_PERSONSIdentity could not be verified due to compromised person records.
ADVERSE_MEDIAAdverse media findings were detected.
CRIMINALCriminal records were found.
DOCUMENT_IRREGULARITYThe submitted document has irregularities.
SELFIE_MISMATCHThe selfie does not match the document photo.
FRAUDULENT_LIVENESSThe liveness verification detected fraudulent behavior.
NOT_DOCUMENTThe submitted file is not a valid identity document.
FACE_MATCH_FAILEDThe selfie does not match the face on the submitted document.
SOURCE_FACE_CONFIDENCE_TOO_LOWThe face in the source image could not be detected with sufficient confidence.
IMAGE_QUALITY_INSUFFICIENTThe image quality is too low for face comparison.
FACE_POSE_NOT_SUITABLEThe face pose in the image is not suitable for verification.
FACE_PARTIALLY_OBSTRUCTEDThe face in the image is partially obstructed.
NO_FACE_DETECTEDNo face was detected in the submitted image.
IMAGE_TOO_BLURRYThe submitted image is too blurry for verification.
IMAGE_OVEREXPOSEDThe submitted image is too bright for verification.
IMAGE_UNDEREXPOSEDThe submitted image is too dark for verification.
DICT_MARKThe user is considered high risk by Brazilian Financial Institutions.
info

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 MessageDescription
name does not matchThe provided name does not match official records.
birthdate does not matchThe provided date of birth does not match official records.
tax id does not existThe provided tax identification number was not found.
tax id situation is irregular or it doesn't existThe tax identification number has an irregular or inactive status.
user is underageThe individual does not meet the minimum age requirement.
user has obit indicationThe individual has an obituary indication on record.
no info was found on the provided pictureThe submitted document could not be read or processed.
document name does not match user nameThe name on the submitted document does not match the provided name.

Compliance

Result MessageDescription
politically exposed personThe individual is classified as a Politically Exposed Person (PEP).
currently sanctionedThe individual appears on a current sanctions list.
criminal lawsuits detectedCriminal lawsuits were detected for the individual.
adverse media foundAdverse media findings were detected.
criminal records foundCriminal records were found for the individual.
rejected due to compliance reasonsThe verification was rejected due to internal compliance policies.

Selfie & Face Verification

Result MessageDescription
selfie does not match documentThe selfie photo does not match the face on the submitted document.
face not clearly detected in source imageThe face in the source image could not be detected with sufficient confidence.
image quality too low for face comparisonThe submitted image quality is insufficient for face verification.
face pose not suitable for comparisonThe face pose in the image is not suitable for verification.
face partially obstructed in imageThe face in the image is partially obstructed or covered.
no face detected in imageNo face was detected in the submitted image.
image too blurry for verificationThe submitted image is too blurry to process.
image too bright for verificationThe submitted image is overexposed.
image too dark for verificationThe submitted image is underexposed.
liveness verification failedThe liveness check detected fraudulent behavior.

Document Validation

Result MessageDescription
identity could not be verifiedThe identity verification could not be completed.
document could not be verifiedThe submitted document has irregularities or could not be validated.
invalid document submittedThe submitted file is not a valid identity document.

Other

Result MessageDescription
inconclusive: KYC verification could not be completedThe verification process was inconclusive. A new attempt may be possible.
inconclusive: please contact usThe verification was inconclusive. Please contact support for assistance.
please contact us for more informationAdditional review is required. Please contact support.
tip

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.