Skip to content

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/rails
json
{
  "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
railmpesa, airtel or card
phoneThe payer's phone, for mpesa and airtel
amountMinorOptional: 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 / consignmentIdExactly one: what the escrow is for
funderIdThe buyer funding it
amountMinor, currencyThe amount (currency defaults to USDT)
methodStellar, Celo, Mobile money, Card, USDT, Bank transfer
collectFor Mobile money or Card: { "rail": "mpesa" | "airtel" | "card", "phone"? } to collect it now
referenceFor money already received; not given for Stellar, Celo or collect
releaseOnSettlement, 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.

WhatEndpointBodyRole
Release an escrowPOST /api/v1/escrows/:id/releasenoneFinance
Refund an escrowPOST /api/v1/escrows/:id/refund{ "reason" }Finance
A farmer's early payoutPOST /api/v1/receipts/:id/payout{ "advanceBps", "discountBps", "send": { "rail" } }Finance
The payout's balancePOST /api/v1/payouts/:id/settle{ "send": { "rail" } }Finance
A freight invoicePOST /api/v1/invoices/:id/pay-out{ "rail", "amountMinor"? }Finance, Desk
A driver's advancePOST /api/v1/trips/:id/advances{ "purpose", "method", "amountMinor", "send": { "rail", "phone"? } }Desk, Finance
Issue a driver cardPOST /api/v1/cardholders/:id/cards{ "openingUsdMinor", "vehicleId"? }Desk, Finance
Load a driver cardPOST /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/approve

Finance. 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/transfersEvery transfer, with status, approvals and the provider's reference
GET /api/v1/rails/balancesWhat the exchange holds on Stellar, including XLM for fees
POST /api/v1/rails/pollCheck every rail now instead of at the next tick (Finance)
GET /api/v1/cards/floatThe KES float for driver cards
GET /api/v1/cards/quoteMamlaka's KES quote for an issue or load
GET /api/v1/cards/:id/balanceA card's live balance from Mamlaka

AgriTrade Exchange