Send money abroad by international wire

Pay a recipient abroad from your US dollar account by SWIFT wire. For a payment in another currency you get a firm exchange rate first, and the recipient amount is fixed before you confirm.

In sandbox

International wires work with test money today. Live payments aren't switched on yet, and the bank sets how long a wire takes: there's no same-day guarantee.

The three calls

  1. Save the recipient once: POST /api/treasury/counterparties with kind: "international". Needs the scope write:counterparties.
  2. Get a firm rate (not needed for US dollar wires): POST /api/treasury/fx-quotes. Needs write:payouts.
  3. Send: POST /api/treasury/payouts with rail: "intl_wire". Needs write:payouts and an Idempotency-Key.
send-eur.tstypescript
const headers = {
Authorization: `Bearer ${process.env.SOREN_API_KEY}`,
"Content-Type": "application/json",
};

// 1. Save the recipient (IBAN or the country's local account number)
const counterparty = await fetch("https://sorenpay.com/api/treasury/counterparties", {
method: "POST",
headers: { ...headers, "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({
  kind: "international",
  name: "Acme GmbH",
  bic: "COBADEFFXXX",
  accountNumber: "DE89370400440532013000",
  holderType: "business",
  address: { line1: "Hauptstrasse 1", city: "Berlin", countryCode: "DE" },
  currency: "EUR",
}),
}).then((r) => r.json());

// 2. Firm rate for exactly EUR 1,000.00 arriving (before bank deductions)
const quote = await fetch("https://sorenpay.com/api/treasury/fx-quotes", {
method: "POST",
headers: { ...headers, "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({
  counterpartyId: counterparty.id,
  buyCurrency: "EUR",
  buyAmountMinor: 100000,
}),
}).then((r) => r.json());

// 3. Send before the quote's lock expires
const payout = await fetch("https://sorenpay.com/api/treasury/payouts", {
method: "POST",
headers: { ...headers, "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({
  rail: "intl_wire",
  counterpartyId: counterparty.id,
  instructedCurrency: "EUR",
  instructedAmountMinor: 100000,
  quoteId: quote.id,
  description: "Invoice 2026-114",
}),
}).then((r) => r.json());

Each call returns the saved object (recipient, quote or payout) with its id. The full field list is in the OpenAPI spec at /api/v1/openapi.json.

After you send

  • Status: GET /api/treasury/payouts/{id}.
  • Tracking: GET /api/treasury/payouts/{id}/tracking returns the SWIFT tracking the bank reports.
  • Held US dollar wires can be released or cancelled with POST /api/treasury/payouts/{id}/release and /cancel.
  • Recall (/recall) isn't available yet.

A payout's amount is reserved from your balance when you send it. If the bank never confirms it, the reservation is released after 24 hours. Nothing is sent twice: a payout is submitted to the bank once and never retried.

Coming soon

  • Local payouts in many currencies through our FX partners: pay a bank abroad in the recipient's currency (/api/payments/international answers 422 capability_unavailable until then).
  • Paying from a currency balance. See Multi-currency.

Every recipient you save is screened against sanctions lists first. See Compliance.