Collect Payments
What you'll buildAccept a payment from your customer in their local currency. The customer pays via their preferred local method (M-Pesa, PIX, SEPA, GCash, etc.) and the funds settle to your TransFi account.
Use this:If you run a marketplace collecting from buyers, a remittance app collecting from senders, an e-commerce store, or a forex platform receiving from customers.
Before You Start
- Sandbox API credentials and your MID from displai.transfi.com.
- No pre-existing balance needed — collecting doesn't require prefunding.
- Create the payer as a user first (Step 1). KYC is required based on transaction volume — Basic KYC is applied automatically at user creation.
The Flow
- Create the payer as a user → save the
userId - (Optional) Submit KYC if the payer needs identity verification
- Create a
payinorder → get apayUrl - Redirect the payer to the payment page
- Listen for the status update → fulfil the order
Step 1 — Create the payer (sender)
Each payer (sender) is a user in TransFi. Create them once and reuse the userId for all future transactions.
curl --location 'https://sandbox-api.transfi.com/v3/users/individual' \
--header 'Authorization: Basic YOUR_BASE64_CREDENTIALS' \
--header 'mid: YOUR_MID' \
--header 'Content-Type: application/json' \
--data '{
"firstName": "Asha",
"lastName": "Kamau",
"email": "[email protected]",
"phone": "0712345678",
"phoneCode": "+254",
"country": "KE",
"date": "15-06-1990",
"address": {
"street": "14 Moi Avenue",
"city": "Nairobi",
"state": "Nairobi",
"postalCode": "00100"
}
}'// Response
{
"status": "success",
"data": {
"userId": "UX-250930062608488"
}
}Store this userId — you'll use it on every order for this payer.
Step 2 — Create the payin order
Choose whether to use TransFi's hosted payment page (headlessMode not set or false) or display payment details in your own UI (headlessMode: true). The hosted page is faster to ship and handles all payment method UX.
Fiat payin — minimal payload (TransFi-hosted payment page):
curl --location 'https://sandbox-api.transfi.com/v3/orders' \
--header 'Authorization: Basic YOUR_BASE64_CREDENTIALS' \
--header 'mid: YOUR_MID' \
--header 'Content-Type: application/json' \
--data '{
"userId": "UX-250930062608488",
"orderType": "payin",
"purposeCode": "company_expenses",
"partnerId": "your-unique-order-ref-001",
"source": {
"currency": "KES",
"amount": "5000",
"paymentType": "mobile_money",
"paymentCode": "MPESA"
},
"destination": {
"currency": "USDT"
}
}'// Response
{
"status": "success",
"data": {
"flow": "FIAT_PAYIN",
"orderId": "OR-2509291454262384294",
"payUrl": "https://sandbox-pay-widget.transfi.com/pay?paytoken=6c237e7e-..."
}
}
purposeCodeis required on every order.Common values:
company_expenses,personal,invoice_payment.See the Purpose Code reference for the full list.
partnerIdis your unique reference for this order and acts as the idempotency key.Generate one per order, store it before the API call, and retry with the same value if a request times out.
Never reuse across different orders.
Don't know the right
paymentCode?Call List Payment Methods API to get all supported payment codes for a currency. Omitting paymentCode lets the payer choose from all enabled methods on the hosted page for a
paymentType(bank_transfer,local_wallet,card)
Step 3 — Redirect the payer
Send the payer to the payUrl from the response. They complete payment on TransFi's hosted page and are returned to your successRedirectUrl or failureRedirectUrl when done.
Step 4 — Track the order status
Poll for status or listen to webhooks. Fiat payin orders move through these statuses:
| Status | Type | What it means | What to do |
|---|---|---|---|
initiated | Intermediate | Order created, waiting for the payer to complete payment | Show a "payment pending" state |
fund_processing | Intermediate | Payer submitted details; waiting for partner to confirm receipt | Show "processing" |
fund_settled | Terminal ✓ | Payment confirmed and received by TransFi | Fulfil the order — update your DB, release the goods/service |
fund_failed | Terminal ✗ | Payment not received or reversed | Show failure message. Create a new order to retry. |
To check order status at any time:
curl --location 'https://sandbox-api.transfi.com/v3/orders/OR-2509291454262384294' \
--header 'Authorization: Basic YOUR_BASE64_CREDENTIALS' \
--header 'mid: YOUR_MID'
If it failsNever reuse the same
orderIdorpartnerId. Create a brand-new order with a newpartnerId
Test in SandboxCreate the order, open the
payUrl, and complete the simulated payment flow. Or trigger status transitions directly usingPOST /v3/simulation/orderNote: The Simulation Flow only works in Sandbox
Collecting Crypto Payments
To accept a crypto payin (e.g. USDT from the payer's wallet), change the source currency to a crypto symbol. The response returns a walletAddress instead of a payUrl — share this address with the payer for them to send to.
// Crypto payin — source is crypto, destination is fiat
"source": {
"currency": "USDTPOLYGON",
"amount": "100"
},
"destination": {
"currency": "EUR"
}// Response — walletAddress to share with the payer
{
"status": "success",
"data": {
"flow": "CRYPTO_PAYIN",
"orderId": "OR-2509291506567158826",
"walletAddress": "0x63d3CEAE8A65486a1caAb8B42f..."
}
}Crypto payin statuses:
initiated→asset_settled(terminal ✓)