Partner API

Create a buy order (KES in, USDT out)

Consumes a buy quote and debits the KES directly from your own VA balance — there is nothing to send and no payment instructions to read. Delivery is asynchronous: nothing is sent until the debit is confirmed and the order reaches a terminal state. Register a webhook endpoint rather than assuming a create means the trade is done. Retry-safe: creating twice with the same partnerReference returns the original order rather than a second one.

post/v1/orders/buy

Request

  • Base URL
    https://sandbox.onlink.africa
  • Auth
    API key in header X-OnLink-Key

Request body

quoteIdstring required

A quote id from POST /v1/quotes with side=buy. Single-use, and the amounts are taken from it — they are not restated here.

partnerReferencestring required

Your own reconciliation handle. Unique per partner, and RETRY-SAFE: creating twice with the same reference returns the original order rather than a second one.

expectedUsdtAmountstring

Optional. If supplied it must equal the quote’s usdtAmount exactly, or the order is refused (409). This catches a bug on your side where one number is displayed and a different one is ordered.

Example request

{
  "expectedUsdtAmount": "10.000000"
}

Response

Order created; your KES debit has been attempted and is awaiting the bank’s confirmation.

orderIdstring uuid required

The order id. Use it for GET /v1/orders/{id}.

status'awaiting_payment' | 'awaiting_usdt' | 'payment_matched' | 'usdt_received' | 'funds_reserved' | 'awaiting_approval' | 'rejected' | 'sending' | 'paying_out' | 'settled' | 'expired' | 'review' required

Where the order is now. A newly created buy order is funds_reserved — your KES debit has been attempted and is awaiting the bank’s confirmation. settled, rejected and expired are the terminal states. Delivery is asynchronous — subscribe to webhooks rather than polling this field to completion.

kesAmountstring required

The trade PRINCIPAL in KES, decimal string, always 2 decimal places (KES cents). Taken from the quote — never restated by you, never a JSON number. This is not what was debited: the debit is kesTotalAmount, which adds the disclosed fee.

usdtAmountstring required

USDT you will receive, decimal string, always 6 decimal places. Never a JSON number. Derived from the PRINCIPAL — the fee does not change it.

ratestring required

KES per USDT the order is priced at, from the consumed quote.

kesTotalAmountstring required

What was actually debited: principal + fee. This is the figure that appears on your statement, and the one to reconcile against. It equals kesAmount exactly when no fee applies.

expiresAtstring date-time required

ISO 8601 UTC. Informational only on this leg — nothing expires it.

Example response

{
  "orderId": "9c1e4b07-6d52-4a83-91fe-40ab72c5d318",
  "status": "funds_reserved",
  "kesAmount": "1281000.00",
  "usdtAmount": "10000.000000",
  "rate": "128.1000",
  "kesTotalAmount": "1293820.00",
  "fee": {
    "kesAmount": "12820.00",
    "currency": "KES",
    "percentBps": 100,
    "flatKesAmount": "10.00"
  },
  "expiresAt": "2026-09-02T09:30:00.000Z",
  "kesDebit": {
    "status": "reserved"
  }
}

Changes

No recorded changes to this operation across all 1 revision of this API.