Multi-currency balances
Hold money in many currencies, each in its own balance, and get account details to be paid in them. Converting between balances and paying from them are coming soon.
Holding currency balances and getting paid in them work in sandbox, with test money. Live balances aren't part of our first launch, which starts with US businesses and the USD account. Converting between balances, paying from a balance and local payouts in many currencies are coming soon.
How it works
- Each currency is its own balance. Money in euros stays in euros. Balances are kept per currency and never added up into one total.
- Separate from your USD business account. Your USD account (with account and routing numbers at our banking partner) and your currency balances are different accounts. A currency balance can be in US dollars too, and it's still separate from your USD account. You can't move money between your USD account and a currency balance, and cards spend from the USD account only.
- Held in your business's name. The money in your currency balances is held by our multi-currency partner in your business's name. SorenPay keeps a ledger of it.
- Balances change when money has actually moved. Money on its way shows as in progress until our partner reports it arrived, and the amount credited is the amount that arrived.
What works today
| What | Status | Where |
|---|---|---|
| Open a balance in a currency | In sandbox | Dashboard: Accounts → Add currency |
| Account details to get paid in a currency | In sandbox, for the currencies our partner issues them in | GET /api/mca/accounts/{currency}/details |
| Add test money | In sandbox | Dashboard: Add test money on a balance |
| Your balances and their status | In sandbox | GET /api/mca/accounts |
| Lock a rate and convert | Coming soon: built, not switched on for beta accounts yet | POST /api/mca/quotes, POST /api/mca/conversions |
| An estimated rate while you type | Coming soon, with converting | Dashboard only (GET /api/mca/rates) |
| Activity for one currency | In sandbox | GET /api/mca/activity?currency=EUR |
| Pay from a balance | Coming soon | See below |
| Local payouts in many currencies | Coming soon | See below |
| Statements | Coming soon |
Every endpoint, with its fields and errors, is in the multi-currency API reference.
Which currencies you can open
It depends on your account and on our partner. GET /api/mca/accounts
answers with coverage.currencies: one entry per currency your workspace can
open, with receive (whether you get account details in it) and convert
(whether it can be converted). A currency your account can't hold has
receive: false, convert: false and a short reason. Some currencies are
restricted and can't be opened at all (422 currency_restricted).
Is converting available on my account?
GET /api/mca/accounts also answers with features:
| Field | Meaning |
|---|---|
features.convert | You can lock a rate and convert between balances |
features.estimate | The dashboard can show an estimated rate while you type |
features.send | You can pay a recipient from a balance |
features is left out when it isn't known yet. While converting is coming
soon, features.convert is false on beta accounts. Where it's false, the
dashboard says converting isn't available on your account yet, and
POST /api/mca/quotes and POST /api/mca/conversions answer
422 capability_unavailable. Nothing is held or written when that happens.
Convert
Converting between balances isn't switched on for beta accounts yet:
features.convert is false, and both calls below answer
422 capability_unavailable. This is how it works once it's on.
Converting takes two calls: a quote that locks a rate, then the conversion.
Both need write:treasury and an Idempotency-Key. Amounts are whole minor
units as strings ("10000" is EUR 100.00), never decimals.
Both balances, the one you sell and the one you buy, have to be open and ready
before you ask for a quote. A currency you don't hold yet answers
404 currency_account_not_found (open it with Add currency first), and a
balance that's still being set up answers 409 account_not_ready.
curl -X POST https://sorenpay.com/api/mca/quotes \
-H "Authorization: Bearer $SOREN_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"sellCurrency": "EUR",
"buyCurrency": "GBP",
"amountMinor": "10000",
"fixedSide": "sell"
}'The quote (201) shows exactly what you'll sell and get, the rate, and
lockExpiresAt. hold is what converting sets aside from the balance: the
amount sold, plus the most the partner's fee can be where there is one. Your
balance has to cover hold. The rate includes our fee (includesOurFee).
{
"id": "…",
"status": "open",
"sell": { "currency": "EUR", "amountMinor": "10000", "display": "100.00" },
"buy": { "currency": "GBP", "amountMinor": "…", "display": "…" },
"rate": "…",
"rateDisplay": "1 EUR = … GBP",
"includesOurFee": true,
"hold": { "currency": "EUR", "amountMinor": "10000", "display": "100.00" },
"lockExpiresAt": "…",
"serverNow": "…"
}curl -X POST https://sorenpay.com/api/mca/conversions \
-H "Authorization: Bearer $SOREN_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ "quoteId": "<quote id>" }'The answer is 202 with {orderId, status}, where status is held or
provider_submitted. That means the conversion was accepted, not that it's
done. Check it with GET /api/mca/conversions/{orderId} until status is
completed (or rejected, failed or cancelled). label describes it in
plain words.
A quote can be used once: using it again answers 422 quote_used. After
lockExpiresAt the conversion answers 422 quote_expired; get a new quote.
To get US dollars, buy USD into a USD currency balance, opened with Add currency. That balance is separate from your USD business account: the dollars land in the currency balance, and can't be moved into the USD account yet.
Estimated rates
Coming soon, with converting. While someone types an amount, the dashboard
shows an estimate from GET /api/mca/rates. It's indicative
(indicative: true): nothing is locked or held, and converting still needs a
quote. It works only with a dashboard session, so an API key gets
403 session_required. In code, use a quote.
Pay from a balance
Paying a recipient straight from a currency balance isn't available yet. The
routes exist (POST /api/mca/payouts/quotes, POST /api/mca/payouts and
GET /api/mca/payouts), but no partner serves payouts from a balance yet,
so sending answers 422 capability_unavailable and features.send is
false.
Until then, pay from your USD account: by ACH or wire inside the US, or by international wire abroad (both in sandbox).
What's coming
- Pay from a currency balance: pay a saved recipient in their currency, straight from one of your balances.
- Local payouts in many currencies: pay people and suppliers abroad in their local currency through our FX partners.
- Statements for each currency balance.
- Live balances: after our first launch.
These are Coming soon. We don't give dates.
Related
- Multi-currency API reference
- Stablecoins: USDC is a separate balance again, apart from both your USD account and your currency balances
- Authentication: scopes and idempotency