Skip to main content

Register a Customer

Every payment on Celar must reference a customer_id. This recipe walks through the full customer registration flow: create the record, complete KYC, and attach payment details.

Customers are the core identity object in Celar. They are used for attribution, compliance, reconciliation, and payment routing. Depending on your integration, a customer can exist as a record only or as a record linked to a wallet.

Examples use the sandbox environment. For production, replace api.sandbox.celar.io with api.celar.io.

How it works

  1. Create an individual or business customer record
  2. Send the customer a Terms of Service link and wait for acceptance
  3. Complete the KYC/KYB compliance flow (upload address proof documents + trigger identity verification)
  4. Add payment details (bank account and/or wallet address)
  5. Once kyc_status returns approved, the customer is cleared for transactions

Step 1: Create the customer

Individual

curl --request POST \
--url https://api.sandbox.celar.io/api/v1/customers \
--header 'Authorization: Bearer <your_api_key>' \
--header 'Content-Type: application/json' \
--data '{
"country": "KEN",
"currency": "KES",
"email": "john.doe@example.com",
"type": "individual",
"tax_id": "TAX12345",
"first_name": "John",
"last_name": "Doe",
"dob": "1995-06-15",
"phone_number": "+254712345678",
"government_id_number": "12345678",
"residential_address": {
"street_line_1": "123 Main Street",
"region": "Nairobi County",
"city": "Nairobi",
"zip": "00100",
"country": "KEN"
}
}'

Business

curl --request POST \
--url https://api.sandbox.celar.io/api/v1/customers \
--header 'Authorization: Bearer <your_api_key>' \
--header 'Content-Type: application/json' \
--data '{
"country": "KEN",
"currency": "KES",
"email": "legal@novaindustries.co.ke",
"type": "business",
"tax_id": "TAX889922",
"business_name": "Nova Industries Limited",
"first_name": "Samuel",
"last_name": "Kariuki",
"dob": "1982-09-14",
"phone_number": "+254722000111",
"government_id_number": "55667788",
"business_tax_id": "BUS667788",
"incorporation_certificate_number": "C.2023/990011",
"ownership_percentage": "70",
"registered_business_address": {
"street_line_1": "45 Industrial Area Road",
"region": "Nairobi County",
"city": "Nairobi",
"zip": "00500",
"country": "KEN"
},
"residential_address": {
"street_line_1": "10 Kilimani Estate",
"region": "Nairobi County",
"city": "Nairobi",
"zip": "00100",
"country": "KEN"
}
}'

Response

{
"message": "1 customer(s) created successfully",
"customers": [
{
"id": "cr_53c79dae85d2cee2",
"email": "john.doe@example.com",
"type": "individual",
"kyc_status": "pending",
"is_active": true
}
]
}

Save the id — this is your customer_id for all subsequent requests.

info

Document fields (incorporation_certificate, proof_of_residential_address, proof_of_business_address) are always null on creation. Complete the compliance flow in Step 2 before using the customer for transactions.

Step 2: TOS attestation

Before KYC can be completed, the customer must accept Celar's Terms of Service. Send them a consent request — Celar generates a signed link valid for 24 hours.

curl --request POST \
--url https://api.sandbox.celar.io/api/v1/customers/cr_53c79dae85d2cee2/celar-consent \
--header 'Authorization: Bearer <your_api_key>'

Response (pending acceptance)

{
"url": "https://celar.io/accept-terms-of-service?jwt=<signed_token>",
"message": "Click "
}

Send the url to your customer. When they visit it and accept, Celar records tos_accepted_at automatically — no further API call is needed on your side.

If the customer has already accepted, the endpoint returns immediately:

{
"accepted_at": "2025-06-01T10:23:00Z",
"message": "Customer has already accepted the terms of service"
}
note

The consent link expires after 24 hours. If the customer misses it, call this endpoint again to generate a fresh link.

Step 3: Complete KYC / KYB

Before the customer can transact, they must complete the compliance flow.

For individual customers:

  • Upload proof_of_residential_address
  • Trigger Didit verification via POST /customers/compliance
  • The customer's identity-document and face/liveness checks happen inside Didit

For business customers:

  • Upload proof_of_residential_address
  • Upload incorporation_certificate
  • Upload proof_of_business_address
  • Trigger Didit verification for the primary contact via POST /customers/compliance

Then check kyc_status until it returns approved.

See Compliance Workflows for the exact endpoints and request formats.

Step 4: Add payment details

Once KYC is underway, attach banking and wallet information. This is required before the customer can send or receive funds.

curl --request PATCH \
--url https://api.sandbox.celar.io/api/v1/customers/payment-details \
--header 'Authorization: Bearer <your_api_key>' \
--header 'Content-Type: application/json' \
--data '{
"customer_id": "cr_53c79dae85d2cee2",
"bank_name": "Equity Bank",
"account_number": "0011223344",
"wallet_address": "0x5D3a536E4D6DbD6114cc1Ead35777bAB948E3643"
}'

For US customers with ACH:

curl --request PATCH \
--url https://api.sandbox.celar.io/api/v1/customers/payment-details \
--header 'Authorization: Bearer <your_api_key>' \
--header 'Content-Type: application/json' \
--data '{
"customer_id": "cr_53c79dae85d2cee2",
"bank_name": "Chase",
"account_number": "000123456789",
"account_type": "checking",
"wallet_address": "0x5D3a536E4D6DbD6114cc1Ead35777bAB948E3643",
"routing_number": "021000021",
"bank_address": {
"street_line_1": "270 Park Avenue",
"city": "New York",
"region": "NY",
"zip": "10017",
"country": "USA"
}
}'

Response

{
"message": "Payment details added successfully"
}
note

This endpoint handles both creation and updates. If payment details already exist, the record is replaced and the response message changes to "Payment details updated successfully". A customer can only have one active set of payment details at a time.

If a new wallet_address is provided that differs from the existing one, the customer's kyc_status is automatically set to pending_update and a compliance re-check is triggered.

Field reference

Individual

FieldRequiredDescription
typeYesindividual
countryYesISO 3166-1 alpha-3 country code
currencyYesISO 4217 currency code
emailYesCustomer's email address
first_nameYesCustomer's first name
last_nameYesCustomer's last name
dobYesDate of birth (YYYY-MM-DD)
phone_numberYesCustomer's phone number in E.164 format (e.g. +254712345678)
government_id_numberYesGovernment-issued ID number used for compliance checks
tax_idNoCustomer's tax identification number
residential_addressYesObject: street_line_1, city, region, zip, country

Business

FieldRequiredDescription
typeYesbusiness
countryYesISO 3166-1 alpha-3 country code
currencyYesISO 4217 currency code
emailYesBusiness email address
business_nameYesRegistered legal name of the business
incorporation_certificate_numberYesOfficial incorporation certificate number
business_tax_idYesBusiness tax identification number
first_nameYesPrimary contact's first name
last_nameYesPrimary contact's last name
dobYesPrimary contact's date of birth (YYYY-MM-DD)
phone_numberYesPrimary contact's phone number in E.164 format (e.g. +254712345678)
government_id_numberYesPrimary contact's government ID number
ownership_percentageYesPrimary contact's ownership percentage
registered_business_addressYesObject: street_line_1, city, region, zip, country
residential_addressYesPrimary contact's residential address
website_urlNoBusiness website URL
business_registration_numberNoBusiness registration number (if different from incorporation certificate number)
beneficiary_ownersNoArray of additional beneficial owners (each with first_name, last_name, dob, email, phone_number, ownership_percentage, address, government_id_number, tax_id)

Payment details

FieldRequiredDescription
customer_idYesThe customer to attach payment details to
bank_nameNo*Name of the customer's bank. Required when providing bank details.
account_numberNo*Bank account number. Required when providing bank details.
account_typeNo*checking or savings. Required for US customers.
wallet_addressNo*Ethereum-compatible wallet address. At least one of wallet_address or bank details (bank_name + account_number) must be provided.
routing_numberNoRequired for US ACH transfers (9-digit routing number)
bank_addressNoPhysical address of the bank branch. Required for US customers.
bank_codeNoBank code (SWIFT/BIC or local code, depending on region)

Once the customer is ready, continue with Create a Wallet if you need a customer wallet, or move straight to a payment recipe.