Bank Accounts

Add a bank account to a receiver for fiat payouts, with the fields the server checks per payment rail, Brazil PIX, errors and list behaviour

A bank account belongs to a receiver and is where a fiat payout lands.

Before you start

  1. The receiver exists and has email, address and countryIsoCode set.
  2. You have the Skyline ids of the account's currency and of the bank's country. Get them from GET /currencies?limit=250 and GET /countries?limit=250. See Setup.
  3. The user behind your API key is an active member of the organisation and is not view-only.

How the server decides which fields are required

Skyline pays out over payment rails (for example SEPA, Faster Payments, ACH or SWIFT). Each rail needs its own bank fields. When you create an account, the server:

  1. finds the rails enabled for the currency and bank country;
  2. leaves out SWIFT rails if you did not send bicSwift;
  3. checks every field that each remaining rail requires, and rejects the request at the first one that is missing or invalid.

The rails and their fields are configuration and can change, so read them before you build the request.

Get the rails and their fields

GET /payment-rails/available-rails?countryId=<country _id>&currencyId=<currency _id>

Send both ids (the same _id values you will send as bankCountry and currency). The response lists the rails enabled for that pair, each with the fields it needs:

[
  {
    "_id": "…",
    "name": "SEPA",
    "display": "SEPA",
    "rail": "SEPA",
    "requiredFields": [
      { "fieldName": "iban", "required": true },
      { "fieldName": "receiver.address.addressLine1", "required": true }
    ]
  }
]
  • A field is needed if any listed rail requires it. Fields named receiver.… are read from the receiver (see Receiver address).
  • An empty array means the pair cannot be paid out: POST /bank-accounts would fail with 400 No payment rails available.
  • GET /payment-rails/required-fields returns every rail's field list without the country and currency filter. Use it as a catalogue only.

If the server still names a missing field, add it and retry.

Create a bank account

POST /bank-accounts

Always required

FieldNotes
receiverThe receiver's _id
currencyCurrency _id from GET /currencies
bankCountryCountry _id from GET /countries

Rail fields

The server checks these fields against the rules below when a rail uses them. The IBAN checksum is checked whenever you send an IBAN.

FieldRule
ibanValid IBAN checksum
accountNumber4 to 17 characters
bicSwiftValid BIC. Needed for SWIFT rails
sortCode6 digits, no dashes. UK accounts are also checked against the account number
routingNumber9 digits (ABA)
ifscCodeValid Indian IFSC

Where a rail accepts either an IBAN or an account number, one of them is enough.

Optional bank details

bankName, bankCode, branchName, branchCode, bankAddress, bankAddress2, bankCity, bankState, bankZip, channel, intermediaryBankName, intermediaryRoutingCode. All are strings.

Receiver address

Some rails require the receiver's address (addressLine1, city, postCode). The server reads it from the receiver, not from the bank account request. Do not put address fields in this request: unknown fields return 400. If the receiver's address is incomplete, update the receiver first.

US dollar accounts in the United States

For a USD account with a US bank, choose the rails with two booleans:

FieldMeaning
achSupportThe account can receive ACH
fedSupportThe account can receive Fedwire
accountTypeCHECKING or SAVINGS. Kept only when achSupport is true

The response shows your choice as wireSupport: { "ach": "YES" | "NO", "fed": "YES" | "NO" }.

Example

{
  "receiver": "665f1c2e9b1e8a0012a3b4c5",
  "currency": "6150b94616b409003977df6d",
  "bankCountry": "6150b94616b409003977df70",
  "iban": "DE89370400440532013000",
  "bicSwift": "COBADEFFXXX",
  "bankName": "Commerzbank"
}

The response is the bank account, with receiver expanded and paymentRails listing the rails the account can be paid on. Keep its _id for transactions.

Brazil (BRL)

BRL payouts use PIX. TED is currently unavailable. Do not create TED accounts.

The receiver needs valid Brazilian identity details:

Receiver typeNeeds
INDIVIDUALtaxId (CPF), nationality (ISO alpha-2), dateOfBirth
COMPANYtaxId (CNPJ)

Set address.state (the UF, for example SP) on Brazilian receivers as well.

You can send taxId, nationality and dateOfBirth in the bank account request. The server copies them onto the receiver only where the receiver's value is missing or invalid. If the request then fails, the receiver is left unchanged.

To fill the bank details, look the bank up with GET /brazilian-banks?search=<name or code>&limit=20. Each result has bankName, bankCode (COMPE), bicSwift (or null), ispb and bicRequired. Send bankName, bankCode and bicSwift from the result. When bicRequired is true the bank has no known BIC: send one you got from the account holder.

PIX fields:

FieldRule
brazilRailPIX
pixKeyTypeEMAIL, PHONE, CPF, CNPJ or EVP. CPF only for an individual, CNPJ only for a company
pixKeyRequired. Up to 50 characters, and valid for its type (see below)
bankName, bankCode, bicSwiftThe bank's name, its three-digit COMPE code and, if it has one, its BIC
pixKeyTypeValid pixKey
EMAILAn email address
PHONEA Brazilian phone number. Stored in E.164, for example +5511999998888
CPFAn 11-digit CPF with valid check digits. Stored as digits only
CNPJA 14-digit CNPJ with valid check digits. Stored as digits only
EVPA random key (UUID v4)
{
  "receiver": "665f1c2e9b1e8a0012a3b4c5",
  "currency": "6150b94616b409003977df71",
  "bankCountry": "6150b94616b409003977df72",
  "brazilRail": "PIX",
  "pixKeyType": "EMAIL",
  "pixKey": "maria@example.com",
  "bankName": "Banco do Brasil",
  "bankCode": "001",
  "taxId": "52998224725",
  "nationality": "BR",
  "dateOfBirth": "1990-01-01"
}

If identity details are missing, the server returns 400 with the fields to fix:

{
  "message": "This beneficiary is missing valid Brazil identity details required for a BRL bank account: taxId, nationality",
  "error": "IncompleteBrlReceiver",
  "invalidFields": ["taxId", "nationality"]
}

Errors

StatusMessageFix
400Receiver not foundThe receiver is not in your organisation
403View-only members cannot modify beneficiariesUse a user who is not view-only
400Currency not found / Bank country not foundUse _id values from the lookups, not ISO codes
400In order to associate a bank account to a receiver, the receiver should have all details filled.Set the receiver's country, address and email
400IncompleteBrlReceiver (see above)Complete the receiver's Brazilian identity details
400No payment rails availableThis currency and country cannot be paid out
400The provided IBAN is not valid — check it for a mistyped characterFix the IBAN
400Bank account iban not provided, Bank account number not provided, Bank account bic/swift not provided, Please provide the Sort Code, Please provide the Routing Number, Please provide a valid IFSC CodeAdd the named field
400Account number must be between 4 and 17 characters, Please provide a valid Sort Code, Please provide a valid Routing NumberFix the format
400Bank account is not validThe UK sort code and account number do not match
400Address Line 1 not provided, City not provided, Post Code not providedComplete the receiver's address

Read, list, update and remove

  • Read one receiver's accounts from GET /receivers/{id} (its bankAccounts array). This is the reliable view: it covers every account on the receiver and leaves out removed ones.
  • GET /bank-accounts/{id} returns one account.
  • GET /bank-accounts/me takes only limit, offset and searchTerm. Filters such as receiver, currency or bankCountry return 400. It lists only accounts on receivers created by the same user, and it includes removed accounts, marked softDeleted: true.
  • PATCH /bank-accounts/{id} changes an account. The same membership rules apply, and it is limited to 20 calls per hour per user.
  • DELETE /bank-accounts/{id} removes the account and returns true. Transactions that already reference it are not affected. The same membership rules apply.

What's next

Add a wallet if the transaction has a crypto leg, then create a transaction.

On this page