API versioning & compatibility
BankConnector's HTTP API is versioned by date, via the BankConnector-Version header, never a /v1 path prefix.
BankConnector-Version: 2026-06-01
How versioning works
How the header is read:
- Every response echoes back the version it was served under, error responses and
401included, so you can confirm what you are pinned to at a glance. - With no header you get
2026-06-01, the oldest version we serve, not the newest. That is deliberate: an integration that never pinned anything must not be moved underneath. Send the header. - A date resolves to the newest version published at or before it. A date before
2026-06-01resolves to2026-06-01; a date after the newest resolves to the newest. - A header that is not a
YYYY-MM-DDdate is400 validation_failed.
What a pinned version covers
The header changes one thing: how a refused request is answered, which status and code (the versions below). Every other change to the API applies to every version at once, whichever you pin.
- A removed or renamed path, field or code, and a changed status, are announced in Contract changes below under the month they ship. We do not promise that a pinned version stays unchanged beyond the refusals, so watch that page.
- Additive changes (new optional request fields, new response fields, new endpoints, new enum values) may appear without notice. Build tolerant clients: ignore unknown fields, handle a status or enum value you have not seen, and branch on
code, notmessage.
Current version: 2026-10-21
- A connection request refused for the connection's state is
409 invalid_state, notvalidation_failed: the request was fine, and the connection needs another step first. See 2026-10-21 below. - A request body we read but cannot use is
422, not400, on every route, with each problem on its field inerror.details.issues, and a field the route does not read is refused rather than dropped. See 2026-10-20 below. - A payment we cannot process is
422, not400.400means we could not read your request at all (not JSON, a bad header);422means the request was fine and the payment inside it is not something we can accept, with the reasons inerror.details.issues. See 2026-08-25 below, and Errors & Retries. - Canonical input schema
1.1(additive over1.0: structuredpostalAddress,regulatoryReporting, andpurposeCode/localInstrument/categoryPurposeoverrides; see Core Concepts). - Object error envelope:
{ error: { code, message, details? } }on every non-2xx response (see Errors & Retries). - Standard list envelope:
{ items, nextCursor?, total? }across all list endpoints (see Pagination). - One word for "you have pulled this document":
collected. On the journal read surfaces (GET /journal/listandGET /journal/documents) each item carriescollected/collectedAt, the/journal/listenvelope carries anuncollectedcount, and the filters are?uncollectedOnly=trueand?collected=true|false. See Receiving Results.
Versions
Four versions can be pinned with BankConnector-Version. They differ only in the refusals described here; every other change on this page applies to all of them.
2026-10-21
Pin this version to tell a refused request apart from a connection that is not ready. A connection request can be refused because of what it sends, or because the connection is not at a point that allows it yet: a setup step or field not done, keys not sent, live when the action needs it deactivated, or a channel the action does not apply to. On this version the second is 409 invalid_state.
| Refusal | 2026-06-01, 2026-08-25 | 2026-10-20 | 2026-10-21 |
|---|---|---|---|
| the connection is not ready for the request | 400 validation_failed | 422 validation_failed | 409 invalid_state |
| a value cannot be used: missing or malformed in the request, or stored but malformed | 400 validation_failed | 422 validation_failed | 422 validation_failed (unchanged) |
The message is the same on every version and names the step to take first. The routes are POST /connections, the connection setup actions under /connections/{id}, the certificate and credential uploads, and GET /connections/{id}/ebics-letter. On POST /connections/{id}/ws-certificate, a connection that does not use Web Services is 409 invalid_state and a family that is not the connection's own is 422 on this version; both stay 400 on every earlier version.
What to do:
- If you branch on the status of a connection action, handle
409 invalid_state: show the message, and do not retry the same request until the step it names is done. - Nothing forces you to move. Keep sending
2026-10-20and you keep422.
2026-10-20
Pin this version to get the same line for every other request body. A body that is valid JSON but not what the route takes (a wrong type, a value out of range) is 422 validation_failed, and a field the route does not read is refused with 422 instead of being dropped, so a misspelt field is an answer rather than a success that changed nothing.
| Request | 2026-06-01, 2026-08-25 | 2026-10-20 |
|---|---|---|
| a body that fails the route's schema | 400 | 422 |
| a body with a field the route does not read | accepted, the field dropped | 422, the field named |
| a body that is not JSON | 400 | 400 (unchanged) |
On every version, each refusal lists its problems in error.details.issues, one { "path", "message" } per problem, where path names the field (rules[0].amountFrom). companyId is accepted on every body; a platformId is refused 400 invalid_parameter on every version on a route that needs a credential (see October 2026). A public route (/auth/login, /signup and the like) refuses it like any other unknown body field. POST /payment-types/suggest keeps reading a whole payment and ignoring the fields it does not use.
What to do:
- Send only the fields each route documents before you move your pin.
- If you branch on the status, handle
422wherever you handle a refused write. - Nothing forces you to move. Keep sending
2026-08-25and you keep the400and the dropped field.
2026-08-25
Pin this version to get a clear line between the two client errors. A payment body that arrives as valid JSON but is not a valid canonical payment (a missing required field, a wrong type, a null where an object belongs) is 422 validation_failed, with every problem listed in error.details.issues. On 2026-06-01 the same defect is 400 on some routes and 422 on others.
| Request | 2026-06-01 | 2026-08-25 |
|---|---|---|
POST /journal/payments, a transaction with no creditor account | 400 | 422 |
POST /journal/payments/preview, same body | 400 | 422 |
POST /convert/{bank}, body null, 42, [] or {"payments":[null]} | 400 | 422 |
POST /convert-async/{bank}, same bodies | 400 | 422 |
POST /validate/{bank}, same bodies | 400 | 200, valid: false |
| a payment that parses but breaks a rule | 422 | 422 (unchanged) |
| a body that is not JSON at all | 400 | 400 (unchanged) |
The boundary is one sentence: 400 means we could not read your request, and 422 means we read it and the payment is not one we can process. Neither is retryable as sent.
POST /validate/{bank} is a report endpoint, so it reports a schema failure inside its 200, as { "valid": false, "issues": [...] }, the same way it reports every other problem. That lets it tell you in advance what POST /convert/{bank} will answer.
What to do:
- If you branch on the status, handle
422wherever you handle a rejected payment, and read400as "my request was malformed" only. - If you read
error.details.issues, nothing changes: it is in the same place under both statuses and both versions. - If you treat a non-
200fromPOST /validate/{bank}as "could not validate", readvalidinstead. This is the one change that could make a rejection look like a success, so it is the one to search your code for. - Nothing forces you to move. Keep sending
2026-06-01and you keep the400answers.
2026-06-01
The baseline, and the version you get when you send no header. A payment that fails the schema check is 400 on POST /convert and POST /convert-async, for every shape of failure.
Contract changes
This page lists the changes to the HTTP contract that you might need to act on or would want to use, one overview per month. A breaking change takes effect for every version, so watch this page whichever version you pin. A removal, a rename or a changed status is marked as such in the month's overview. Small additions, such as a new optional field, appear in the API Reference and are not repeated here.
November 2026
November so far tightens one approval-policy rule and retires the sandbox's one-call provisioning.
- Removed:
POST /sandbox/provisionandPOST /sandbox/provision/verify, on every version; both answer404. Get a sandbox by signing up athttps://sandbox.bankconnector.com/signupand create an API key under Company settings › API keys. See Getting started. - Changed:
POST /approvals/policiesandPOST /approvals/policies/{id}refuse acustompolicy withorderedApproval: trueunless at least two entries ofgroupseach have anameand an approver, withvalidation_failedongroups. Send a second named step, ororderedApproval: falsefor a policy one approver may release. - Changed: on
POST /journal/payments, a retry that arrives while the sameIdempotency-Keyorpayment.messageIdis still being processed answers409 request_in_progress, not409 conflict, on every version. Retry it unchanged after a short wait.409 conflictnow means only that the key ormessageIdwas used with a different body: never retry that as it is. Branch oncode; the message text is no longer needed to tell them apart. See Errors & retries. - Changed: on the sandbox, a payment waits for approval as it does in production once your company has an active approval policy for the bank:
POST /journal/paymentsanswerspending-approvalandPOST /journal/payments/previewsaysapproval.required: truewhen that policy requires it. While no policy is active, the sandbox still releases payments without approval. Production is unchanged. - Changed:
POST /journal/documents/{id}/signer-releasereleases or cancels a held payment only for an approver the approval policy governing the payment's bank names, in the browser and the ERP add-on. Anyone else, an Approver invited from the ERP and not yet named included, is409 approver_not_designated, andGEToffers them no act, with that code inrefusal.
October 2026
October added follow-up for payments the bank has not settled, a verification-only file for checking payees, and signup that waits for approval. A client that matches on a removed path, field or code must change; the rows say what to do.
| Kind | Endpoint | What to do |
|---|---|---|
| Changed | POST /users | An email address whose login belongs to another organisation answers the same 201 as a new invitation, not 409 conflict. No login is made: the person is listed in GET /users as invited, and a second invite of the address is 409 conflict. An address already in your own organisation is still 409 conflict. |
| Changed | POST /signup, POST /partners/register | An email address that already has a BankConnector login answers the same 202 as a new address, not 409 conflict; its owner is emailed how to sign in. POST /partners/register no longer answers 502 email_send_failed: resend a link that did not arrive with POST /partners/register/resend. |
| New status | POST /signup/verify, every authenticated request | A self-service signup waits for BankConnector to approve it. POST /signup/verify answers 200 with awaitingApproval: true and no API key; until the approval email arrives, POST /auth/login and every authenticated request of that organisation answer 403 forbidden. Treat awaitingApproval as "no credential yet". |
| New | POST /users/{id}/sign-out | An Admin ends every live session of a colleague. Answers 200 with revoked, the sessions ended. |
| Changed | DELETE /me/sessions, DELETE /me/sessions/{id} | Signing out another of your sessions asks for a fresh factor in the JSON body: a current 2FA code (or backupCode) when you have two-factor authentication, otherwise your current password. Without it the answer is 422 (totp_required, totp_enrollment_required or reauth_required). Signing out the calling session needs nothing. |
| Removed | GET /bank-coverage-requests/demand, PATCH /bank-coverage-requests/{id} | Both refused every caller with 403 and now answer 404. GET and POST /bank-coverage-requests are unchanged. |
| Removed | password on POST /users | The route only invites; the person sets their own password from the emailed link. On 2026-10-20 and later a password is refused as an unknown field (422); on an older pin it is ignored. Stop sending it. |
| Changed | Sandbox | Every pain.001 file is built in pain.001.001.09 whatever the bank, and ?painVersion= on the conversion routes is ignored. A bank's payment types are listed only once your organisation has a connection to that bank: GET /profiles leaves paymentTypes out for the others, and GET /banks/{bankKey}/payment-types answers 403 forbidden. Production is unchanged. |
| Changed | Bank setup guides | Webhooks can subscribe to a new event, bank-guide.access-revoked: we withdrew an approved bank guide request, and the bank's guide is locked again unless your organisation has a connection to it. Danske, Bank Connect, Nordea Corporate Access and OP banks stay open to every organisation. |
| Changed | POST /journal/documents/{id}/signer-release | Releases or cancels a payment a German or Austrian bank holds after its payee check (awaiting-signer-release) on an EBICS connection with authorisationMode: "at-upload", the default. An Approver reads the result and decides, and the company's EBICS subscriber signs. It answered 422 ebics_signer_missing there. |
| Added | GET /journal/list, GET /journal/documents | Each row carries environment ("test" or "production"). A bank's test system can send statements for a real account; an integration that books statements skips the "test" rows. |
| Changed | file.received event | No longer raised for an EBICS customer protocol (HAC) that finally refused no order; every poll fetches one. The document is still stored. A protocol that did refuse an order still raises it. If you counted file.received as proof of a successful poll, count something else. |
| Added | POST /webhooks | transport: "teams" posts each event into a Microsoft Teams chat or channel as a card; see Webhooks. A webhook's transport can now read "teams". |
| Changed | POST /webhooks | eventTypes refuses with 400 validation_failed an event name only our own staff chain writes (partner.created, bankkey.imported and the like), as it refuses an unknown name. No customer endpoint ever received these. GET /webhooks reports one an endpoint already holds in unknownEventTypes; remove it to clear the warning. |
| Changed | "*" webhook subscription | A "*" subscription (or one created without eventTypes) receives the events in the event catalog and no others. To keep receiving an event the catalog does not list, name it in eventTypes. |
| Changed | Every route that needs a credential | A request that states platformId, in the query string or the JSON body, answers 400 invalid_parameter naming the parameter, on every version. A public route refuses it like any other unknown body field. Name the organisation with companyId alone, and send no platformId, not even an empty one. |
| Changed | POST /connections/{id}/ebics-hev, ebics-send-ini, ebics-fetch-hpb and the other EBICS setup steps | A call to the bank that fails, including a host name that does not exist, answers 502 bank_unavailable with error.details.nextSteps. It answered 500 internal_error. |
| Changed | POST /approver-identity | A fødselsnummer that is not valid, or a District user ID that is empty or over 35 characters, is validation_failed (422 on 2026-10-20, 400 before it). It answered 422 on every version. |
| Changed | POST /company/require-2fa | A body without enabled is validation_failed (422 on 2026-10-20, 400 before it). It read a missing enabled as false and turned the requirement off. Send "enabled": false to turn it off. |
| Changed | POST /connections/{id}/approvers | An approval-governance refusal has its own code (409 policy_change_in_flight, 422 policy_quorum_shortfall, 400 policy_roster_invalid), as on POST /approvals/bank-rosters. It answered 500 internal_error. |
| New | GET /banks/{bankKey}/sftp-naming | Answers the server, logins, folders and payment file name a TietoEvry bank's agreement gives (SpareBank 1, Eika and the other savings banks on TietoEvry's shared SFTP), before anything is saved. A bank whose setup guide your organisation has not been given answers 403 bank_guide_access_required, as POST /connections does. |
| New | GET /profiles/members | Lists the Sparkassen and cooperative banks (Volksbanken, Raiffeisenbanken) the German group profiles serve, each with its town, BIC, bank codes and bankKey. Match a customer's bank name, BIC, bank code or IBAN against it, and save the member with memberBankCode on PATCH /banks/{bankKey}/settings. |
| Changed | PATCH /banks/{bankKey}/settings | A memberBankCode that would change the member bank of a group profile the company has a connection on, or a setup in progress for another member, answers 409 member_bank_locked. The first choice, and sending the stored member again, pass. |
| New version | All routes | 2026-10-21: a connection request refused because the connection is not ready is 409 invalid_state; a value that cannot be used stays 422 validation_failed. See 2026-10-21. |
| New version | All routes | 2026-10-20: a request body that fails its route's schema is 422, and a field the route does not read is refused, naming the field. See 2026-10-20. |
| Changed | POST /users, connection routes | A refusal carries one code wherever it is raised. POST /users answers 409 conflict for an email address already registered (it was 400 bad_request). A connection route naming an unknown or deleted connection answers 404 connection_not_found (some answered 400 validation_failed or 404 not_found). On 2026-10-20 a connection's validation_failed refusal is 422. |
| Changed | GET /connections/{id}/ebics-letter | Before the subscriber keys exist: 409 invalid_state on 2026-10-21, 400 validation_failed on earlier versions (it was 404). |
| Changed | POST /connections/{id}/ebics-params | A new signatureVersion once the EBICS connection's keys went to the bank is refused and saves nothing: 409 invalid_state on 2026-10-21, 400 validation_failed before. It saved the version before, and the next upload was signed in a version the bank had not registered. Set the version before you send the keys. |
| Changed | POST /connections/{id}/server-info | An SFTP host-key pin that is not a SHA-256 fingerprint (hostFingerprint, downloadHostFingerprint) is refused and nothing is saved: 422 validation_failed on 2026-10-20, 400 before. Send SHA256: plus base64 or 64 hex characters; either is stored as SHA256: plus unpadded base64. |
| Changed | GET /webhooks/{id}/deliveries, POST /webhooks/{id}/redeliver-failed | A different nextCursor (still opaque), a malformed cursor is 400 invalid_cursor, and the last page ends with nextCursor: null, even when exactly full. A cursor issued before this change, or built from a delivery's id, is malformed: pass nextCursor back as it came. redeliver-failed refuses a since that is not a real ISO-8601 date or time with 400 invalid_since. |
| Changed | GET /accounts, GET /company/api-keys, GET /me/organisations, GET /approvals/pending, GET /approvals/oversight | A different nextCursor (still opaque), and a malformed cursor is 400 invalid_cursor. A cursor issued before this change, or built from an item's id, is malformed: pass nextCursor back as it came. The two approval lists end with nextCursor: null on the last page, even when it holds exactly limit requests. |
| Changed | GET /journal/documents, /journal/list, /journal/events, /journal/reconciliation, GET /bank-coverage-requests | A list's last page carries nextCursor: null even when it holds exactly limit items. GET /bank-coverage-requests refuses a malformed cursor with 400 invalid_cursor; a cursor it issued before this change is malformed. |
| Renamed | Remittance warning codes | Four warnings carry one code each, whatever bank or standard raises them, on every version: BANK_REMITTANCE_DOCUMENTS_AS_TEXT, BANK_REMITTANCE_ADDITIONAL_INFO_NOT_SENT, BANK_REMITTANCE_TEXT_NOT_SENT and BANK_REMITTANCE_TEXT_JOINED. The old spellings had a bank or standard in the prefix (BANK_SE_, BANK_SEPA_, BANK_NPC_, BANK_NL_). Message, path and severity are unchanged. If you match on an old code, match on the new one. |
| Renamed | Validation issue codes | 64 codes take their level's prefix, BANK_ on a bank issue and PAYMENT_TYPE_ on a payment-type issue, on every version, and only the prefixed spelling is sent (NEMKONTO_DKK_ONLY is BANK_NEMKONTO_DKK_ONLY). If you match on any of them, match on the prefixed code. The list is at the end of this month. |
| Changed | messageId, paymentId, endToEndId, instructionId | An id made only of whitespace or invisible characters (the zero width space, the soft hyphen), or only of emoji or control characters, is refused as a schema failure naming the field, because the payment file would carry an id that reads as empty. /convert answered 200 with an empty id element before. Such characters beside other characters are accepted, and emoji are written without the emoji. |
| Changed | Every list route | A value that is not allowed (type, direction or status outside its set) or a limit that is not a number answers 400 invalid_parameter, naming the parameter, instead of an empty or unfiltered page. GET /approvals/pending and GET /approvals/oversight page with cursor, as every other list does; after still works. To poll for documents use GET /journal/list?uncollectedOnly=true. |
| New status | POST /connections/{id}/ws-certificate | With action: "renew", answers 409 renewal_in_progress while another renewal of the same connection is running. Nothing reached the bank; read the connection again after a minute for the new expiry. |
| Added | Reference | Already served, now in the API reference: GET /approvals/policy, GET /journal/documents/{id}/raw-pain002 (the bank's original pain.002 status report) and POST /payment-types/suggest. |
| Removed | The twelve Web Services certificate paths | POST /connections/{id}/activate-danske, /activate-nordea, /activate-op, /activate-samlink, /activate-crosskey, /activate-bankconnect and the six /renew-* paths now return 404. Use POST /connections/{id}/ws-certificate with action (activate or renew) and family, the kind that GET /banks/{bankKey}/setup-info serves for the bank. Fields and errors are the same, except that an unknown connection answers 404 connection_not_found and a family that is not the connection's own is 400 validation_failed. Only a signed-in Admin calls it. |
| Changed | GET /accounts/statements | One page of the list envelope: items replaces statements, and nextCursor (pass it back as ?cursor=, ?limit= up to 500) points at the next older page. account and gaps stay; each page's gaps are the ones whose later statement is on that page. Follow nextCursor until it is null. |
| Removed | GET /version | Answers as any unknown path does. The API reference's version is the contract date you send in BankConnector-Version. |
| Changed | PATCH /company/name, GET /company/legal-identity | An Admin renames their own organisation with PATCH /company/name. GET /company/legal-identity needs a signed-in Admin; an API key gets 403. To erase an organisation or hold its data, ask us. |
| Removed | guide.fieldCopy, bankConnect.fieldCopy on GET /banks/{bankKey}/setup-info | Each entry of fields[] carries the same label, placeholder and help, in the order the enrolment form asks for them. |
| Removed | approval.limitEquivalence on the POST /journal/payments response | The response's approval is the request as GET /approvals/pending shows it. |
| Removed | grantsRevoked on DELETE /connections/{id}; the granted value of reachableBanks[].access on GET /dashboard; the event connection.grant-withdrawn | A bank connection belongs to one organisation and is not shared with another. |
| Removed | platformId | Gone from every response and from the webhook envelope, on every version. Key on companyId. A request that states it is refused (see the platformId row above). |
| Renamed | POST /connections/{id}/platform-bank-key | Now POST /connections/{id}/registry-bank-key (the old path returns 404); a connection's usePlatformBankKey is useRegistryBankKey and platformBankKey on GET /connections/{id} is registryBankKey. Each still means BankConnector's copy of the bank's PGP key, and each connection keeps its choice. |
| Removed | Approval policy versions | A policy keeps one id and is changed in place, so version, predecessorId and supersededById are gone and status is draft or active. POST /approvals/policies/{id}/propose and POST /approvals/changes/{changeId}/submit return 404; a pending policy change is the kind policy-edit with its proposed rule in proposed; the error code policy_superseded is retired. |
| New status | POST /signup | The company register must find the company. A number it does not know, or lists as inactive, is 422 on registrationNumber; a register that gives no answer is 503 service_unavailable naming the number's field, and the same signup can be sent again in a moment. A country with no register lookup signs up with the name and address as sent. Send the lookup's registerAnswer back with the signup. |
| New status | POST /journal/ingest, POST /inbound/statement | A statement file stating an amount or credit/debit indicator we cannot read is 422 incomplete_statement, and error.details.parseIssues names each field. Nothing from the file is stored. A file of this kind fetched from the bank sends no statement.imported; we keep it and deliver it once we can read it. |
| New state | Reconciliation | State unconfirmed appears once a bank report is 5 banking days overdue. Check with the bank before paying again; see Receiving Results. |
| New | GET /journal/payments/batch?messageId= | Shows what BankConnector holds for a batch you sent and got no answer for. Only not-found means you may send it again, under a new messageId. |
| Added | resendOf on a payment | Link a re-issued payment to the refused one; the original batch's GET /journal/documents/{id}/payments then reports refusals. |
| New | POST /journal/payee-verifications | Checks payees with a verification-only file; the results arrive as a file.received event. |
| New value | company.inactiveReasons in a company register lookup | Can read insolvency. A UK company number is looked up in Companies House on POST /signup/register-lookup and POST /partners/register/lookup. |
| New | GET /banks/live | Lists the banks your organisation has an active connection to, per environment. |
| Changed | GET /journal/documents | Without limit returns up to 1000 documents a page with a nextCursor to follow; a malformed cursor is 400 invalid_cursor with or without limit. |
| New | GET /journal/documents/{id}/export.camt053 | Returns a bank statement as camt.053.001.02 for an ERP's own statement import, whatever format the bank sent and after its original file has expired. |
| New | POST /connections/{id}/intraday-report | Fetches the bank's intraday account report (camt.052) now. A connection asks its bank at most once per 15 minutes: a request inside them gets the last report again, with reused: true and its fetchedAt. |
| Changed | Norwegian savings banks | The SpareBank 1 and Eika banks are each listed under their own key and name (for example jaeren-sparebank-no), and eika-alliance-no and sparebank-1-alliance-no are removed. Connect to the customer's own bank; its setup takes the bank ID from knownServer.bankId on GET /banks/{bankKey}/setup-info. |
| Changed | POST /connections/{id}/activate, DNB Norway | Refused for a dnb-no connection until its customer number, division number and the certificate that signs its payment files are on it; asks for no PGP keys. PUT /connections/{id}/asic-signing-material answers 400 validation_failed for a certificate and key that could not sign a payment file. |
| Changed | POST /connections/{id}/activate, SpareBank 1 and Eika | Refused for a connection that runs through TietoEvry until its PGP key pair is generated, TietoEvry's PGP public key is added and the SFTP password TietoEvry issued is stored. Setup asks for all three (GET /banks/{bankKey}/setup-info). |
| Changed | SpareBank 1 company settings | A company's noApproverCodesEnabled starts true on its first settings save at a SpareBank 1 bank (for example sr-bank-no), as at Nordea Norge, Danske Bank Norge and DNB. If the company approves in the bank's netbank, send false on that first save. Companies already connected keep their answer. |
| Changed | POST /connections/{id}/ebics-fetch-hpb, POST /connections/{id}/activate | Once the EBICS connection has gone live, ebics-fetch-hpb is refused before it contacts the bank (409 invalid_state on 2026-10-21, 400 validation_failed before), and activate refuses a deactivated EBICS connection the same way. Fetch a live connection's bank keys with POST /connections/{id}/ebics-refetch-hpb, which shows changed fingerprints and stores new keys only when you accept them. |
| New status | POST /connections/{id}/ebics-fetch-hpb | 409 ebics_bank_keys_untrusted when the bank's EBICS keys are refused: a published fingerprint that does not match, a key-management mode the bank publishes no fingerprints for, or an answer naming another Host ID. details.reason says which. These answered 500 before; nothing is saved either way. |
| Changed | POST /connections/{id}/ebics-fingerprints-confirmed | 409 ebics_bank_keys_untrusted (details.reason: fingerprint_mismatch) when the connection's bank keys differ from a fingerprint the bank publishes. It recorded a confirmation before; now nothing is recorded, and the next step is to fetch the bank's keys again. |
Renamed validation issue codes
36 codes take their level's prefix. Each keeps its old spelling after the prefix (ACH_ROUTING_REQUIRED is PAYMENT_TYPE_ACH_ROUTING_REQUIRED): ACH_ROUTING_FORMAT, ACH_ROUTING_REQUIRED, CH_QR_REFERENCE_CHECKDIGIT_INVALID, CH_QR_REFERENCE_REQUIRED, EFT_CAD_ONLY, EFT_CREDITOR_ACCOUNT_REQUIRED, EFT_ROUTING_REQUIRED, BANK_OFFERS_NO_PAYMENT_TYPES, ING_NL_CTGYPURP_IGNORED, NVB_INITIATING_PARTY_NAME_OR_ID, TRUIST_LCLINSTRM_REQUIRED, USBANK_DEBTOR_AGENT_ID_REQUIRED, BANKCONNECT_BEC_NON_BANKING_DAY_REJECTED, CREDITOR_REFERENCE_TYPE_MISSING, DE_AXZ_LOCAL_INSTRUMENT_DROPPED, DE_CCU_CHARGE_BEARER_SUBSTITUTED, DE_CCU_LOCAL_INSTRUMENT_PROPRIETARY_DROPPED, DK_ADDRESS_COUNTRY_ONLY_DROPPED, DK_ADDRESS_ULTIMATE_PARTY_DROPPED, DK_ADDRESS_ULTIMATE_PARTY_OMITTED, DK_FIK_KORTART_NOT_OFFERED, FIXED_CREDITOR_AGENT_COUNTRY_OVERRIDDEN, FI_ADDRESS_HYBRID_TOO_MANY_LINES, FI_INVOICES_WITHOUT_CREDIT_NOTE_NOT_ERI, FR_ADDRESS_LINES_ONLY, NEMKONTO_DKK_ONLY, NEMKONTO_DOMESTIC_ONLY, NL_ADDRESS_LINES_ONLY, PROFILE_HMRC_RTI_REFERENCE_NOT_SENT, PROFILE_SERVICE_USER_NUMBER_CONFLICT, PROFILE_SERVICE_USER_NUMBER_NOT_SENT, PROFILE_SERVICE_USER_NUMBER_OVERRIDDEN_BY_ULTIMATE_DEBTOR, SEPA_INSTANT_PAIN_VERSION_UNSUPPORTED, SEPA_NON_EEA_DEBTOR_ADDRESS_INCOMPLETE, SEPA_NON_EEA_DEBTOR_COUNTRY_REQUIRED, SEPA_REMITTANCE_TEXT_NOT_SENT.
28 more take the BANK_ prefix the same way: ADDRESS_DERIVATION_COUNTRY_MISSING, ADDRESS_DERIVATION_COUNTRY_UNSUPPORTED, ADDRESS_DERIVATION_POSTCODE_CONFLICT, ADDRESS_DERIVATION_TOO_MANY_LINES, ADDRESS_DERIVATION_TOWN_AMBIGUOUS, ADDRESS_DERIVATION_TOWN_NOT_FOUND, ADDRESS_DERIVATION_TOWN_TOO_LONG, ADDRESS_DERIVATION_VERSION_UNSUPPORTED, DEBTOR_ADDRESS_NOT_FILLED_COUNTRY_CONFLICT, DEBTOR_ADDRESS_NOT_FILLED_NO_REGISTERED_ADDRESS, DEBTOR_ADDRESS_NOT_FILLED_OTHER_PARTY, DENMARK_ADDRESS_COUNTRY_REQUIRED, DENMARK_ADDRESS_HYBRID_TOO_MANY_LINES, DENMARK_ADDRESS_TOWN_REQUIRED, DK_ADDRESS_COUNTRY_REQUIRED, DK_ADDRESS_LINE_TOO_LONG, DK_ADDRESS_TOO_MANY_LINES, DK_ADDRESS_TOWN_REQUIRED, FI_ADDRESS_COUNTRY_REQUIRED, FI_ADDRESS_TOWN_REQUIRED, FI_URGENT_LOCAL_INSTRUMENT_CONFLICT, FI_URGENT_SALARY_NOT_INSTANT, FI_URGENT_SEPA_INSTANT_UNAVAILABLE, SEPA_REMITTANCE_ADDITIONAL_INFO_NOT_SENT, SEPA_REMITTANCE_ADDITIONAL_INFO_UNSUPPORTED, SEPA_REMITTANCE_DOCUMENTS_AS_TEXT, SEPA_REMITTANCE_TEXT_AND_REFERENCE, SEPA_REMITTANCE_UNSTRUCTURED_REPEATED.
September 2026
September added payment states to handle, a banking-day lookup and the bank's payee check for German and Austrian SEPA files.
- Removed fields:
approverUserIdson connections (readGET /approvals/bank-rosters),payload.rawXmlonGET /journal/documents/{id}(fetchGET /journal/documents/{id}/file, see Receiving Results). The approver's masked ID isssnFirst6, notssnLast4. - New states to handle: payment status
awaiting-signer-release(at the bank, waiting for your signers), payment statusrejected-by-approver(final, never sent), reconciliation statenot-sent(the bank never received it) and statement statusunknown(an entry code we do not recognise, never treated as settled money). See Receiving Results. - Changed:
GET /profileslists each bank'spaymentTypesas codes, and one-time links carry their token after#. - Submitting payments: a
messageIdis one payment, so re-sending one returns the original, or409 message_id_already_usedwhen that payment was rejected or cancelled; send a corrected payment under a newmessageId. From 30 days past due,POST /journal/paymentsanswers402 billing_past_due, and an unpaid invoice adds aBankConnector-Billing-Warningheader to every response. GET /banking-days/adjustreturns the banking day on or next to a date. A SEPA file to a German or Austrian EBICS bank goes out with the bank's payee check, set for multi-payment files byGET/PATCH /company/payee-verification.
August 2026
Show the August changes
August introduced dated versions and made the journal's names consistent.
- Removed:
/bank-requestsis now/bank-coverage-requests, and the old path returns404. - Removed and renamed fields: whole-document responses no longer return
slaAlertSentAtorsideEffectsCompleted, andretrieved,retrievedAt,unretrievedandwasAlreadyRetrievedarecollected,collectedAt,uncollectedandwasAlreadyCollected, with matching filters. - New version
2026-08-25: a payment we cannot process is422, not400. See 2026-08-25.