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.iowithapi.celar.io.
How it works
- Create an individual or business customer record
- Send the customer a Terms of Service link and wait for acceptance
- Complete the KYC/KYB compliance flow (upload address proof documents + trigger identity verification)
- Add payment details (bank account and/or wallet address)
- Once
kyc_statusreturnsapproved, 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.
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"
}
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"
}
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
| Field | Required | Description |
|---|---|---|
type | Yes | individual |
country | Yes | ISO 3166-1 alpha-3 country code |
currency | Yes | ISO 4217 currency code |
email | Yes | Customer's email address |
first_name | Yes | Customer's first name |
last_name | Yes | Customer's last name |
dob | Yes | Date of birth (YYYY-MM-DD) |
phone_number | Yes | Customer's phone number in E.164 format (e.g. +254712345678) |
government_id_number | Yes | Government-issued ID number used for compliance checks |
tax_id | No | Customer's tax identification number |
residential_address | Yes | Object: street_line_1, city, region, zip, country |
Business
| Field | Required | Description |
|---|---|---|
type | Yes | business |
country | Yes | ISO 3166-1 alpha-3 country code |
currency | Yes | ISO 4217 currency code |
email | Yes | Business email address |
business_name | Yes | Registered legal name of the business |
incorporation_certificate_number | Yes | Official incorporation certificate number |
business_tax_id | Yes | Business tax identification number |
first_name | Yes | Primary contact's first name |
last_name | Yes | Primary contact's last name |
dob | Yes | Primary contact's date of birth (YYYY-MM-DD) |
phone_number | Yes | Primary contact's phone number in E.164 format (e.g. +254712345678) |
government_id_number | Yes | Primary contact's government ID number |
ownership_percentage | Yes | Primary contact's ownership percentage |
registered_business_address | Yes | Object: street_line_1, city, region, zip, country |
residential_address | Yes | Primary contact's residential address |
website_url | No | Business website URL |
business_registration_number | No | Business registration number (if different from incorporation certificate number) |
beneficiary_owners | No | Array of additional beneficial owners (each with first_name, last_name, dob, email, phone_number, ownership_percentage, address, government_id_number, tax_id) |
Payment details
| Field | Required | Description |
|---|---|---|
customer_id | Yes | The customer to attach payment details to |
bank_name | No* | Name of the customer's bank. Required when providing bank details. |
account_number | No* | Bank account number. Required when providing bank details. |
account_type | No* | checking or savings. Required for US customers. |
wallet_address | No* | Ethereum-compatible wallet address. At least one of wallet_address or bank details (bank_name + account_number) must be provided. |
routing_number | No | Required for US ACH transfers (9-digit routing number) |
bank_address | No | Physical address of the bank branch. Required for US customers. |
bank_code | No | Bank 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.