Appearance
Money endpoints
How to take and send money through the API. The concepts are on Money on rails; the rules on The rules every rail keeps.
Being released
The money rails described here are built and tested, and are being rolled out. Until a rail is switched on for the exchange, invoices are paid by bank transfer or mobile money and recorded by Finance, as today.
Which rails are open
http
GET /api/v1/railsjson
{
"stellar": { "kind": "testnet", "accounts": { "exchange": "G…", "escrow": "G…" }, "issuers": { "USDC": "G…", "USDT": "G…" }, "currencies": ["USDC", "USDT"], "explorer": "https://stellar.expert/explorer/testnet/tx/" },
"gateway": { "kind": "sandbox", "currencies": { "mpesa": ["KES"], "airtel": ["KES"], "card": ["KES"] } },
"celo": { "kind": "celo", "chainId": 11142220, "contract": "0x…", "treasury": "0x…", "tokens": { "USDC": "0x…", "USDT": "0x…" }, "currencies": ["USDC", "USDT"], "explorer": "…" }
}A rail that is not switched on is null.
Taking money
Pay an invoice
The public invoice (GET /api/v1/invoices/INV-…, no token) carries the instructions for the chains: payTo for Stellar and payToCelo for Celo. The payer follows them from their own wallet; there is nothing to call.
To collect through the gateway (Finance or Desk):
http
POST /api/v1/invoices/INV-0042/collect
{ "rail": "mpesa", "phone": "254712345678" }| Field | |
|---|---|
rail | mpesa, airtel or card |
phone | The payer's phone, for mpesa and airtel |
amountMinor | Optional: less than the outstanding amount, for a part payment |
The answer is the in transfer, Awaiting the payer; for card it also carries the hosted card page link to send them. The invoice payment is written when Mamlaka confirms.
To record money already received by other means (Finance or Desk):
http
POST /api/v1/invoices/INV-0042/payments
{ "amountMinor": 50000_00, "method": "Bank transfer", "reference": "FT2611020042", "at": "2026-11-02" }Fund an escrow
http
POST /api/v1/escrows
{ "funderId": "BYR-006", "orderId": "ORD-0005", "amountMinor": 1000_00, "currency": "USDT", "method": "Stellar" }| Field | |
|---|---|
orderId / receiptId / consignmentId | Exactly one: what the escrow is for |
funderId | The buyer funding it |
amountMinor, currency | The amount (currency defaults to USDT) |
method | Stellar, Celo, Mobile money, Card, USDT, Bank transfer |
collect | For Mobile money or Card: { "rail": "mpesa" | "airtel" | "card", "phone"? } to collect it now |
reference | For money already received; not given for Stellar, Celo or collect |
releaseOn | Settlement, Arrival confirmed or Manual |
On Stellar and Celo the escrow is created Awaiting funds and the answer carries payTo, the instructions to fund it.
Sending money
Each of these answers 202 with a transfer Awaiting two approvals. Nothing is written as paid until it lands.
| What | Endpoint | Body | Role |
|---|---|---|---|
| Release an escrow | POST /api/v1/escrows/:id/release | none | Finance |
| Refund an escrow | POST /api/v1/escrows/:id/refund | { "reason" } | Finance |
| A farmer's early payout | POST /api/v1/receipts/:id/payout | { "advanceBps", "discountBps", "send": { "rail" } } | Finance |
| The payout's balance | POST /api/v1/payouts/:id/settle | { "send": { "rail" } } | Finance |
| A freight invoice | POST /api/v1/invoices/:id/pay-out | { "rail", "amountMinor"? } | Finance, Desk |
| A driver's advance | POST /api/v1/trips/:id/advances | { "purpose", "method", "amountMinor", "send": { "rail", "phone"? } } | Desk, Finance |
| Issue a driver card | POST /api/v1/cardholders/:id/cards | { "openingUsdMinor", "vehicleId"? } | Desk, Finance |
| Load a driver card | POST /api/v1/cards/:id/load | { "tripId", "usdMinor" } | Desk, Finance |
send.rail is stellar, mpesa or airtel. Without send, the payout and advance endpoints record money already paid, with a method and reference. Card issues and loads also return Mamlaka's quote in shillings.
json
{
"transfer": {
"id": "TRF-0042", "rail": "mpesa", "direction": "out", "currency": "KES", "amountMinor": 5000_00,
"status": "Awaiting", "approvalsNeeded": 2, "approvals": [], "counterparty": "256772410233"
}
}Approving and cancelling
http
POST /api/v1/transfers/TRF-0042/approveFinance. The first approval returns the transfer with one approval; the second, from a different user, sends it and returns it Pending or Confirmed.
http
POST /api/v1/transfers/TRF-0042/cancel
{ "reason": "Wrong beneficiary" }Finance. Only a payment out not yet sent; it becomes Failed with the reason.
Reading
| Endpoint | |
|---|---|
GET /api/v1/transfers | Every transfer, with status, approvals and the provider's reference |
GET /api/v1/rails/balances | What the exchange holds on Stellar, including XLM for fees |
POST /api/v1/rails/poll | Check every rail now instead of at the next tick (Finance) |
GET /api/v1/cards/float | The KES float for driver cards |
GET /api/v1/cards/quote | Mamlaka's KES quote for an issue or load |
GET /api/v1/cards/:id/balance | A card's live balance from Mamlaka |