Skip to main content
This is the recipients-specific integration guide. Getting fields right is most of the work in this service, and the API is built so you never have to know a country’s banking conventions yourself.

Never hardcode a country’s fields

Every route publishes exactly what it needs. Read the descriptors and render them.
A form built this way keeps working when a route adds a field, changes a bank list, or tightens a pattern. A form built from a hardcoded list starts failing silently — the extra field is not sent, and the payout is refused.

The two field styles

The same routing values are sent two different ways depending on which endpoint you use. This is the single most common source of 400s here.
The inline shape accepts a fixed vocabulary: accountNumber, routingNumber, sortCode, iban, swiftBic, bankCode, branchCode, bankInstitutionNumber, transitNumber, accountType, phoneNumber, bsb, institutionName, and country. A route requiring something outside that list can only be used through a saved payment detail.

What validation checks

Saved details are validated against the route’s descriptors, and every problem comes back at once:
Map errors[].field straight back onto your form. Every entry names the field and the reason, so three bad inputs are three highlighted boxes rather than three round trips.

Institution directories

A route with institutionDirectoryEnabled: true resolves institution codes to canonical names for you.
  • Present the options from the select descriptor.
  • Send the code, in fields.
  • Sakawave fills in institutionName on the stored detail.
Do not ask the user to type a bank name on such a route, and do not bother sending institutionName yourself — it is resolved from the code.

Country, and when it is required

country is required for a bank-transfer route that is not already scoped to one country. A route with destinationCountry set already knows; a scheme route like sepa or cemac does not. The simplest rule: always send country when you know it.

Verification changes the name

Where a route supports account lookup, Sakawave asks the provider who owns the account and replaces the name you sent. The destination’s displayName is the verified name, not your accountName.
Two things follow:
  1. Show it before confirming a payment. A name that comes back materially different means the account number is wrong or belongs to someone else. This check costs nothing and catches both typos and misdirection.
  2. Do not assume it matches your records exactly. Banks return their own formatting — case, ordering, middle names. Compare loosely and review the near-misses rather than failing them.
Not every route verifies. Where none is available, displayName is the name you sent, unchanged — so never treat its presence alone as proof of anything.

The counterparty profile

Separately from routing, international payout rails require a profile of who is being paid: For a saved recipient these are required at creation, so the failure comes early. Inline they are optional to the parser and required by the rail, so the failure comes late — at destination time, as 422 recipient_profile_incomplete listing each missing field. Domestic NGN routes do not ask for the profile at all, which is why an integration built only against NGN can be surprised by its first international payout.

A checklist for a correct payload

  1. Read the route. Never assume its fields.
  2. Render from fieldDescriptors, honouring required, lengths, pattern, and options.
  3. Send codes, not names, on directory-backed routes.
  4. Include country whenever you know it.
  5. Put routing in fields for a saved detail, top-level for an inline destination.
  6. Supply the counterparty profile on international routes.
  7. Compare the returned displayName against what you expected before releasing money.