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.

📘

Recipe

Onboarding 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

StepCallResult
1POST /customersCustomer created, data_requirements list what KYC still needs
2POST /customers/{customer_id}/documents or GET /customers/{customer_id}/kycKYC data submitted
3customer-product-changed webhookProducts activated, the Customer can transact
4POST /customers/{customer_id}/ordersOrder created with a guaranteed quote
5POST /customers/{customer_id}/orders/{order_id}/confirmOrder 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": false until KYC completes.
  • data_requirements: the documents and data Lirium still needs. Each one carries its own status (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.

FieldTypeRequiredDescription
document_typestringYesid_front | id_back | proof_of_address | selfie
file_typestringYesimage/png | image/jpeg | image/gif | application/pdf
filebinaryYesFile 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 demand

Customer Details returns the current products and data_requirements at 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 date

Confirmation 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


Did this page help you?