Onboarding Customers

To onboarding a customer, follow these steps:

  1. Create a Customer
  2. Add Associated Persons
  3. Add Associated Entities
  4. Upload documents
  5. Submit onboarding
  6. Monitor Onboarding Status

Note: customer onboarding functionality is currently unavailable for U.S. residents.

📘

Onboard using KYB link

Instead of integrating the Customer API directly to onboard and verify (KYC/KYB) customer, you can generate onboarding Links for a faster setup. See Guide here

1. Create a Customer

If withLivenessCheck=FALSE, then:

  • On step 2 : identityDocumentFront must be provided
  • On step 4 : directorsLivenessCheck and shareHoldersLivenessCheck must be provided.

See API Reference

curl --request POST \
     --url https://api.sandbox.keyrails.com/api/v1/customers \
     --header 'Authorization: Bearer {{AccessToken}}' \
     --header 'accept: application/json' \
     --header 'content-type: application/*+json' \
     --data '
{
  "businessLegalName": "string",
  "businessTradeName": "string",
  "taxIdentificationNumber": "string",
  "website": "string",
  "incorporationDate": "1999-03-21",
  "companyRegistrationNumber": "string",
  "businessIndustries": [
    "AccountFunding"
  ],
  "businessModel": "string",
  "customerJurisdictions": [
    "NG", "GB"
  ],
  "regulatedEntity": "string",
  "notRegulatedReason": "string",
  "sourceOfFunds": "string",
  "accountPurpose": "string",
  "email": "string",
  "transactionOriginCountries": [
    "GB"
  ],
  "transactionDestinationCountries": [
    "GB", "NG"
  ],
  "companySourceOfWealthExplanation": "string",
  "companySourceOfWealthEvidence": "Base64String",
  "shareholdersSourceOfWealthExplanation": "string",
  "shareholdersSourceOfWealthEvidence": "Base64String",
  "fundingSourceEvidence": "Base64String",
  "fundingSourceExplanation": "string",
	"countryOfIncorporation": "GA",
  "registeredAddress": {
    "street1": "string",
    "city": "string",
    "country": "CA"
  },
  "operationalAddress": {
    "street1": "string",
    "city": "string",
    "country": "CA"
  },
  "contactPerson": {
    "firstName": "string",
    "lastName": "string",
    "phoneNumber": "+44791234560",
    "email": "string"
  },
  "businessIndustryType": "CorporateOrMerchant",
  "withLivenessCheck": true,
  "termsOfServiceAcceptance": {
    "date": "2025-07-28T20:00:44.191Z",
    "ipAddress": "201.221.240.218"
  },
  "customerBaseBreakdown": "Retail",
  "isBusinessRegulated": true,
  "compliance": {
    "hasFinancialCrimeHistoryLast5Years": false,
    "isNegativeNewsAndSanctionsScreeningPerformed": false,
    "isTransactionMonitoringOrBlockchainAnalyticsPerformed": true,
    "isKYCPerformed": true,
    "financialCrimeProceedingsDescription": "string",
    "negativeNewsAndSanctionsVendor": "string",
    "transactionMonitoringOrBlockchainAnalyticsVendor": "string",
    "kycVendor": "string"
  },
  "transactionBreakdown": {
    "stablecoinTxCountMonthly": "Range1To10",
    "incomingStablecoinAvgUsdValue": "Usd15kTo50k",
    "outgoingStablecoinTxCountMonthly": "Range1To10",
    "outgoingStablecoinAvgUsdValue": "Usd15kTo50k",
    "incomingAchTxCountMonthly": "Range1To10",
    "incomingAchAvgUsdValue": "Usd15kTo50k",
    "outgoingAchTxCountMonthly": "Range1To10",
    "outgoingAchAvgUsdValue": "Usd15kTo50k",
    "incomingDomesticWireTxCountMonthly": "Range1To10",
    "incomingDomesticWireAvgUsdValue": "Usd15kTo50k",
    "outgoingDomesticWireTxCountMonthly": "Range1To10",
    "outgoingDomesticWireAvgUsdValue": "Usd15kTo50k",
    "incomingInternationalWireTxCountMonthly": "Range1To10",
    "incomingInternationalWireAvgUsdValue": "Usd15kTo50k",
    "outgoingInternationalWireTxCountMonthly": "Range1To10",
    "outgoingInternationalWireAvgUsdValue": "Usd15kTo50k",
    "estimatedMonthlyVolumeUsd": "Usd500kTo1m",
    "transactionTypes": ["StablecoinTransactions"],
    "preferredSettlementCurrencies": ["USD"]
  }
}
'

Response

{
  "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

2. Add Associated Persons

If withLivenessCheck=FALSE when creating a customer in step 1, then identityDocumentFront must be provided.

See API Reference

curl --request POST \
     --url https://api.sandbox.keyrails.com/api/v1/customers/{customerId}/associated-persons \
     --header 'Authorization: Bearer {{AccessToken}}' \
     --header 'accept: application/json' \
     --header 'content-type: application/*+json' \
     --data '
{
  "firstName": "string",
  "lastName": "string",
  "email": "string",
  "dateOfBirth": "1988-10-28",
  "shareHolderPercentage": 25,
  "address": {
    "street1": "string",
    "city": "string",
    "state": "string",
    "country": "string"
  },
  "identity": {
    "type": "Passport",
    "countryCode": "JP",
    "identityNumber": "string",
    "identityDocumentFront": "data:image/pdf;base64,abdcxxxx",
    "identityDocumentBack": "data:image/pdf;base64,abdcxxxx"
  }
}
'

Response

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "verificationUrl": "string" // when withVerification=TRUE
}

3. Add Associated Entities

See API Reference

curl --request POST \
     --url https://api.sandbox.keyrails.com/api/v1/customers/{customerId}/associated-entities \
     --header 'Authorization: Bearer {{AccessToken}}' \
     --header 'accept: application/json' \
     --header 'content-type: application/*+json' \
     --data '
{
  "entityLegalName": "string",
  "shareHolderPercentage": 25,
  "businessTradeName": "string",
  "incorporationNumber": "string",
  "relationshipEstablishedAt": "1988-10-28",
  "countryOfRegistration": "AL",
  "registeredAddress": {
    "street1": "string",
    "city": "string",
    "state": "string",
    "country": "CA"
  }
}
'

Response

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

4. Upload documents

  • Required file types: organizationChart, shareholdersProofOfAddress, directorsProofOfAddress, ownershipChart, shareholdersRegistry,directorsRegistry, companyProofOfAddress, businessRegistrationDocument, articlesOfAssociationOrMemorandum,
  • If withLivenessCheck=FALSE when creating a customer in step 1, then both directorsLivenessCheck and shareHoldersLivenessCheck must be provided.

See API Reference

curl --request POST \
     --url https://api.sandbox.keyrails.com/api/v1/customers/{customerId}/documents \
     --header 'Authorization: Bearer {{AccessToken}}' \
     --header 'accept: application/json' \
     --header 'content-type: application/*+json' \
     --data '
{
  "files": [
     // ---------- REQUIRED FILES ----------
        {
            "fileType": "organizationChart",
            "fileName": "OrganizationChart.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "shareholdersProofOfAddress",
            "fileName": "ShareholdersProofOfAddress.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "directorsProofOfAddress",
            "fileName": "DirectorsProofOfAddress.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "ownershipChart",
            "fileName": "OwnershipChart.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "shareholdersRegistry",
            "fileName": "ShareholdersRegistry.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "directorsRegistry",
            "fileName": "DirectorsRegistry.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "companyProofOfAddress",
            "fileName": "CompanyProofOfAddress.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "businessRegistrationDocument",
            "fileName": "BusinessRegistrationDocument.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "articlesOfAssociationOrMemorandum",
            "fileName": "ArticlesOfAssociationOrMemorandum.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        // ---------- OPTIONAL FILES ----------
        {
            "fileType": "other",
            "fileName": "Other.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "parentCompanyBusinessRegistrationDocument",
            "fileName": "ParentCompanyBusinessRegistrationDocument.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "parentCompanyShareholdersRegistry",
            "fileName": "ParentCompanyShareholdersRegistry.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "parentCompanyDirectorsRegistry",
            "fileName": "ParentCompanyDirectorsRegistry.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "parentCompanyShareholdersProofOfAddress",
            "fileName": "ParentCompanyShareholdersProofOfAddress.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "parentCompanyDirectorsProofOfAddress",
            "fileName": "ParentCompanyDirectorsProofOfAddress.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "parentCompanyShareholdersId",
            "fileName": "ParentCompanyShareholdersId.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "parentCompanyDirectorId",
            "fileName": "ParentCompanyDirectorId.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "complianceOfficerCV",
            "fileName": "ComplianceOfficerCV.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "independentAmlAudit",
            "fileName": "IndependentAmlAudit.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "amlPolicy",
            "fileName": "AmlPolicy.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        },
        {
            "fileType": "regulatoryLicenses",
            "fileName": "RegulatoryLicenses.pdf",
            "fileBlob": "data:image/pdf;base64,abdcxxxx"
        }
  ]
}
'

5. Complete and submit onboarding

Finalise and submit the full customer onboarding package for review.

See API Reference

curl --request POST \
     --url https://api.sandbox.keyrails.com/api/v1/customers/{customerId}/submit \
     --header 'Authorization: Bearer {{AccessToken}}' \
     --header 'accept: application/json'

👍

Update customer status

Note you can update the customer status using the status simulation endpoint. See API Reference

Monitor Onboarding Status

See API Reference

curl --request GET \
     --url https://api.sandbox.keyrails.com/api/v1/customers/{customerId} \
     --header 'Authorization: Bearer {{AccessToken}}' \
     --header 'accept: application/json'

Response:

{
  "id": "string",
  "type": "string",
  "status": "string",
  "businessLegalName": "string",
  "businessTradeName": "string",
  "taxIdentificationNumber": "string",
  "website": "string",
  "incorporationDate": "string",
  "countryOfIncorporation": "string",
  "companyRegistrationNumber": "string",
  "registeredAddress": {
    "street1": "string",
    "street2": "string",
    "postalCode": "string",
    "city": "string",
    "state": "string",
    "country": "string"
  },
  "businessModel": "string",
  "termsOfServiceAcceptance": {
    "date": "string",
    "ipAddress": "string"
  },
  "email": "string",
  "associated-entities": [
    {
      "id": "string",
      "entityLegalName": "string",
      "countryOfRegistration": "string",
      "shareHolderPercentage": 0,
      "registeredAddress": {
        "street1": "string",
        "city": "string",
        "state": "string",
        "country": "string"
      },
      "businessTradeName": "string",
      "incorporationNumber": "string",
      "relationshipEstablishedAt": "string"
    }
  ],
  "associated-persons": [
    {
      "firstName": "string",
      "id": "string",
      "middleName": "string",
      "lastName": "string",
      "email": "string",
      "dateOfBirth": "string",
      "shareHolderPercentage": 0,
      "phone": "string",
      "verificationUrl": "string",
      "address": {
        "street1": "string",
        "city": "string",
        "state": "string",
        "country": "string"
      }
    }
  ]
}

Webhooks Examples

Before proceeding, ensure that your webhook configuration is set up. Refer to the setup guide for detailed instructions.

Webhook types: - Identity

Customer approved

{
  "tenantId": "64790ea8-f9b1-4b52-aff6-f6177bb3fcee",
  "action": "Update",
  "id": "cfc05dcb-5983-413b-8d8b-f8ef69a14787",
  "resourceId": "d8d01119-4b78-41a6-b868-0849b9ecf2ff",
  "resourceType": "Identity",
  "createdAtUtc": "0001-01-01T00:00:00",
  "changes": {
    "complianceStatus": "Approved"
  }
}

Customer rejected

{
  "tenantId": "47dce736-7fe1-42f9-a317-2676733823fe",
  "action": "Update",
  "id": "fa85e3f4-99cb-46be-bbd3-4faad0bf565d",
  "resourceId": "51777f07-8b43-468f-8808-c7cb1405f254",
  "resourceType": "Identity",
  "createdAtUtc": "0001-01-01T00:00:00",
  "changes": {
    "complianceStatus": "Rejected",
    "rejectionReasons": [
      "Failed to verify proof of address",
      "Poor quality of the document"
    ]
  }
}

What’s Next