Skip to main content
This guide shows you how to submit KYC (Know Your Customer) information programmatically using the HIFI API. Users must complete KYC verification to unlock rails (payment corridors that enable currency conversions between fiat and stablecoins).
Recommended: For most use cases, use KYC Links for a hosted, user-friendly flow. This guide covers the programmatic API approach for teams that need full control over the KYC collection process.

Prerequisites

  • API keys from the Dashboard (Get API keys)
  • A user created in your HIFI account
  • Sandbox endpoint: https://sandbox.hifibridge.com
All examples use the sandbox environment. For production, replace the sandbox URL with the production endpoint and use your production API keys.

Process Overview

  1. Retrieve KYC Requirements - Get required information for your target rail
  2. Update KYC Information - Provide personal information
  3. Upload KYC Documents - Submit identity verification documents
  4. Submit KYC - Submit the application for review
  5. Check KYC Status - Monitor approval status

Retrieve KYC Requirements

First, find out what information is needed for your target rail by calling the Retrieve KYC Requirements endpoint. Request:
curl --request GET \
     --url 'https://sandbox.hifibridge.com/v2/users/32051b2f-0798-55a7-9c42-b08da4192c97/kyc/requirements?rails=USD' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY'
Response:
{
  "userId": "32051b2f-0798-55a7-9c42-b08da4192c97",
  "rails": "USD",
  "type": "individual",
  "required": {
    "firstName": "string",
    "lastName": "string",
    "email": "string",
    "phone": "string",
    "nationality": "string",
    "dateOfBirth": "date",
    "taxIdentificationNumber": "string",
    "documents": {
      "identity": {
        "minCount": 1,
        "acceptedDocTypes": [
          "DRIVERS",
          "ID_CARD",
          "PASSPORT",
          "RESIDENCE_PERMIT"
        ]
      }
    }
  },
  "optional": {},
  "invalid": {
    "message": "fields are either missing or invalid",
    "fields": {
      "phone": "missing",
      "nationality": "missing",
      "taxIdentificationNumber": "missing"
    },
    "documents": {
      "message": "The following document groups are not satisfied: identity",
      "groups": {
        "identity": {
          "minCount": 1,
          "acceptedDocTypes": [
            "DRIVERS",
            "ID_CARD",
            "PASSPORT",
            "RESIDENCE_PERMIT"
          ]
        }
      }
    }
  }
}
Response Fields:
required
object
All mandatory KYC fields needed for the rail. These must be provided before submission.
optional
object
Additional fields that aren’t mandatory but may help with approval or enable additional features.
invalid
object
Most Important Field: Lists any missing or invalid data that must be corrected before KYC submission.
Rail-Specific Requirements: Each rail has different KYC requirements based on regulatory needs. Visit our Rails page to learn about available rails and their specific requirements.

Update KYC Information

Provide the missing personal information using the Update KYC endpoint. Request:
curl --request POST \
     --url https://sandbox.hifibridge.com/v2/users/32051b2f-0798-55a7-9c42-b08da4192c97/kyc \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --data '
{
  "phone": "+18573491112",
  "taxIdentificationNumber": "725569852",
  "nationality": "USA"
}
'
Response:
{
  "userId": "32051b2f-0798-55a7-9c42-b08da4192c97",
  "kycInfo": {
    "type": "individual",
    "firstName": "John",
    "lastName": "Doe",
    "nationality": "USA",
    "email": "[email protected]",
    "phone": "+18573491112",
    "address": {
      "city": "New York",
      "country": "USA",
      "postalCode": "10010",
      "addressLine1": "123 Main St",
      "stateProvinceRegion": "NY"
    },
    "dateOfBirth": "1999-01-01T00:00:00+00:00",
    "taxIdentificationNumber": "725569852",
    "documents": []
  }
}
Personal information updated! Notice the documents array is still empty - we’ll upload those next.

Upload KYC Documents

Now we need to upload identity verification documents. This is a two-step process:
  1. Upload the file to get a fileId
  2. Attach the file to the user’s KYC application

Upload a File

First, upload the identity document (driver’s license, passport, etc.) using the Upload a File endpoint. Request:
curl --request POST \
     --url https://sandbox.hifibridge.com/v2/files \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY' \
     --header 'content-type: multipart/form-data' \
     --form 'file=@drivers_license_front.png'
Response:
{
  "id": "file_JzALYV2L1-4LBmaxZ6GCm",
  "createdAt": "2025-09-25T22:05:16.764Z",
  "fileName": "drivers_license_front.png",
  "size": 17834,
  "mimeType": "image/png"
}
Response Fields:
id
string
required
The file ID. Save this - you’ll use it in the next step to attach this document to the user’s KYC application.
fileName
string
Original filename of the uploaded file.
size
number
File size in bytes.
mimeType
string
File type (e.g., image/png, image/jpeg, application/pdf).

Add Documents to KYC

Now attach the uploaded file(s) to the user’s KYC application using the Add Documents endpoint.
Driver’s License Requirements: Most identity documents require both front and back images. For this example, we’ll use the same file ID for both sides, but in production you should upload and attach separate images.
Request:
curl --request POST \
     --url https://sandbox.hifibridge.com/v2/users/32051b2f-0798-55a7-9c42-b08da4192c97/kyc/documents \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --data '
[
  {
    "type": "DRIVERS",
    "subType": "FRONT_SIDE",
    "issuedCountry": "USA",
    "fileId": "file_JzALYV2L1-4LBmaxZ6GCm"
  },
  {
    "type": "DRIVERS",
    "subType": "BACK_SIDE",
    "issuedCountry": "USA",
    "fileId": "file_JzALYV2L1-4LBmaxZ6GCm"
  }
]
'
Request Fields:
type
string
required
Document type. Options: DRIVERS, ID_CARD, PASSPORT, RESIDENCE_PERMIT
subType
string
required
Which side of the document. Options: FRONT_SIDE, BACK_SIDE (passports typically only need FRONT_SIDE)
issuedCountry
string
required
Country that issued the document (ISO country code).
fileId
string
required
The file ID received from the file upload endpoint.
Response:
{
  "count": 2,
  "data": [
    {
      "id": "e477fa56-3e1e-4dac-abe6-008166749f30",
      "type": "DRIVERS",
      "subType": "FRONT_SIDE",
      "issuedCountry": "USA",
      "url": "https://pqgnrjvoqbopfaxmlhlv.supabase.co/storage/v1/object/sign/kyc_documents/...",
      "fileId": "file_JzALYV2L1-4LBmaxZ6GCm"
    },
    {
      "id": "a2190d1d-61af-416d-8fcf-20673da5eaa0",
      "type": "DRIVERS",
      "subType": "BACK_SIDE",
      "issuedCountry": "USA",
      "url": "https://pqgnrjvoqbopfaxmlhlv.supabase.co/storage/v1/object/sign/kyc_documents/...",
      "fileId": "file_JzALYV2L1-4LBmaxZ6GCm"
    }
  ]
}
Response Fields:
count
number
Number of documents successfully attached.
data
array
Array of document objects with IDs, types, and temporary signed URLs for viewing.
Documents uploaded! All required KYC information is now complete. Time to submit for review.

Submit KYC

With all fields and documents provided, submit the KYC application to unlock the rail using the Submit KYC endpoint. Request:
curl --request POST \
     --url https://sandbox.hifibridge.com/v2/users/32051b2f-0798-55a7-9c42-b08da4192c97/kyc/submissions \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --data '{"rails": "USD"}'
Response:
{
  "USD": {
    "status": "CREATED",
    "message": "Your KYC application has been successfully created. We will review it shortly."
  }
}
KYC application submitted! What happens next?
  1. Status starts as CREATED (immediate)
  2. Transitions to PENDING (within minutes in sandbox)
  3. Final status: ACTIVE or REJECTED (typically automatic in sandbox, 1-3 business days in production)
Sandbox Auto-Approval: In the sandbox environment, KYC applications are typically automatically approved within minutes for testing purposes. However, certain compliance checks (like PEP screening by banking partners) may still block approval even in sandbox. In production, the review process typically takes 1-3 business days.
You can either:
  1. Poll the Retrieve KYC Status endpoint
  2. Listen for KYC.STATUS_UPDATE webhook events

Check KYC Status

Check the current KYC status for the rail using the Retrieve KYC Status endpoint. Request:
curl --request GET \
     --url 'https://sandbox.hifibridge.com/v2/users/32051b2f-0798-55a7-9c42-b08da4192c97/kyc/status?rails=USD' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY'
Response:
{
  "status": "ACTIVE",
  "message": "",
  "reviewResult": {
    "reviewAnswer": "APPROVED",
    "reviewRejectType": "",
    "rejectReasons": [],
    "comment": ""
  },
  "details": {
    "identity": {
      "reviewResult": {
        "reviewAnswer": "APPROVED",
        "reviewRejectType": "",
        "rejectReasons": [],
        "comment": ""
      },
      "details": [
        {
          "id": "e477fa56-3e1e-4dac-abe6-008166749f30",
          "type": "DRIVERS",
          "subType": "FRONT_SIDE",
          "reviewResult": {
            "reviewAnswer": "APPROVED",
            "reviewRejectType": "",
            "rejectReasons": [],
            "comment": ""
          }
        },
        {
          "id": "a2190d1d-61af-416d-8fcf-20673da5eaa0",
          "type": "DRIVERS",
          "subType": "BACK_SIDE",
          "reviewResult": {
            "reviewAnswer": "APPROVED",
            "reviewRejectType": "",
            "rejectReasons": [],
            "comment": ""
          }
        }
      ]
    },
    "questionnaire": {
      "reviewResult": {
        "reviewAnswer": "APPROVED",
        "reviewRejectType": "",
        "rejectReasons": [],
        "comment": ""
      }
    },
    "personalInfo": {
      "reviewResult": {
        "reviewAnswer": "APPROVED",
        "reviewRejectType": "",
        "rejectReasons": [],
        "comment": ""
      }
    }
  }
}
KYC approved! The status is ACTIVE, which means the rail is now unlocked and the user can:
  • Onramp fiat to stablecoins
  • Offramp stablecoins to fiat
Response Fields:
status
string
Overall KYC status for the rail. Possible values: - CREATED - Application submitted, not yet reviewed - PENDING - Being reviewed by compliance team - ACTIVE - Approved, rail is unlocked - REJECTED - Not approved (see rejectReasons for details)
reviewResult
object
High-level review outcome for the entire application.
details
object
Detailed review results broken down by category (identity documents, personal information, questionnaire). Useful for diagnosing issues if rejected.

Next Steps

Now that your user has completed KYC and unlocked the rail, you can: