BBankConnectorDeveloper Docs

Core Concepts

Audience: ๐Ÿ”Œ Integration Client ยท ๐Ÿ—๏ธ Platform Operator

Five ideas explain almost everything about integrating with BankConnector.

1. The tenancy model

Platform โ†’ Company โ†’ (bank connections, accounts, payments, webhooks)

As an integration client you operate as one company. Your API key fixes the platform; you name the company in each call.

2. You send canonical JSON, not XML

You never author ISO 20022 XML. You send a canonical payment instruction โ€” a clean, bank-agnostic JSON object โ€” and BankConnector's engine:

  1. validates it (structure, then generic rules, then bank rules, then payment-type rules),
  2. applies your saved bank settings (charge bearer, execution-date offset, etc.),
  3. converts it to the correct pain.001 flavour for the target bank,
  4. queues it for asynchronous delivery.

The same canonical object works across banks; the engine handles the per-bank dialect.

3. The canonical payment instruction

One instruction contains one or more payments (each becomes a PmtInf), and each payment contains one or more transactions (each becomes a CdtTrfTxInf).

PaymentInstruction
โ”œโ”€โ”€ messageId                 (required, โ‰ค35 chars โ€” your dedup handle)
โ”œโ”€โ”€ initiatingParty { name, organisationId? }
โ””โ”€โ”€ payments[]  (1..1000)
    โ”œโ”€โ”€ paymentId              (required, โ‰ค35)
    โ”œโ”€โ”€ paymentType            ("sepa", "domestic", "international", ...)
    โ”œโ”€โ”€ executionDate          (required, "YYYY-MM-DD", a real calendar date)
    โ”œโ”€โ”€ debtor  { name, country?, account, agent? }
    โ””โ”€โ”€ transactions[]  (1..10000)
        โ”œโ”€โ”€ endToEndId         (required, โ‰ค35)
        โ”œโ”€โ”€ amount             (required, STRING โ€” see below)
        โ”œโ”€โ”€ currency           (required, ISO 4217)
        โ”œโ”€โ”€ creditor { name, account, agent? }
        โ””โ”€โ”€ remittance?        (structured or unstructured)

A complete, valid example

{
  "messageId": "ORDER-2026-10432",
  "initiatingParty": {
    "name": "Acme Holding",
    "organisationId": { "id": "NL-1", "scheme": "CUST" }
  },
  "payments": [
    {
      "paymentId": "p1",
      "paymentType": "sepa",
      "executionDate": "2026-07-15",
      "debtor": {
        "name": "Acme Holding",
        "country": "NL",
        "account": { "iban": "NL91ABNA0417164300", "currency": "EUR" },
        "agent": { "bic": "ABNANL2A" }
      },
      "transactions": [
        {
          "endToEndId": "e1",
          "amount": "1250.00",
          "currency": "EUR",
          "creditor": {
            "name": "Supplier BV",
            "account": { "iban": "FR1420041010050500013M02606" },
            "agent": { "bic": "BNPAFRPP" }
          },
          "remittance": {
            "creditorReference": { "type": "scor", "value": "RF18539007547034" }
          }
        }
      ]
    }
  ]
}

Field rules that trip people up

These are the ones worth reading twice. The full catalog is in Validation Reference.

4. Payments are accepted synchronously, delivered asynchronously

POST /journal/payments does validation, conversion, and approval-planning synchronously and returns 201 with the converted document and its XML. But the send to the bank is always asynchronous, via a transactional outbox and a delivery worker. The bank's acknowledgement (pain.002) arrives later still.

So a 201 tells you the payment is well-formed and accepted. It does not tell you the bank received or executed it. You observe that through the payment lifecycle, via webhooks or polling.

The payment lifecycle

converted โ”€โ”ฌโ”€โ–ถ pending-approval โ”€โ–ถ queued-for-delivery โ”€โ–ถ sending โ”€โ–ถ sent
           โ”‚                                                          โ”‚
           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ queued-for-delivery          โ–ผ
                                                              validated / executed
    (any stage) โ”€โ–ถ sanctions-hold                             partially-accepted
                โ”€โ–ถ delivery-failed                            rejected
                                                              cancelled

5. You learn results by webhooks or polling

Two supported patterns, covered in Receiving Results:

Most robust integrations use webhooks for latency and a periodic poll as a safety net.

Bank keys

A bankKey is <bank>-<country-code> โ€” the country code is part of the key so the same bank in different countries resolves to its own profile (e.g. jpmorgan-us, and other JPMorgan country flavours), each with its own BIC, pain version, payment types, and rules. This convention is enforced at startup.

BankConnector's bank registry covers hundreds of banks across dozens of countries and grows continuously โ€” the authoritative, current list is always GET /profiles, not a number written down here.

Backward-compatible aliases. A few keys were historically bare (no country suffix); they still resolve to their canonical form, so existing integrations keep working:

Legacy keyCanonical key
jpmorganjpmorgan-us
danske-bankdanske-dk
deutsche-bankdeutsche-bank-de