Onboarding Customers
To onboarding a customer, follow these steps:
- Create a Customer
- Add Associated Persons
- Add Associated Entities
- Upload documents
- Submit onboarding
- Monitor Onboarding Status
Note: customer onboarding functionality is currently unavailable for U.S. residents.
Onboard using KYB linkInstead 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
andshareHoldersLivenessCheck
must be provided.
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.
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
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 bothdirectorsLivenessCheck
andshareHoldersLivenessCheck
must be provided.
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.
curl --request POST \
--url https://api.sandbox.keyrails.com/api/v1/customers/{customerId}/submit \
--header 'Authorization: Bearer {{AccessToken}}' \
--header 'accept: application/json'
Update customer statusNote you can update the customer status using the status simulation endpoint. See API Reference
Monitor Onboarding Status
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"
]
}
}
Updated 23 days ago