Merchant API
Merchants integrate with Trans Flow only. Trans Flow handles routing to the payment networks behind a single signed API, so adding a new network never changes the contract below.
https://www.transflowsolution.comGet your API key
Open the Developers tab in your dashboard and create a key. Live keys start with tf_live_, test keys with tf_test_. The key is shown once — store it server-side only.
Charge a customer
One POST creates the payment and returns the prompt the customer approves on their phone.
curl -X POST https://www.transflowsolution.com/api/public/transflow/v1/payments \
-H "X-TransFlow-Key: tf_live_xxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: order-8125" \
-H "Content-Type: application/json" \
-d '{
"payment_method": "mobile_money",
"direction": "collection",
"channel": "MTN",
"amount": 25.00,
"reference": "order-8125",
"walletNumber": "0244000000"
}'Show the prompt
If the response status is customer_action_required, render the ussdCode behind a Dial now button so the customer can approve instantly.
<a href="tel:*170%23">Dial now</a>
Confirm the result
Point your webhook URL at your server and verify before fulfilling, or poll the payment by reference.
curl -H "X-TransFlow-Key: tf_live_xxxxxxxxxxxxxxxx" \ https://www.transflowsolution.com/api/public/transflow/v1/payments/order-8125
X-TransFlow-Key: tf_live_xxxxxxxxxxxxxxxx Idempotency-Key: order-8125 Content-Type: application/json
Every payment declares a payment_method. Today only mobile_money is active; card and bank_transfer are reserved and return a clear “coming soon” error, so your integration will not change when they go live.
{
"payment_method": "mobile_money",
"direction": "collection",
"channel": "MTN",
"amount": 25.00,
"reference": "order-8125",
"walletNumber": "0244000000",
"customerName": "Ama Mensah",
"description": "Order 8125"
}The response carries the normalised status. When the customer must approve a prompt you get customer_action_required plus a ussdCode you can render behind a “Dial now” button.
{
"data": {
"id": "0f2c...",
"reference": "order-8125",
"status": "customer_action_required",
"ussdCode": "*170#",
"promptNickname": "TRANSFLOW",
"expiresAt": "2026-08-04T04:12:00.000Z"
}
}{
"direction": "payout",
"channel": "BANK",
"amount": 500.00,
"reference": "settlement-114",
"bankCode": "GCB",
"bankAccountNumber": "1234567890",
"accountName": "Ama Mensah"
}Send the amount you are selling for. Trans Flow adds the convenience fee, charges the customer the total, and settles your order amount. Every payment response includes the breakdown, so your checkout can show it before the customer approves the prompt.
{
"order_amount": 100.00,
"customer_fee_percentage": 3,
"customer_fee_amount": 3.00,
"total_customer_paid": 103.00,
"currency": "GHS"
}Verification asks the network for the authoritative state and reconciles the stored record. The engine also polls in the background with backoff, so a transaction always reaches a final state even if you never call this.
curl -H "X-TransFlow-Key: tf_live_..." \ https://your-app.lovable.app/api/public/transflow/v1/payments/order-8125
pending— accepted, not yet sent to a networkcustomer_action_required— waiting on the prompt or USSD dialprocessing— the network is working on itsuccessful— funds movedfailed— rejected, see failureCodeexpired— the customer never approved in timecancelled— cancelled before completion
{ "error": { "code": "idempotency_conflict",
"message": "This idempotency key was already used with a different payload" } }