Customer Onboarding
Create a Customer, complete their KYC, and place their first order
This guide walks you through onboarding an end user end to end: you create the Customer, their KYC data is collected and reviewed, their products are activated, and they place their first order.
RecipeOnboarding Flow shows this same flow as runnable code.
Before you start, make sure you can authenticate. See Authentication Setup and JWT Generation.
Flow at a Glance
| Step | Call | Result |
|---|---|---|
| 1 | POST /customers | Customer created, data_requirements list what KYC still needs |
| 2 | POST /customers/{customer_id}/documents or GET /customers/{customer_id}/kyc | KYC data submitted |
| 3 | customer-product-changed webhook | Products activated, the Customer can transact |
| 4 | POST /customers/{customer_id}/orders | Order created with a guaranteed quote |
| 5 | POST /customers/{customer_id}/orders/{order_id}/confirm | Order completed, balance credited |
1. Create the Customer
Register your end user with Create Customer. Only reference_id, type and contact.email are mandatory, but the more profile data you send, the fewer requirements KYC will ask for later.
{
"reference_id": "unique-individual-id",
"type": "individual",
"profile": {
"first_name": "Juan",
"last_name": "Pérez",
"date_of_birth": "1974-08-09",
"national_id_country": "AR",
"national_id_type": "national_id",
"national_id": "24053066",
"citizenship": "AR",
"address_line1": "1234 Av. Corrientes",
"city": "Buenos Aires",
"state": "CABA",
"country": "AR",
"zip_code": "1430",
"tax_country": "AR",
"tax_id": "20-24053066-9"
},
"contact": {
"email": "[email protected]",
"cellphone": "+5491156668452"
}
}The response returns Lirium's id for the Customer — store it, every subsequent call uses it as {customer_id}. It also returns:
products: the products enabled for your domain, all with"active": falseuntil KYC completes.data_requirements: the documents and data Lirium still needs. Each one carries its ownstatus(pending_submission,pending_review,approved,rejected).
{
"id": "585fbdc4f9f311ea96a90242ac140006",
"created_at": "2020-09-01T11:28:59+00:00",
"reference_id": "unique-individual-id",
"state": "active",
"products": [
{ "code": "crypto_buy_sell", "active": false, "enabled": false }
],
"data_requirements": [
{
"id": "document_id_front",
"type": "document",
"document_type": "id_front",
"status": "pending_submission",
"created": "2020-09-01T11:28:59+00:00",
"last_updated_at": "2020-09-01T11:28:59+00:00"
}
]
}reference_id is your own identifier for the Customer. It must be unique within your domain, accepts up to 191 characters and is case insensitive. See Customers Reference for the full field list.
2. Collect the KYC Data
There are two ways to satisfy the data_requirements, depending on how your integration is configured.
Option A — You collect the documents
Send each file with Upload KYC Document. This endpoint takes multipart/form-data, not JSON: the metadata fields plus the bytes in the file key.
| Field | Type | Required | Description |
|---|---|---|---|
document_type | string | Yes | id_front | id_back | proof_of_address | selfie |
file_type | string | Yes | image/png | image/jpeg | image/gif | application/pdf |
file | binary | Yes | File content bytes. |
Make one call per document type. Each response returns the whole Customer, so you can read the updated data_requirements and see which requirements are still pending_submission.
Option B — Lirium collects the documents
When Lirium performs the KYC, call Get KYC Link and redirect the Customer to the returned collection_url. The response also lists what is still pending and whether Lirium emailed the link to the Customer on that call.
{
"collection_url": "https://kyc.example.com/collect/9f2c1a7b4e5d",
"data_requirements": [
{
"id": "document_id_front",
"type": "document",
"document_type": "id_front",
"status": "pending_submission",
"created": "2020-09-01T11:28:59+00:00",
"last_updated_at": "2020-09-01T11:28:59+00:00"
}
],
"email_sent": false
}A null collection_url with an empty data_requirements array means Lirium has nothing pending for that Customer.
3. Wait for the Products to Be Activated
A Customer can only transact once the product behind the operation — crypto_buy_sell for a buy — is both active and enabled. Activation happens after the KYC review, so it is asynchronous.
Subscribe to the Customer product changed webhook and act on it, instead of polling:
{
"id": "674670ef4c444efcac88ebae4184e4d4",
"action": "customer-product-changed",
"products": ["crypto_buy_sell"],
"customer": {
"id": "585fbdc4f9f311ea96a90242ac140006",
"state": "active",
"products": [
{ "code": "crypto_buy_sell", "active": true, "enabled": true }
]
}
}Also subscribe to Customer requirement rejected: a rejected document must be resubmitted, and the payload carries the rejection_reason you need to show the Customer. See Webhooks Reference to register your endpoints.
Checking the state on demandCustomer Details returns the current
productsanddata_requirementsat any time. Use it to reconcile state — for example when a webhook delivery failed — rather than as a polling loop.
4. Place the First Order
With the product active, create the order with Create Order. A buy order takes the settlement amount in fiat and returns how much crypto the Customer receives.
{
"reference_id": "order-onboarding-001",
"operation": "buy",
"asset": {
"currency": "BTC"
},
"buy": {
"settlement": {
"currency": "ARS",
"amount": "10000.00"
}
}
}{
"id": "3d691e6e71b4487198dca66e1bebe5f0",
"operation": "buy",
"state": "pending",
"customer_id": "585fbdc4f9f311ea96a90242ac140006",
"created_at": "2020-09-01T21:28:29+00:00",
"last_updated_at": "2020-09-01T21:28:29+00:00",
"asset": {
"currency": "BTC",
"amount": "0.00021345",
"operation": "credit"
},
"buy": {
"requires_confirmation_code": true,
"expires_at": "2020-09-01T21:29:15+00:00",
"settlement": {
"currency": "ARS",
"amount": "10000.00",
"operation": "debit"
}
}
}The order stays in pending until you confirm it, and the quote is guaranteed only until expires_at. If it expires, the order becomes aborted and no balance is affected — create a new one. All amounts are strings.
5. Confirm the Order
Show the Customer the final conditions, including your own fees, and confirm with Confirm Order.
If the order returned "requires_confirmation_code": true, Lirium sent a security code to the Customer's email address on file — pass it as confirmation_code. Otherwise confirm with an empty body.
{
"confirmation_code": "123456",
"customer": {
"currency": "ARS",
"amount": "10450.00"
}
}The optional customer object records the amount the Customer actually accepted in their local currency, after your fees. On success the order moves to completed and the asset is credited to the Customer's balance.
{
"id": "3d691e6e71b4487198dca66e1bebe5f0",
"operation": "buy",
"state": "completed",
"submitted_at": "2020-09-01T21:28:40+00:00",
"asset": {
"currency": "BTC",
"amount": "0.00021345",
"operation": "credit"
}
}
Keep the email address up to dateConfirmation codes are sent to
contact.email. Use Update Customer whenever the Customer changes it, or they will not be able to confirm orders.
Next Steps
- Orders — order operations, states and fields
- Customers Reference — Customer properties, states and data requirements
- Fiat Instructions — fund the Customer with a local fiat rail
- Error Codes — handle failures
Updated 6 days ago
