Create quote and the discovery endpoints are not gated, so a new integration can price orders end to end and only discover the wall here. Ask support to switch it on first.
Request
Set exactly one amount. Provide either deposit.amount or payout.amount, never both and never neither. The other leg is derived. Sending both, or none, is rejected with 400.
deposit and payout are strict objects — an unknown key is rejected rather than ignored.
fieldsToCreateOrder is the flat union of the two fieldsToCreateOrder arrays the quote returned. Send every field marked required: true on either leg, keyed by its key.
The key itself is optional on the wire and defaults to an empty object — which is only useful for the rare pair where neither leg asks for anything. Every fiat and crypto leg we run today asks for at least one field, so in practice you always send it; omitting it turns a clear "field X is required" into the same error with nothing to go on.
Request body example:
Response
The full Order shape — every field of deposit, payout and refund — is on the Types page, and Get order shows a completed one. Every order endpoint on this site returns the same object.
The three fields you act on straight away:
order._id — the orderId every later call takes.
order.status — deposit_awaiting on a fresh order. See Order statuses.
order.deposit.transferInstructions — how the user pays. Its type decides whether you show details, redirect, or trigger an STK push. See Transfer types explanation.
statusChangeLogs comes back empty: it records transitions, and creation is not one.
Response example (sandbox, bank manual transfer):
The rates, fees, contract address and bank details above are sandbox fixtures. Never hard-code them.
What to do next
Show order.deposit.transferInstructions to the user.
type RequestBody = {
quoteId?: string; // from Create quote; reuses its locked rate and fees
userEmail: string; // required
userCountryIsoCode: string;// required, the user's country
userIp: string; // required, must be a valid IP
deposit: {
paymentChannel: PaymentChannel;
currencyType: CurrencyType;
currencyCode: string;
countryIsoCode?: string; // required if currencyType is fiat
carrierCode?: string; // mobile money / airtime
amount?: number;
};
payout: {
paymentChannel: PaymentChannel;
currencyType: CurrencyType;
currencyCode: string;
countryIsoCode?: string; // required if currencyType is fiat
carrierCode?: string;
amount?: number;
};
fieldsToCreateOrder?: Record<string, any>; // union of the deposit and payout fieldsToCreateOrder from the quote
orderParams?: string; // your own reference, echoed back and searchable
callbackUrl?: string; // "Back to website" button on the widget status page
webhookUrl?: string; // overrides your dashboard webhook URL for this order only
};