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.

Same Envelope As Other Corridors

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.

Beneficiary Not Allowed Here

The quote body has no beneficiary_info and no destination_type. Both belong on Initialize.

SWIFT Quote - Sample Request
SWIFT Quote - Sample Response

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
1
beneficiaryobjectRequired

SWIFT payload — see the three tables below. Validated against the corridor's field schema for (country, destination_type=swift).

2
referencestringOptional

Client-set idempotency / tracking reference. Overrides or supplements the quote's reference.

3
payment_reasonstringOptional

Short reason code for the payment (free text at this level).

4
callback_urlstringOptional

Per-payout webhook URL override.

5
customer_idstringOptional

Optional link to a persisted customer record.

6
client_meta_datastringOptional

Arbitrary client metadata string.

beneficiary — Core SWIFT Fields
1
destination_typestringRequired

Set to 'swift' (lowercase). Selects the SWIFT wire rail.

2
countrystringRequired

ISO 3166-1 alpha-2 of the destination account. Must match the country on the quote.

3
account_namestringRequired

Full name of the recipient (e.g. 'John Doe').

4
account_numberstringRequired

Recipient's account number, or IBAN if the destination country uses IBAN.

5
swift_codestringRequired

Recipient bank's SWIFT code.

6
bank_namestringRequired

Display name of the destination bank.

7
bank_addressstringRequired

Street address of the destination bank branch.

8
bank_citystringRequired

City of the destination bank branch.

9
bank_post_codestringRequired

Postal / ZIP code of the destination bank branch.

10
bank_countrystringRequired

ISO 3166-1 alpha-2 of the destination bank's country.

11
remittance_purposestringRequired

Lowercase snake_case value from the remittance purposes enum (see reference below).

12
beneficiaryobjectRequired

Recipient's physical address (nested object — see table below).

13
senderobjectRequired

Sender identity, discriminated by `type` ('business' or 'individual'). See table below.

beneficiary.beneficiary — Recipient Address
1
countrystringRequired

ISO 3166-1 alpha-2 of the recipient.

2
citystringRequired

City.

3
post_codestringRequired

Postal / ZIP code.

4
addressstringRequired

Street address.

RW and SG Only

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
1
typestringRequired

'business' or 'individual' (case-insensitive, normalised server-side).

2
account_namestringRequired

Legal name of the sender (same name-validation rules as recipient account_name).

3
countrystringRequired

Sender's ISO 3166-1 alpha-2 country code.

4
citystringRequired

Sender's city.

5
addressstringRequired

Sender's street address.

6
post_codestringRequired

Sender's postal code.

7
registration_numberstringConditional

Business registration / tax ID, 2–30 chars. REQUIRED when type='business'; ignored for individuals.

8
date_of_birthstringConditional

YYYY-MM-DD. REQUIRED when type='individual'.

9
country_of_birthstringConditional

ISO 3166-1 alpha-2. REQUIRED when type='individual'.

SWIFT Initialize - Sample Request
SWIFT Initialize - Sample Response

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.

1
AU — bsb_numberstringRequired for AU

Australia: 6-digit BSB code, pattern ^\d{6}$. The corridor placeholder shows '062-000' but dashes are NOT accepted — strip them ('062000').

2
IN — IFSCodestringRequired for IN

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.

3
HK — swift_code patternstring

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.

4
RW / SG — beneficiary.typestringRequired for RW / SG

Rwanda and Singapore require `type` ('business' or 'individual') on the nested beneficiary object.

Valid remittance_purpose Values

Step 3 — Finalize

No body. Commit the debit and release the payment to the SWIFT rail.

Empty Body

Any body you send on Finalize is ignored. The server only reads the :quoteId from the path.

SWIFT Finalize - Request
SWIFT Finalize - Sample Response

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.

Discover SWIFT Support
SWIFT Corridor Entry (Example)

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

1

Beneficiary on the quote. It doesn't go there. Quote has no beneficiary_info, no destination_type. Both live on Initialize.

2

Casing on enums. API is lowercase snake_case for destination_type, remittance_purpose, sender.type. The adapter uppercases them before dispatch — send lowercase.

3

Casing on SWIFT/BIC. Must be uppercase (DEUTDEFF, not deutdeff). Length is exactly 8 or 11.

4

Three address blocks. bank_* = destination bank; nested beneficiary.* = recipient's physical address; sender.* = payer's address. All three are independent.

5

Finalize body. There is none — sending a body is ignored.

6

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).

7

Sender variant mismatch. type: "individual" with registration_numberregistration_number is silently ignored. type: "business" without registration_number → validation fails.

8

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.

9

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".

10

AU BSB has no dashes. Placeholder shows 062-000; regex ^\d{6}$ rejects the dash. Submit as 062000.

Did you find this page useful?