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.

In sandbox

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

WhatStatusWhere
Open a balance in a currencyIn sandboxDashboard: Accounts → Add currency
Account details to get paid in a currencyIn sandbox, for the currencies our partner issues them inGET /api/mca/accounts/{currency}/details
Add test moneyIn sandboxDashboard: Add test money on a balance
Your balances and their statusIn sandboxGET /api/mca/accounts
Lock a rate and convertComing soon: built, not switched on for beta accounts yetPOST /api/mca/quotes, POST /api/mca/conversions
An estimated rate while you typeComing soon, with convertingDashboard only (GET /api/mca/rates)
Activity for one currencyIn sandboxGET /api/mca/activity?currency=EUR
Pay from a balanceComing soonSee below
Local payouts in many currenciesComing soonSee below
StatementsComing 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:

FieldMeaning
features.convertYou can lock a rate and convert between balances
features.estimateThe dashboard can show an estimated rate while you type
features.sendYou 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

Coming soon

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.

1. Lock a rate: sell EUR 100.00 for GBPbash
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": "…"
}
2. Convert before the lock expiresbash
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

Coming soon

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.