Ryft allows you to convert funds between currencies using foreign exchange (FX). For more background, see Conversions in Core Concepts.
Before creating a conversion, you can use the conversionsGetRate endpoint to retrieve an indicative gross exchange rate and buy amount, along with the fees that will be charged.
The rate returned is indicative only and is not held — the rate applied when you create a conversion may differ. Request a rate only when needed rather than polling; this endpoint is rate-limited and will return a 429 Too Many Requests response if exceeded.
Rates are briefly unavailable during a short daily window (~90 seconds) while FX trading closes. During this window the endpoint returns a 400 Bad Request response with a message indicating that rates are temporarily unavailable — retry shortly. Creating a conversion is unaffected, as pricing is applied asynchronously.
Use the conversionCreate endpoint to create a conversion. Specify the sell currency and amount and the buy currency.
The sell.amount must be within the minimum and maximum conversion limits for the sell currency; requests outside the range are rejected with a 400. See conversion amount limits.
Before creating a conversion, you must obtain agreement from the account holder to Ryft's conversion terms. Set termAgreement: true in the request body to confirm this — the request is rejected if it is false.
{
"sell": {
"currency": "EUR",
"amount": 100000
},
"buy": {
"currency": "GBP"
},
"reason": "Monthly EUR settlement",
"termAgreement": true
}The API responds with the new conversion in status: InProgress. The rate, buy.amount, sell.fees/buy.fees, and estimatedSettlementDate are not present — pricing is applied asynchronously.
{
"id": "cv_XXXXXXXX",
"sell": {"amount": 100000, "currency": "EUR"},
"buy": {"currency": "GBP"},
"status": "InProgress",
"reason": "Monthly EUR settlement",
"createdTimestamp": 1750000000
}Next, subscribe to the Conversion.updated webhook event to track the conversion through the rest of its lifecycle: the first event carries the pricing (rate, buy.amount, sell.fees/buy.fees and estimatedSettlementDate), and a later one moves status to Settled once the bought funds are credited to the account's balance. See Conversions Webhooks for the full payload examples.
Conversions are booked for same-day settlement if created before the cut-off time for the currencies involved, provided the relevant FX markets are open. Otherwise, they settle on the next available business day. Cut-off times vary by currency, and FX markets are closed on weekends and public holidays. See Settlement times for specific currency cut-offs.
Because the deadline depends on both currencies and the calendar, don't assume a fixed offset. Instead, use the estimatedSettlementDate (ISO date) returned by Ryft:
- conversionsGetRate — returned alongside the indicative rate, so you can show an expected settlement date before creating a conversion.
- The conversion object — populated once pricing has been applied, from the first
Conversion.updatedevent onward. It is not present on the create response or theConversion.createdevent.
estimatedSettlementDate is an estimate and may not exactly match the final settlement date. A conversion is settled once a Conversion.updated event with status: Settled is emitted and settledTimestamp is set — at that point the bought funds are credited to the account's balance.
Upon settlement, the converted funds will reflect in the account's available balance.
- Automatic payouts: Ryft will trigger a payout within 24 hours of the conversion settling. No action is required.
- Manual payouts: For NonHosted accounts we recommend triggering a payout after receiving the
Conversion.updatedevent wherestatusisSettled.
See Payouts for more on payout configuration.
Ryft applies an FX fee to every conversion. The rate and all amounts are gross values (before fees).
The fee is charged on exactly one side of the conversion, so sell.fees and buy.fees are mutually exclusive — read whichever one is present. Which side it falls on determines the net amount credited to the account balance:
- Buy side (
buy.fees) — the wholesell.amountis converted atrateto givebuy.amount, and the fee is deducted from it afterwards: Net Credit =buy.amount− Fee. - Sell side (
sell.fees) — the fee is deducted fromsell.amountbefore the conversion, so only the remainder is converted: Net Credit =buy.amountin full.
Fee amounts are in minor units of the currency of the side they are charged on.
Once calculated, the fee breakdown on that side contains either ryft or platform, depending on the account type:
- Main Accounts —
ryftshows Ryft's fee, which is deducted in full. - Sub-Accounts —
platformshows the total gross platform fee deducted. Ryft's fee (platform.ryftFee) is taken out of this amount — it is not an additional deduction. The platform retains the difference (platform.amount−platform.ryftFee.amount).
{
"ryft": {"amount": 700}
}Total fee deducted: 700 (all retained by Ryft).
{
"platform": {
"amount": 1000,
"ryftFee": {"amount": 700}
}
}Total fee deducted: 1000 (700 goes to Ryft, 300 retained by the platform).
The platform fee is a single rate across all Sub-Accounts, including conversions Sub-Accounts create directly via the Ryft Portal. Contact us to configure it.
For Sub-Account conversions, the platform fee is settled against the Main Account's balance via a ConversionPlatformFee balance transaction.
- With a configured platform fee — the transaction's
netvalue represents the platform's retained earnings (platform.amount−platform.ryftFee.amount). - Without a platform fee — a
ConversionPlatformFeetransaction is still created to cover Ryft's FX fee, resulting in a negativenetvalue (a debit) on the Main Account.
Take the single populated fee — ryft.amount for a Main Account, or platform.amount for a Sub-Account — from whichever side carries fees, then apply the net credit above. The effective rate you received is the net amount credited ÷ sell.amount.
For a buy-side fee (sell.amount 100000, buy.amount 86000, Ryft fee 700):
net amount = 86000 − 700 = 85300
effective rate = 85300 ÷ 100000 = 0.853For a sell-side fee (sell.amount 100000, Ryft fee 700, so 99300 converted at 0.86 to give buy.amount 85398):
net amount = 85398
effective rate = 85398 ÷ 100000 = 0.85398Alternatively, once the conversion settles the credited funds appear as a balance transaction of type ConversionBuy, whose net field is the net amount credited — so you can read it directly instead of computing it. The sold funds are debited from the sell-currency balance as a matching ConversionSell transaction.
The following walks through the full lifecycle of a conversion. In this scenario, a merchant collects payments in EUR but only holds a GBP bank account. They convert €1,000.00 of their EUR balance to GBP so it can be paid out.
{
"sell": {"currency": "EUR", "amount": 100000},
"buy": {"currency": "GBP"},
"reason": "Monthly EUR settlement",
"termAgreement": true
}The response contains the new conversion. The rate and buy amount are not yet known:
{
"id": "cv_XXXXXXXX",
"sell": {"amount": 100000, "currency": "EUR"},
"buy": {"currency": "GBP"},
"status": "InProgress",
"reason": "Monthly EUR settlement",
"createdTimestamp": 1750000000
}A Conversion.created webhook is dispatched immediately, carrying the same unpriced object.
Once the rate is determined, a Conversion.updated event is emitted. The rate, buy.amount (gross, before fees), fees, and estimatedSettlementDate are now populated. See Calculating the net amount and effective rate to derive what is credited to the balance:
{
"id": "cv_XXXXXXXX",
"sell": {"amount": 100000, "currency": "EUR"},
"buy": {
"amount": 86000,
"currency": "GBP",
"fees": {
"ryft": {"amount": 700}
}
},
"rate": 0.86,
"status": "InProgress",
"reason": "Monthly EUR settlement",
"estimatedSettlementDate": "2026-06-20",
"createdTimestamp": 1750000000
}Where the fee is charged on the sell side instead, fees sits on sell and buy carries none — the fee came off the 100000 EUR before conversion, so 99300 was converted at rate and the full buy.amount is credited:
{
"id": "cv_XXXXXXXX",
"sell": {
"amount": 100000,
"currency": "EUR",
"fees": {
"ryft": {"amount": 700}
}
},
"buy": {"amount": 85398, "currency": "GBP"},
"rate": 0.86,
"status": "InProgress",
"reason": "Monthly EUR settlement",
"estimatedSettlementDate": "2026-06-20",
"createdTimestamp": 1750000000
}When the conversion settles, a further Conversion.updated is emitted. The status is now Settled, settledTimestamp is set, and the GBP funds are available in the account's balance:
{
"id": "cv_XXXXXXXX",
"sell": {"amount": 100000, "currency": "EUR"},
"buy": {
"amount": 86000,
"currency": "GBP",
"fees": {
"ryft": {"amount": 700}
}
},
"rate": 0.86,
"status": "Settled",
"reason": "Monthly EUR settlement",
"estimatedSettlementDate": "2026-06-20",
"settledTimestamp": 1750086400,
"createdTimestamp": 1750000000
}The GBP funds are now available in the account's balance. If the account is on automatic payouts, Ryft will trigger a payout within 24 hours — no action needed. If on manual payouts, trigger one after receiving the settled event above.
- API reference — full endpoint documentation
- Conversions Webhooks — event payload reference
- Payouts — payout configuration