SWIFT Payouts
Cross-border payouts use the SWIFT destination type when the destination country/currency has no local corridor (ACH, SEPA, domestic GBP, mobile money, etc.). This is the fallback wire rail for USD, EUR, HKD, and similar currencies into most countries.
SWIFT flows use the standard three-step sequence — beneficiary details go on Initialize, not on the quote.
SWIFT is not a separate endpoint — the quote, initialize, and finalize responses all use the same data.payout envelope you see for bank, mobile_money, ACH, and SEPA corridors. The only architectural difference is destination_type: "swift" (plus the SWIFT-specific fields like swift_code, remittance_purpose, and the discriminated sender variant) on the Initialize beneficiary. Refer to Create Payouts Quote, Initialize Payout, and Finalize Payout above for full per-field explanations — the SWIFT steps below focus on what's SWIFT-specific.
Step 1 — Create Quote
Describes currency, amount, and destination country. No beneficiary info on the quote. The quote is the same shape used for every payout corridor — see Create Payouts Quote above for the full field reference.
The quote body has no beneficiary_info and no destination_type. Both belong on Initialize.
Step 2 — Initialize (the SWIFT payload)
The SWIFT beneficiary lives inside the top-level beneficiary object on POST /api/payouts/:quoteId/initialize. All API fields are lowercase snake_case; the adapter normalises them to the downstream provider's format.
Top-Level Fields
SWIFT payload — see the three tables below. Validated against the corridor's field schema for (country, destination_type=swift).
Client-set idempotency / tracking reference. Overrides or supplements the quote's reference.
Short reason code for the payment (free text at this level).
Per-payout webhook URL override.
Optional link to a persisted customer record.
Arbitrary client metadata string.
beneficiary — Core SWIFT Fields
Set to 'swift' (lowercase). Selects the SWIFT wire rail.
ISO 3166-1 alpha-2 of the destination account. Must match the country on the quote.
Full name of the recipient (e.g. 'John Doe').
Recipient's account number, or IBAN if the destination country uses IBAN.
Recipient bank's SWIFT code.
Display name of the destination bank.
Street address of the destination bank branch.
City of the destination bank branch.
Postal / ZIP code of the destination bank branch.
ISO 3166-1 alpha-2 of the destination bank's country.
Lowercase snake_case value from the remittance purposes enum (see reference below).
Recipient's physical address (nested object — see table below).
Sender identity, discriminated by `type` ('business' or 'individual'). See table below.
beneficiary.beneficiary — Recipient Address
ISO 3166-1 alpha-2 of the recipient.
City.
Postal / ZIP code.
Street address.
Rwanda (RW) and Singapore (SG) additionally require type on the nested beneficiary — one of "business" or "individual". No other SWIFT-supporting country requires this.
beneficiary.sender — Payer Identity
'business' or 'individual' (case-insensitive, normalised server-side).
Legal name of the sender (same name-validation rules as recipient account_name).
Sender's ISO 3166-1 alpha-2 country code.
Sender's city.
Sender's street address.
Sender's postal code.
Business registration / tax ID, 2–30 chars. REQUIRED when type='business'; ignored for individuals.
YYYY-MM-DD. REQUIRED when type='individual'.
ISO 3166-1 alpha-2. REQUIRED when type='individual'.
Country-Specific Extras
A handful of countries add required fields beyond the core SWIFT schema. The corridor config at GET /api/payouts/supported-countries/:country is the source of truth.
Australia: 6-digit BSB code, pattern ^\d{6}$. The corridor placeholder shows '062-000' but dashes are NOT accepted — strip them ('062000').
India: 11-char IFSC code, pattern ^[A-Z]{4}0[A-Z0-9]{6}$. Note the key is `IFSCode` (camelCase) — unlike every other field in the payload. Sending `ifs_code` or `ifsc_code` silently fails validation.
Hong Kong uses a stricter SWIFT regex: ^[A-Za-z]{4}HK[A-Za-z0-9]{2}([A-Za-z0-9]{3})?$ — chars 5–6 are pinned to literal 'HK'. Case-insensitive on HK only.
Rwanda and Singapore require `type` ('business' or 'individual') on the nested beneficiary object.
Step 3 — Finalize
No body. Commit the debit and release the payment to the SWIFT rail.
Any body you send on Finalize is ignored. The server only reads the :quoteId from the path.
Discovering SWIFT-Enabled Countries
Before building a SWIFT payload, fetch the corridor config for the destination country and look for destination_types containing "swift". The returned schema for that destination type is the source of truth for that country's required fields.
Validation Failures
http | code | cause |
|---|---|---|
400 | INVALID_BODY | Request body isn't valid JSON or doesn't match the handler shape. |
400 | INVALID_BENEFICIARY_DATA | `country` missing from beneficiary; or a required SWIFT field is missing / fails regex / exceeds length limits. The error message lists each failing field. |
410 | QUOTE_EXPIRED | Quote TTL elapsed before Initialize or Finalize was called. Run the quote + initialize flow again. |
422 | UNSUPPORTED_CORRIDOR | (country, destination_type) pair has no schema — e.g. requesting `swift` for a country that doesn't support it. |
422 | AMOUNT_OUTSIDE_LIMITS | Quote amount is below or above the corridor's min/max limits. |
422 | INSUFFICIENT_BALANCE | Company balance can't cover the payout when source is `offchain`. |
Common Pitfalls
Beneficiary on the quote. It doesn't go there. Quote has no beneficiary_info, no destination_type. Both live on Initialize.
Casing on enums. API is lowercase snake_case for destination_type, remittance_purpose, sender.type. The adapter uppercases them before dispatch — send lowercase.
Casing on SWIFT/BIC. Must be uppercase (DEUTDEFF, not deutdeff). Length is exactly 8 or 11.
Three address blocks. bank_* = destination bank; nested beneficiary.* = recipient's physical address; sender.* = payer's address. All three are independent.
Finalize body. There is none — sending a body is ignored.
country appears twice. Once at the top of beneficiary (corridor lookup key), once nested inside beneficiary.beneficiary.country (recipient's country — often the same value).
Sender variant mismatch. type: "individual" with registration_number → registration_number is silently ignored. type: "business" without registration_number → validation fails.
Name format. account_name / sender.account_name must have ≥2 space-separated parts, each ≥2 chars. No Mr/Mrs/Dr. No single-letter-plus-dot. J. Doe rejects; John Doe passes.
IFSCode is the one camelCase field. Every other SWIFT field is snake_case; India's IFSC is literally IFSCode. Sending ifs_code / ifsc_code silently fails as "missing required field".
AU BSB has no dashes. Placeholder shows 062-000; regex ^\d{6}$ rejects the dash. Submit as 062000.