Skip to main content
POST
Create an FX quote

Minor units in, decimals out

You send sourceAmount as a positive integer of minor units — "2500000" for ₦25,000 — and the response returns "25000.00". The request and the response are not in the same form. Never feed a response amount back into a request.

A quote is bound to one transfer

Five things are fixed when the quote is created: sourceAccountId, destinationId, sourceCurrency, destinationCurrency, and amountSide together with its amount. Spending it on a transfer that differs in any of them fails with fx_quote_mismatch or fx_quote_amount_mismatch. Quote, preview, and transfer in one sequence, and do not cache a quote across user decisions.

Expiry

expiresAt comes from the FX provider, not from a fixed Sakawave window — read it rather than assuming a duration. A quote is also single-use: used becomes true when a transfer spends it.

Error codes

Authorizations

Authorization
string
header
required

A secret API key, sent as Authorization: Bearer sk_test_… in sandbox or Bearer sk_live_… in live.

Body

application/json

Provide only the amount matching amountSide. The currencies must differ.

sourceAccountId
string
required

The account the money leaves. Must be active, debitable, and in sourceCurrency.

Required string length: 26
Pattern: ^[0-7][0-9A-HJKMNP-TV-Z]{25}$
Example:

"01K2Z3AB4C5D6E7F8G9HJKMNPQ"

destinationId
string
required

An unexpired, unspent destination. Its currency must equal destinationCurrency.

Required string length: 26
Pattern: ^[0-7][0-9A-HJKMNP-TV-Z]{25}$
Example:

"01K2Z3AB4C5D6E7F8G9HJKMNPQ"

sourceCurrency
enum<string>
required
Available options:
NGN,
USD,
GBP,
EUR,
GHS,
ZAR,
UGX,
CAD,
MXN,
AED
destinationCurrency
enum<string>
required
Available options:
NGN,
USD,
GBP,
EUR,
GHS,
ZAR,
UGX,
CAD,
MXN,
AED,
AUD,
SGD,
HKD,
KES,
TZS,
BRL,
CNY,
XAF,
PHP,
USDC
amountSide
enum<string>
required

Which side you are fixing. Send the matching amount and only that one.

Available options:
source,
destination
sourceAmount
string
required

A positive integer number of minor units.

Pattern: ^[1-9]\d*$
Example:

"2500000"

destinationAmount
string

A positive integer number of minor units.

Pattern: ^[1-9]\d*$
Example:

"2500000"

Response

Successful response.

id
string
required

A 26-character ULID.

Required string length: 26
Pattern: ^[0-7][0-9A-HJKMNP-TV-Z]{25}$
Example:

"01K2Z3AB4C5D6E7F8G9HJKMNPQ"

sourceAccountId
string
required

A 26-character ULID.

Required string length: 26
Pattern: ^[0-7][0-9A-HJKMNP-TV-Z]{25}$
Example:

"01K2Z3AB4C5D6E7F8G9HJKMNPQ"

destinationId
string
required

A 26-character ULID.

Required string length: 26
Pattern: ^[0-7][0-9A-HJKMNP-TV-Z]{25}$
Example:

"01K2Z3AB4C5D6E7F8G9HJKMNPQ"

sourceCurrency
enum<string>
required
Available options:
NGN,
USD,
GBP,
EUR,
GHS,
ZAR,
UGX,
CAD,
MXN,
AED
destinationCurrency
enum<string>
required
Available options:
NGN,
USD,
GBP,
EUR,
GHS,
ZAR,
UGX,
CAD,
MXN,
AED,
AUD,
SGD,
HKD,
KES,
TZS,
BRL,
CNY,
XAF,
PHP,
USDC
amountSide
enum<string>
required
Available options:
source,
destination
sourceAmount
string
required

A decimal display amount returned by transfer APIs. Preserve it as a string.

Pattern: ^-?\d+(?:\.\d+)?$
Example:

"25000.00"

destinationAmount
string
required

A decimal display amount returned by transfer APIs. Preserve it as a string.

Pattern: ^-?\d+(?:\.\d+)?$
Example:

"25000.00"

rate
string
required
expiresAt
string<date-time>
required
Example:

"2026-08-14T09:00:00.000Z"

used
boolean
required