Fiat Payin
A fiat payin accepts a fiat payment from a customer (via mobile money or bank) and converts it into stablecoins, settling the equivalent amount into a Celar wallet. A rate quote is required before submission.
Examples use the sandbox environment. For production, replace
api.sandbox.celar.iowithapi.celar.io.
How it works
- Fetch a rate from the Rates API: get the
fiatAmountand asignature - Submit a
fiat_payintransfer with the customer's fiat payment details - The customer sends the fiat amount via their mobile money provider
- Celar confirms receipt and converts it to stablecoins
- Stablecoins are settled to the destination Celar wallet
- A webhook fires when the status moves to
settled
Rate quotes are valid for 5 minutes. Submit the transfer before the signature expires.
Prerequisites
- A valid
customer_idwith payment details: see Register a Customer - A rate quote from the Rates API
- A unique
Idempotency-Keyfor the request
Step 1: Get a rate
Before submitting, fetch a rate quote from the Rates API. This returns the fiatAmount and signature you need for the next step.
Step 2: Submit the transfer
curl --request POST \
--url https://api.sandbox.celar.io/api/v1/payments/transfer \
--header 'Authorization: Bearer <your_api_key>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <unique_uuid>' \
--data '{
"operationType": "fiat_payin",
"customer_id": "cr_2ae76bc76f03437d",
"amount": 500,
"signature": "sig_8c23dc5c3140a72b",
"source": {
"currency": "KES",
"description": "Customer deposit via MPESA",
"reference": "REF-23923",
"serviceProvider": "MPESA",
"paymentMethod": "mobile",
"phoneNumber": "+254712345678"
},
"destination": {
"currency": "USDC",
"chain": "base",
"address": "0xabc123..."
}
}'
Response
{
"success": true,
"message": "Payin is pending. Please check webhook"
}
The fiat payin is asynchronous: monitor your webhook or poll the payment status for updates.
US customers
The signature field is not required. Instead, provide source.transfer_type to specify the funding method.
transfer_type | Description |
|---|---|
wire | Bank wire transfer. Returns wire instructions for the customer to follow |
ach_debit | ACH pull from the customer's linked Plaid bank account (requires prior Plaid linkage) |
curl --request POST \
--url https://api.sandbox.celar.io/api/v1/payments/transfer \
--header 'Authorization: Bearer <your_api_key>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <unique_uuid>' \
--data '{
"operationType": "fiat_payin",
"customer_id": "cr_2ae76bc76f03437d",
"amount": 500,
"source": {
"currency": "USD",
"description": "Wire deposit from US customer",
"paymentMethod": "bank",
"transfer_type": "wire"
},
"destination": {
"currency": "USDC",
"chain": "base"
}
}'
Wire response
{
"message": "Follow the details to complete payin",
"bankDetails": { }
}
bankDetails contains the wire instructions the customer uses to send funds.
ACH response
{
"message": "Payin completed successfully"
}
Fiat payin automations
US customers support a standing wire automation for fiat payins. When enabled, Celar automatically converts every incoming wire for that customer into stablecoins without requiring a per-transfer API call.
- Set
source.is_automation: trueon a fiat payin request to activate it source.transfer_typemust bewire- automations are not supported forach_debit- The response returns
bankDetailswith the fixed wire instructions the customer sends funds to - All subsequent wires from that customer are processed automatically
Field reference
| Field | Required | Description |
|---|---|---|
operationType | Yes | fiat_payin |
customer_id | Yes | The customer sending the fiat |
amount | Yes | Fiat amount the customer is paying |
signature | Yes (non-US) | Rate signature from the Rates API |
source.currency | Yes | Fiat currency code: e.g. KES |
source.serviceProvider | Conditional | Required for mobile payins: e.g. MPESA, MTN, AIRTEL |
source.paymentMethod | Yes | mobile for non-US customers |
source.phoneNumber | Conditional | Required for mobile payins (E.164 format) |
source.accountNumber | Conditional | Required for bank payins |
source.transfer_type | Conditional | Required for US customers: wire or ach_debit |
source.is_automation | No | US customers only. Set to true to create a standing wire automation for this customer |
source.description | Yes | Internal description |
source.reference | No | Your own reference ID |
destination.currency | Yes | USDC or USDT |
destination.chain | Yes | base, polygon, arbitrum, or baseSepolia |
destination.address | No | Forward stablecoins to this address after conversion |
See Payment Statuses and Webhooks for more.