sandbox.bankconnector.com API Reference

Operate / Operator API reference

Operator API reference

The setup & administration endpoints an operator or workspace admin uses to stand a tenant up and keep it running: bank connections and channel activation, approvals, users, workspace/company admin, and session sign-in. These are session-authenticated (an X-API-Key gets 403); the day-to-day integration surface is in the API reference.

Download the spec: openapi.json, openapi.yaml. The full spec covers both tracks.

Connections

Bank connection setup, channel activation, and EBICS onboarding (session-authenticated, Admin only)

GET/connectivity/profiles
List connectivity profiles (channel info per bank)

Read-only metadata: which channel each bank uses (sftp / danske-ws / nordea-ca / bankconnect / ebics), its known server and endpoint details, and SFTP wizard config. No auth required. Pass view=badge for the catalogue projection (bankKey, bankName, channelType and webservice.wsVariant only), which is an order of magnitude smaller. A deployed sandbox always answers the badge projection, whether or not view was passed.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
view enumqueryno`badge` projects each row down to identity + channel badge. Omit it for the full connection declaration. Any other value is a 400 `invalid_parameter`.
Responses
StatusDescription
200Connectivity profiles
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "bankKey": "string",
      "bankName": "string",
      "channelType": "sftp",
      "stepper": "sftp",
      "sftp": {
        "gateway": "tietoevry",
        "bankId": "string",
        "host": "string",
        "port": 0,
        "uploadPath": "string",
        "downloadPath": "string",
        "testHost": "string",
        "testPort": 0,
        "testLoginDiffers": false,
        "downloadHost": "string",
        "usernameHint": "string",
        "uploadTemplate": "string",
        "downloadPattern": "string",
        "additionalDownloadPaths": [
          "string"
        ],
        "deletesOnDownload": false,
        "minPollIntervalSeconds": 0,
        "instantUploadPrefix": "string",
        "uploadExtension": "string",
        "inputs": [
          {}
        ],
        "sshKeyBits": 0,
        "pgpKeyBits": 0,
        "dualAuth": false
      },
      "webservice": {
        "wsVariant": "danske",
        "endpoint": "string",
        "pkiEndpoint": "string",
        "receiverId": "string",
        "environment": "TEST",
        "environmentEvidence": {
          "basis": "string",
          "source": "string",
          "checkedOn": "string",
          "detail": "string"
        },
        "registrationNumber": "string",
        "setupFields": {
          "add": [],
          "remove": [],
          "copy": {}
        },
        "minPollIntervalSeconds": 0
      },
      "ebics": {
        "gateway": "multivia",
        "url": "string",
        "hostId": "string",
        "bic": "string",
        "signatureVersion": "A005",
        "supportedVersions": [
          "2.1"
        ],
        "keyLengthBits": 0,
        "sepa": {
          "sct": false,
          "cor": false,
          "b2b": false,
          "scc": false
        },
        "bankKeyHashes": {
          "authentication": "string",
          "encryption": "string"
        },
        "certHashes": {
          "authentication": "string",
          "encryption": "string"
        },
        "bankKeyPinCheck": {
          "checkedOn": "string",
          "source": "string"
        },
        "bankKeyRotation": {
          "validFrom": "string",
          "bankKeyHashes": {},
          "certHashes": {},
          "check": {}
        },
        "keyManagementByVersion": {},
        "h005": {
          "upload": {},
          "uploadByKind": {},
          "uploadOptInByKind": {},
          "download": {}
        },
        "h005OnFile": false,
        "veuOnly": false,
        "h3k": false,
        "edsSupported": false,
        "ebicsNotes": [
          "string"
        ],
        "noPositiveStatusReport": {
          "basis": "string",
          "source": "string",
          "checkedOn": "string",
          "detail": "string"
        },
        "paymentValidationPortal": {
          "name": "string",
          "evidence": {}
        },
        "statementsOnly": {
          "basis": "string",
          "source": "string",
          "checkedOn": "string",
          "detail": "string"
        },
        "evidence": {
          "supportedVersions": {},
          "signatureVersion": {},
          "keyLengthBits": {},
          "sepa": {},
          "h005": {}
        }
      },
      "bankPgpPublicKey": "string",
      "bankPgpKeySlug": "string",
      "sshKeyType": "ed25519",
      "introEmail": {
        "to": "string",
        "subject": "string",
        "body": "string"
      },
      "sftpSetup": {
        "requirementsText": "string",
        "add": [
          {}
        ],
        "remove": [
          "countries"
        ],
        "copy": {},
        "counterpart": "string",
        "stepCopy": {},
        "screens": [
          {}
        ]
      },
      "ebicsSetup": {
        "add": [
          {}
        ],
        "remove": [
          "request-email"
        ],
        "copy": {},
        "groups": [
          {}
        ]
      },
      "notes": "string"
    }
  ]
}
GET/connections
List bank connections for a company
Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Connection list
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "companyId": "string",
      "bankKey": "string",
      "bankName": "string",
      "coveredBankKeys": [
        "string"
      ],
      "status": "setup",
      "deliveryMode": "converted-only",
      "environment": "test",
      "channelType": "sftp",
      "sftp": {
        "host": "string",
        "port": 0,
        "username": "string",
        "uploadPath": "string",
        "downloadPath": "string",
        "downloadHost": "string",
        "answers": {},
        "filename": "string",
        "hostFingerprint": "string",
        "hostFingerprintToCheck": "string",
        "downloadHostFingerprint": "string",
        "allowPlaintext": false,
        "expectedInboundEncryption": "pgp",
        "nextKeys": {
          "pgp": {},
          "ssh": {}
        },
        "tietoevry": {
          "code": "string",
          "orgNo": "string",
          "custId": "string",
          "bankId": "string",
          "env": "test"
        },
        "demo": {
          "outcome": "accepted",
          "delaySeconds": 0,
          "rejectReason": "string",
          "auto": false
        }
      },
      "webservice": {
        "wsVariant": "danske",
        "endpoint": "string",
        "pkiEndpoint": "string",
        "customerId": "string",
        "senderId": "string",
        "functionId": "string",
        "targetId": "string",
        "receiverId": "string",
        "environment": "TEST",
        "signingCertFingerprint": "string",
        "signingCertSerial": "string",
        "encryptionCertSerial": "string",
        "bankCertAdded": false,
        "bankConnectCamt052": false,
        "answers": {}
      },
      "ebics": {
        "url": "string",
        "hostId": "string",
        "partnerId": "string",
        "userId": "string",
        "protocolVersion": "string",
        "subscriberMode": "technical",
        "signatureVersion": "A005",
        "state": "created",
        "lettersPostedAt": "string",
        "fingerprintConfirmation": {
          "confirmedAt": "string",
          "confirmedBy": "string",
          "confirmedByName": "string",
          "keyManagement": "key",
          "fingerprints": {}
        },
        "modulusLength": 0,
        "subscriberId": "string",
        "subscriberSignatureCertPem": "string",
        "subscriberAuthCertPem": "string",
        "subscriberEncryptionCertPem": "string",
        "bankAuthPublicKeyPem": "string",
        "bankEncryptionPublicKeyPem": "string",
        "bankKeyHashesPinned": {
          "authentication": "string",
          "encryption": "string"
        },
        "bankCertHashesPinned": {
          "authentication": "string",
          "encryption": "string"
        },
        "perUserActivation": {
          "required": 0,
          "active": 0
        },
        "signatureProfile": "T",
        "keyManagement": "key",
        "authorisationMode": "outside-ebics",
        "authorisationConfirmation": {
          "mode": "outside-ebics",
          "bankMode": "outside-ebics",
          "confirmedAt": "string"
        },
        "veuOnly": false,
        "uploaderUserId": "string",
        "bankParams": {
          "bankName": "string",
          "url": "string",
          "hostId": "string",
          "protocolVersions": [],
          "authenticationVersions": [],
          "encryptionVersions": [],
          "signatureVersions": [],
          "recoverySupported": false,
          "preValidationSupported": false,
          "clientDataDownloadSupported": false,
          "downloadableOrderDataSupported": false,
          "fetchedAt": "string"
        },
        "hev": {
          "checkedAt": "string",
          "versions": [],
          "h005Supported": false,
          "profileMismatch": {},
          "ok": false,
          "message": "string",
          "source": "connection",
          "url": "string",
          "hostId": "string"
        },
        "discovery": {
          "via": "HTD",
          "fallbackFrom": {},
          "customerName": "string",
          "hostId": "string",
          "accounts": [],
          "orderInfo": [],
          "users": [],
          "fetchedAt": "string"
        },
        "agreementMismatches": [
          {}
        ],
        "agreementRefresh": {
          "attemptedAt": "string",
          "ok": false,
          "message": "string"
        },
        "reportCoverage": {
          "source": "contract",
          "fallback": "no-agreement-record",
          "reports": [],
          "noStatusReportFor": []
        },
        "stagedRenewal": {
          "subscriberMode": "technical",
          "userId": "string",
          "ebicsUserId": "string",
          "startedAt": "string",
          "ambiguous": false
        },
        "deactivatedAt": "string",
        "sprSuspension": {
          "at": "string",
          "mode": "technical",
          "userIds": [],
          "unconfirmedUserIds": []
        },
        "technicalRekey": {
          "stagedAt": "string",
          "sentAt": "string"
        }
      },
      "pgpFingerprint": "string",
      "pgpPublicKey": "string",
      "pgpExpiresAt": "string",
      "bankPgpPublicKey": "string",
      "useRegistryBankKey": false,
      "bankKeyFingerprintPin": "string",
      "bankPgpKeyInfo": {
        "keyId": "string",
        "fingerprint": "string",
        "userId": "string",
        "algorithm": "string",
        "createdAt": "string",
        "expiresAt": "string"
      },
      "sshPublicKey": "string",
      "sshPublicKeyArmored": "string",
      "sshFingerprint": "string",
      "sshKeyType": "ed25519",
      "abnXmlSigningPublicKey": "string",
      "abnXmlSigningFingerprint": "string",
      "steps": {
        "introEmailSent": false,
        "pgpGenerated": false,
        "bankPublicKeyAdded": false,
        "serverInfoAdded": false,
        "sftpUserAdded": false,
        "sftpTestingSkipped": false,
        "wsConfigAdded": false,
        "bankCertAdded": false,
        "certsIssued": false,
        "hevChecked": false,
        "ebicsKeysGenerated": false,
        "ebicsIniHiaSent": false,
        "ebicsLetterSent": false,
        "ebicsBankKeysFetched": false,
        "abnXmlSigningKeyGenerated": false,
        "sftpPasswordSet": false,
        "approversAssigned": false
      },
      "ingestedFiles": [
        "string"
      ],
      "productionVerifiedAt": "string",
      "connectedAt": "string",
      "testChannelSupported": false,
      "signingCertExpiresAt": "string",
      "tlsPins": [
        "string"
      ],
      "wsCertExpiresAt": "string",
      "wsBankCertExpiresAt": "string",
      "wsBankSigningCertExpiresAt": "string",
      "asicCertExpiresAt": "string",
      "certAlertSent": {},
      "pollIntervalSeconds": 0,
      "lastPolledAt": "string",
      "consecutivePollFailures": 0,
      "pollFailureAlertSentAt": "string",
      "sendsPaused": false,
      "sendsPausedAt": "string",
      "sendsPausedReason": "string",
      "createdAt": "string",
      "updatedAt": "string",
      "signingCertSubject": "string",
      "signingCertExpiry": "string",
      "inboundHealth": {
        "status": "live",
        "consecutiveFailures": 0,
        "threshold": 0,
        "reasons": [
          "string"
        ]
      }
    }
  ]
}
POST/connections
Create (or find existing) bank connection: starts the setup wizard

Creates a bank connection for the given company, or returns the existing one if already set up. A workspace (platform) admin must first enter a company context with POST /auth/company-context; otherwise the call fails with "select a company context first."

Request body required
PropertyTypeRequiredDescription
companyIdstringyes
bankKeystringyes
environmentstringno
countriesstring[]no
Example
{
  "companyId": "string",
  "bankKey": "string",
  "environment": "string",
  "countries": [
    "string"
  ]
}
Responses
StatusDescription
201Connection created
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
409`conflict` when two requests create the same connection at once. `invalid_state` when the bank's country already belongs to another of the company's connections in its bank group: change that connection's countries instead. `invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (201)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "brandSetup": [
    {
      "connectionId": "string",
      "bankKey": "string",
      "bankName": "string",
      "channelType": "sftp",
      "environment": "test",
      "coveredBankKeys": [
        "string"
      ],
      "outcome": "created"
    }
  ]
}
GET/connections/{id}
Get a single connection and its readiness
Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Connection + readiness
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
404Not found
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "sftpWizard": [
    {
      "id": "string",
      "phase": "prepare",
      "title": "string",
      "short": "string",
      "summary": "string",
      "intro": "string",
      "bullets": [
        "string"
      ],
      "notice": "string",
      "wait": "string",
      "steps": [
        {
          "type": "countries",
          "title": "string",
          "help": "string"
        }
      ],
      "stepCount": 0,
      "unnumbered": false
    }
  ],
  "registryBankKey": {
    "available": false,
    "fingerprint": "string",
    "validTo": "string",
    "uid": "string",
    "usable": false,
    "unusableReason": "string"
  }
}
DELETE/connections/{id}
Delete a bank channel (Admin, cannot be undone)

Deletes this bank channel. The channel's stored credentials are destroyed and cannot be recovered: its private PGP/SSH keys, SFTP password and every Web Services signing and encryption key and certificate. Payments already approved but not yet delivered over this channel will fail delivery; new payments to this bank are refused with 422 validation_failed until a channel is set up again from scratch. Payment, statement and audit history stays intact and still resolves. If this was the bank's last channel, the bank is also taken off "Your banks".

A production channel, or one that is currently live, also requires ?confirm=<bankKey>; without it the request is refused with 400 confirmation_required. Any EBICS download transactions the bank still holds open cannot be receipted from here once the keys are gone. The response reports how many there were.

Parameters
NameInRequiredDescription
id stringpathyes
confirm stringquerynoThe connection's own `bankKey`. Required when the channel is production or live; ignored otherwise.
companyId stringquerynoThe organisation this request acts on. Read from here OR from `companyId` in the JSON body (this query parameter wins when both are sent). Required, in one of the two places, for an API key, a signed-in session, a workspace administrator or a system admin; an application install or a delegated user falls back to its own company when neither is given.
Responses
StatusDescription
200Channel deleted: the body is the receipt (what was destroyed, and what survived)
400Confirmation required: re-send with ?confirm=<bankKey>
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404Not found (unknown connection, or one that was already deleted)
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "deleted": false,
  "bankKey": "string",
  "environment": "test",
  "secretsDestroyed": 0,
  "inboundAttemptsCleared": 0,
  "openEbicsTransactions": 0,
  "ebicsEnrolmentsCleared": 0,
  "ebicsKeysetsDestroyed": 0,
  "bankUnselected": false
}
GET/connections/{id}/health
Channel health for one connection

The three health facts the channel dashboard shows: payments the bank accepted (a count over the last windowDays days, when the most recent acceptance landed, and how many were rejected), statements received (a count, plus the newest one's ISO document type and the format the bank actually sent), and the inbound endpoint (this connection's poll cadence and when it was last polled). It also carries inboundHealth (live, degraded or down, judged on one shared failure threshold, the same as every connection read and the operator channel-health board) and the connection's own lifecycle connectionStatus, so a channel that has never been activated is not mistaken for one that is failing. Counts are windowed on the same event as the timestamp beside them: paymentsAccepted counts the acceptances and rejections that happened in the last windowDays days, and statementsReceived counts the statements that arrived in them. The last… timestamps are not windowed, so a channel that went quiet reports when it last worked, not null.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Channel health
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
404Not found
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connectionId": "string",
  "bankKey": "string",
  "environment": "test",
  "connectionStatus": "setup",
  "status": "live",
  "inboundHealth": {
    "status": "live",
    "consecutiveFailures": 0,
    "threshold": 0,
    "reasons": [
      "string"
    ]
  },
  "windowDays": 0,
  "paymentsAccepted": {
    "count": 0,
    "lastAcceptedAt": "string",
    "rejectedCount": 0
  },
  "statementsReceived": {
    "count": 0,
    "lastReceivedAt": "string",
    "lastType": "string",
    "lastSourceFormat": "string"
  },
  "endpoint": {
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string"
  }
}
POST/connections/{id}/intraday-report
Fetch the intraday account report now

Asks the bank for its intraday account report (camt.052) on this connection now, and ingests what it returns like any other bank file: each report is a journal document (GET /journal/documents?type=camt.052, or GET /journal/documents/{id} for a documentId in the answer). Some banks generate this report each time it is requested (Danske Bank), so it is never fetched on the scheduled poll; this request is how one arrives. The bank decides which postings each report covers. complete is false when the bank refused a list, or a list or a download failed; ingested then holds what did arrive. A connection asks its bank at most once per 15 minutes, as Danske Bank asks its customers not to list files every few minutes. A request inside those 15 minutes does not reach the bank: it is answered with the last report again, reused: true, with the same fetchedAt. nextFetchAt is the earliest a request reaches the bank again.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The reports this request ingested, or, inside the 15 minutes after the last fetch, that fetch's reports again
400The bank endpoint is one the outbound address policy refuses (`validation_failed`; 422 on `BankConnector-Version: 2026-10-20`)
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
404No such connection for this company (`connection_not_found`)
409The connection is being polled right now; try again in a minute
422No intraday report to fetch on this connection: it is not active, its bank offers none, or it is a test connection
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502The bank could not be reached
Example response (200)
{
  "connectionId": "string",
  "ingested": [
    {
      "documentId": "string",
      "type": "string",
      "name": "string"
    }
  ],
  "skipped": 0,
  "complete": false,
  "fetchedAt": "string",
  "reused": false,
  "nextFetchAt": "string"
}
GET/connections/{id}/test-files
The SFTP test round's files, grouped by country

The test files this connection has to get through before it goes live, grouped by the country each belongs to. The countries are the connection's own claimed coverage (coveredBankKeys: a country belongs to exactly one connection per company and environment). Each country's file list comes from that country's bank (a bank with no domestic rail has fewer files), so the n of m counter's denominator is per country.

Each row's state is derived from the payment it describes. A pain.002 coming back advances that payment's status, and the row follows it. The exception is accepted-by-person: many banks send no pain.002 and confirm a test round by email, by phone, or by switching the channel on, so a named person marking a file accepted is a first-class path. accepted-by-bank and accepted-by-person are separate states and are never collapsed into one, because "the bank confirmed" and "a person said the bank confirmed" carry different weight if a test round is disputed. Where both exist, the bank's verdict decides state and the person's record is still served beside it.

items is one entry per country (total counts countries); fileCount / acceptedCount at the top level count files across all of them.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The test files, grouped by country
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
404Not found
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connectionId": "string",
  "bankKey": "string",
  "environment": "test",
  "items": [
    {
      "country": "string",
      "countryName": "string",
      "bankKeys": [
        "string"
      ],
      "files": [
        {
          "bankKey": "string",
          "scenario": "string",
          "label": "string",
          "description": "string",
          "amount": "string",
          "currency": "string",
          "paymentType": "string",
          "format": "string",
          "paymentCount": 0,
          "state": "ready",
          "accepted": false,
          "payment": {},
          "acceptance": {},
          "withdrawal": {}
        }
      ],
      "acceptedCount": 0,
      "fileCount": 0
    }
  ],
  "total": 0,
  "acceptedCount": 0,
  "fileCount": 0
}
POST/connections/{id}/test-files/acceptance
Record or withdraw a person's acceptance of a test file

Records that a named person confirmed the bank accepted one test file, out of band. Admin only, and audited: the entry stores who (user id and the name at the time) and when, as evidence for a go-live decision.

The log is append-only. action: "withdraw" appends a second entry naming who withdrew it and when; the original acceptance is never deleted, rewritten or hidden. A withdrawn row falls back to whatever its payment says, and the withdrawal stays readable beside it.

A file's current standing is the last entry for its (bankKey, scenario) pair. Accepting a file that is already accepted returns 409 test_file_already_accepted; withdrawing one nobody accepted returns 409 test_file_not_accepted. A (bankKey, scenario) pair that is not a test file on this connection, a country it does not cover, or a scheme this bank does not offer, is refused with 422 unknown_test_file.

Where a pain.002 has arrived, the row's state comes from the payment and this route cannot change it. Answers the same body as GET /connections/{id}/test-files, refreshed.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
bankKeystringyesThe covered bankKey the file belongs to. The country, in the connection's own coverage model.
scenariostringyesThe test scenario id, as `GET /connections/{id}/test-files` reports it.
actionenumyes
notestringnoOptional free text kept with the record, how the bank confirmed, or why an acceptance was withdrawn.
Example
{
  "companyId": "string",
  "bankKey": "string",
  "scenario": "string",
  "action": "accept",
  "note": "string"
}
Responses
StatusDescription
200Recorded: the refreshed test-file view
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404Not found
409Already accepted, or nothing to withdraw
413The request body is larger than this operation accepts (`payload_too_large`).
422Not a test file on this connection
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connectionId": "string",
  "bankKey": "string",
  "environment": "test",
  "items": [
    {
      "country": "string",
      "countryName": "string",
      "bankKeys": [
        "string"
      ],
      "files": [
        {
          "bankKey": "string",
          "scenario": "string",
          "label": "string",
          "description": "string",
          "amount": "string",
          "currency": "string",
          "paymentType": "string",
          "format": "string",
          "paymentCount": 0,
          "state": "ready",
          "accepted": false,
          "payment": {},
          "acceptance": {},
          "withdrawal": {}
        }
      ],
      "acceptedCount": 0,
      "fileCount": 0
    }
  ],
  "total": 0,
  "acceptedCount": 0,
  "fileCount": 0
}
POST/connections/{id}/test-files/send
Send one test file to the bank

Sends a real payment file. Builds one test file, one country × one scenario, and puts it through the same entry point POST /journal/payments uses: the same conversion, approval policy, PGP sign-and-encrypt and filename pattern. Nothing is simulated; what keeps it a test payment is the connection it goes out over.

Sandbox only. A connection whose environment is production is refused with 403 sandbox_only, the same refusal POST /banks/{bankKey}/test-payment returns. That check can only read the label on the connection, so testServerConfirmed is required and a request without it is refused with 422 test_server_not_confirmed: only the customer knows whether the host behind the label is really a test server. Nothing is built or sent before both checks pass.

It writes no test-file state. A row's state is derived from the payment this creates, so re-read GET /connections/{id}/test-files afterwards. A send that fails leaves the row on whatever the payment says (sending, send-failed), never on accepted.

Answers with the payment pipeline's own outcome (201, or the pipeline's refusal), so a payment that stopped at the approval policy is readable as itself. Send an Idempotency-Key to make a double-clicked send retry-safe.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
bankKeystringyesThe covered bankKey the file belongs to. The country, in the connection's own coverage model.
scenariostringyesThe test scenario id, as `GET /connections/{id}/test-files` reports it.
accountobjectyesThe customer's own paying account. Required, with no default: a file built with a sample IBAN would be rejected by the bank as an unknown debtor.
testServerConfirmedbooleanyesConfirms this connection points at the bank's test server, not production. Required; `false` or absent is refused with 422 test_server_not_confirmed.
Example
{
  "companyId": "string",
  "bankKey": "string",
  "scenario": "string",
  "account": {
    "name": "string",
    "iban": "string",
    "other": {
      "id": "string",
      "scheme": "string"
    },
    "currency": "string",
    "country": "string"
  },
  "testServerConfirmed": false
}
Responses
StatusDescription
201Accepted: the payment pipeline's own outcome
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403The connection is production. The test round is sandbox-only
404Not found
413The request body is larger than this operation accepts (`payload_too_large`).
422Not a test file on this connection, or the test server was not confirmed
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (201)
{
  "id": "string",
  "journalNo": "string",
  "companyId": "string",
  "bankKey": "string",
  "environment": "test",
  "direction": "inbound",
  "type": "pain.001",
  "sourceFormat": "string",
  "summary": "string",
  "status": "string",
  "messageId": "string",
  "transactionCount": 0,
  "totals": [
    {
      "currency": "string",
      "amount": "string"
    }
  ],
  "paymentType": "string",
  "source": {
    "reference": "string",
    "name": "string"
  },
  "collected": false,
  "collectedAt": "string",
  "idempotencyKey": "string",
  "createdAt": "string",
  "expiresAt": "string",
  "deduped": false,
  "xml": "string",
  "deliveryMode": "string",
  "autoSelected": [
    {
      "paymentId": "string",
      "selected": "string",
      "confidence": "string",
      "reason": "string"
    }
  ],
  "autoFilled": [
    "string"
  ],
  "unknownFieldsDropped": [
    "string"
  ],
  "warnings": [
    {
      "code": "string",
      "level": "generic",
      "severity": "error",
      "message": "string",
      "path": "string",
      "bank": "string",
      "paymentType": "string"
    }
  ],
  "approval": {
    "id": "string",
    "companyId": "string",
    "documentId": "string",
    "paymentRef": "string",
    "source": {
      "reference": "string",
      "name": "string"
    },
    "erpNotes": [
      {
        "kind": "payee-account-changed",
        "paymentRef": "string",
        "from": "string",
        "to": "string",
        "shownTo": "string",
        "shownAt": "string"
      }
    ],
    "makerUserId": "string",
    "makerName": "string",
    "makerClaimedEmail": "string",
    "maxTransaction": "string",
    "journalTotal": "string",
    "currency": "string",
    "currencies": [
      "string"
    ],
    "payeeName": "string",
    "payeeCount": 0,
    "fundingAccount": {
      "iban": "string",
      "accountOther": "string",
      "bankKey": "string",
      "accounts": [
        {
          "iban": "string",
          "accountOther": "string",
          "totals": []
        }
      ]
    },
    "policyVersionId": "string",
    "requiredApprovals": 0,
    "allowSelfApproval": false,
    "approverLimits": {},
    "requireOneFromEachGroup": false,
    "orderedApproval": false,
    "groups": [
      {
        "id": "string",
        "name": "string",
        "userIds": [
          "string"
        ]
      }
    ],
    "approverUserIds": [
      "string"
    ],
    "approvals": [],
    "rejections": [],
    "status": "pending",
    "createdAt": "string",
    "updatedAt": "string"
  },
  "delivery": {
    "queued": false,
    "externalApproval": {
      "authority": "string",
      "at": "string"
    }
  },
  "whitelist": {
    "applicable": false,
    "outcome": "cleared",
    "checks": [
      {
        "nip": "string",
        "nrb": "string",
        "date": "string",
        "status": "listed",
        "requestId": "string",
        "error": "string"
      }
    ],
    "conversions": [
      {
        "nrb": "string",
        "amount": "string",
        "currency": "string",
        "date": "string",
        "rate": {
          "table": "string",
          "no": "string",
          "effectiveDate": "string",
          "mid": "string"
        },
        "amountPln": "string",
        "reachesThreshold": false,
        "error": "string"
      }
    ]
  }
}
POST/connections/{id}/test-files/file
Build one test file for sending by hand

The same file as bytes, for uploading to the bank's portal by hand. Many banks take a test round through their portal instead of over the channel.

The XML is what send would have submitted. It is not signed or encrypted: the portal authenticates the person uploading. Nothing is recorded or sent: no payment exists afterwards and no row moves, and a file that was downloaded and never uploaded has not reached the bank. Meets the same refusals as send, because building a file for a country the connection does not cover is the same act.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
bankKeystringyesThe covered bankKey the file belongs to. The country, in the connection's own coverage model.
scenariostringyesThe test scenario id, as `GET /connections/{id}/test-files` reports it.
accountobjectyesThe customer's own paying account. Required, with no default: a file built with a sample IBAN would be rejected by the bank as an unknown debtor.
testServerConfirmedbooleanyesConfirms this connection points at the bank's test server, not production. Required; `false` or absent is refused with 422 test_server_not_confirmed.
Example
{
  "companyId": "string",
  "bankKey": "string",
  "scenario": "string",
  "account": {
    "name": "string",
    "iban": "string",
    "other": {
      "id": "string",
      "scheme": "string"
    },
    "currency": "string",
    "country": "string"
  },
  "testServerConfirmed": false
}
Responses
StatusDescription
200The generated pain.001, its filename and the pain version
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403The connection is production. The test round is sandbox-only
404Not found
413The request body is larger than this operation accepts (`payload_too_large`).
422Not a test file on this connection, or the test server was not confirmed
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "filename": "string",
  "xml": "string",
  "painVersion": "string"
}
PUT/connections/{id}/signing-cert
Pin the bank's published signing certificate

Stores the bank's published X.509 signing certificate (PEM or base64-DER) on the connection. Inbound Web Services signatures are then verified against it, and any mismatch fails closed. Admin only. Returns 400 if the certificate does not parse. Returns the certificate subject and expiry so you can confirm you pinned the right one; the raw PEM is never returned. GET /connections/{id} then shows signingCertSubject and signingCertExpiry.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
certstringyesThe bank's published signing certificate. PEM (-----BEGIN CERTIFICATE-----) or base64-DER.
Example
{
  "companyId": "string",
  "cert": "string"
}
Responses
StatusDescription
200Pinned
400Not a PEM certificate (`validation_failed`)
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connectionId": "string",
  "certSubject": "string",
  "certExpiry": "string"
}
POST/connections/{id}/generate-pgp
Generate our PGP key pair (SFTP channel)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200PGP key pair generated
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/generate-abn-xmldsig-key
Generate our ABN AMRO Access Direct XML-Signature key (SFTP channel, ABN AMRO only)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Signing key generated
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/bank-key
Save the bank's PGP public key (SFTP channel)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
armoredKeystringyesASCII-armored PGP public key block.
Example
{
  "companyId": "string",
  "armoredKey": "string"
}
Responses
StatusDescription
200Bank key saved
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/server-info
Save SFTP server info (host, port, paths, fingerprint)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
hoststringno
portnumberno
uploadPathstringno
downloadPathstringno
downloadHoststringno
downloadHostFingerprintstringno
filenamestringno
hostFingerprintstringnoThe bank's SFTP host-key fingerprint. A SHA-256 one (`SHA256:` plus base64, or 64 hex characters, with or without colons) is the pin, stored as `SHA256:` plus unpadded base64 in `sftp.hostFingerprint`. An MD5 (32 hex) or SHA-1 (40 hex, or `SHA1:` plus base64) one, for a bank that publishes only that, is never a pin: it is stored in `sftp.hostFingerprintToCheck`, and the next `test-connection`, `detect-folders` or `folder-health` compares it with the key the server presents and, on a match, pins that key's SHA-256 and clears it. A key that does not match fails that check as a wrong pin does, and nothing is stored. No file is uploaded or downloaded until then. Anything else is refused with `validation_failed` (`422` on API version 2026-10-20, `400` before it). Empty clears both. `downloadHostFingerprint` takes a SHA-256 fingerprint only, by the pin rule.
answersobjectnoAnswers to the bank's own agreement questions (the `sftp.inputs` its setup-info lists), keyed by question. Keys the bank does not declare are dropped. For a bank behind the TietoEvry gateway (SpareBank 1, Eika) the three keys are `code`, `orgNo` and `custId`; the bank ID comes from the bank itself (`sftp.bankId` in its setup-info). Once all three are saved, the SFTP login, folders and TietoEvry channel settings are derived for this connection's environment, and a malformed value is refused with 400 `validation_failed`.
Example
{
  "companyId": "string",
  "host": "string",
  "port": 0,
  "uploadPath": "string",
  "downloadPath": "string",
  "downloadHost": "string",
  "downloadHostFingerprint": "string",
  "filename": "string",
  "hostFingerprint": "string",
  "answers": {}
}
Responses
StatusDescription
200Server info saved
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/sftp-user
Set SFTP username and generate SSH key pair (single combined call)

Sets the SFTP username and generates the SSH key pair in one call. Get the username from the bank first. The response includes the connection and readiness state, from which you can retrieve the generated SSH public key to send to the bank for whitelisting.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
usernamestringnoSFTP username assigned by the bank. The SSH key is generated with or without it.
Example
{
  "companyId": "string",
  "username": "string"
}
Responses
StatusDescription
200Username set + SSH key generated
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/sftp-host-keys
Pin the bank's new SFTP host key on a set-up connection

For when the bank moves to a new server or host key: the new fingerprint, typed from the bank's own notice, replaces the pinned one. A SHA-256 fingerprint is the pin. An MD5 or SHA-1 one, for a bank that publishes only that, is first compared with the key the connection's server presents, without signing in: on a match that key's SHA-256 is pinned, and a key that does not match is refused with validation_failed, so the connection keeps its pin. If the server cannot be reached for that comparison, nothing is written and the answer is 502 bank_unavailable. The download server of a split-host bank takes a SHA-256 fingerprint only. A live connection stays live and its next transfer checks the new key. Works on an active or a deactivated SFTP connection, never one still in setup; it is refused with invalid_state, and nothing is written, if it would leave the connection missing a setup step it had. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
hostFingerprintstringnoThe bank's new SFTP host-key fingerprint. A SHA-256 one is the pin: `SHA256:` plus base64, or 64 hex characters (with or without colons), stored as `SHA256:` plus unpadded base64. Type it from the bank's own notice: the server never offers the key it presents. An MD5 (32 hex) or SHA-1 (40 hex, or `SHA1:` plus base64) one, for a bank that publishes only that, is never a pin: it is compared now with the key the server presents and, on a match, that key's SHA-256 is pinned. A key that does not match is refused with `validation_failed`, and the connection keeps its pin. Anything else is refused with `validation_failed`. Omit to keep the pin.
downloadHostFingerprintstringnoSplit-host banks only: the download server's new host key, as a SHA-256 fingerprint: `SHA256:` plus base64, or 64 hex characters (with or without colons), stored as `SHA256:` plus unpadded base64. Type it from the bank's own notice: the server never offers the key it presents. Anything else, MD5 and SHA-1 included, is refused with `validation_failed`. Omit to keep the pin.
Example
{
  "companyId": "string",
  "hostFingerprint": "string",
  "downloadHostFingerprint": "string"
}
Responses
StatusDescription
200Host key pinned
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the bank's SFTP server could not be reached to check an MD5 or SHA-1 fingerprint
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/sftp-bank-key
Replace the bank's PGP public key on a set-up connection

For when the bank replaces its PGP key: payment files are encrypted to the new key from the next one sent. An expired key, or one that can neither encrypt nor verify, is refused like the setup step's. Not for a connection that uses BankConnector's copy of the bank key. Works on an active or a deactivated SFTP connection, never one still in setup; it is refused with invalid_state, and nothing is written, if it would leave the connection missing a setup step it had. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
armoredKeystringyesThe bank's new ASCII-armored PGP public key block.
Example
{
  "companyId": "string",
  "armoredKey": "string"
}
Responses
StatusDescription
200Bank key replaced
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/sftp-key-prepare
Prepare a new PGP or SSH key pair beside the one in use

Generates our next key pair of the named kind; the connection keeps using the current one. The new public half is on the connection as sftp.nextKeys for you to send to the bank. Calling it again while a pair waits returns that pair unchanged. Works on an active or a deactivated SFTP connection, never one still in setup; it is refused with invalid_state, and nothing is written, if it would leave the connection missing a setup step it had. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
keyenumyes`pgp`: our PGP key pair, which signs payment files and decrypts the bank's. `ssh`: our SSH key pair, which signs in to the bank's server.
Example
{
  "companyId": "string",
  "key": "pgp"
}
Responses
StatusDescription
200New key pair prepared
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/sftp-key-switch
Switch to the prepared key pair

Puts the prepared key pair of the named kind in use and retires the one it replaces. Switch once the bank confirms it holds the new public half: files and sign-ins use the new pair from then on. Works on an active or a deactivated SFTP connection, never one still in setup; it is refused with invalid_state, and nothing is written, if it would leave the connection missing a setup step it had. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
keyenumyes`pgp`: our PGP key pair, which signs payment files and decrypts the bank's. `ssh`: our SSH key pair, which signs in to the bank's server.
Example
{
  "companyId": "string",
  "key": "pgp"
}
Responses
StatusDescription
200Switched to the new key pair
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/sftp-key-discard
Discard the prepared key pair

Throws away the prepared key pair of the named kind; the pair in use is untouched. Works on an active or a deactivated SFTP connection, never one still in setup; it is refused with invalid_state, and nothing is written, if it would leave the connection missing a setup step it had. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
keyenumyes`pgp`: our PGP key pair, which signs payment files and decrypts the bank's. `ssh`: our SSH key pair, which signs in to the bank's server.
Example
{
  "companyId": "string",
  "key": "pgp"
}
Responses
StatusDescription
200Prepared key pair discarded
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/approvers
Assign approver users to a connection

Assigns which users may approve payments on this connection. Approvers and approval policy are separate: the policy (under POST /approvals/policies) defines the rule (how many approvers, any amount thresholds), and this endpoint assigns the eligible users per connection. Both must be in place for a connection to reach go-live. Users must exist in the company first: create them with POST /users.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
userIdsstring[]yesUser IDs of company members with the Approver role. Must already exist in the company. Max 200.
Example
{
  "companyId": "string",
  "userIds": [
    "string"
  ]
}
Responses
StatusDescription
200Approvers assigned
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409Refused by approval governance with the code `POST /approvals/bank-rosters` gives it: `second_admin_required`, `policy_cosign_required`, `policy_change_in_flight`
413The request body is larger than this operation accepts (`payload_too_large`).
422One or more user IDs are not valid approvers in this company, or `policy_quorum_shortfall`: the bank's policy requires more approvers than were named
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "pendingPolicyChange": {
    "id": "string",
    "proposedBy": {
      "userId": "string",
      "name": "string"
    },
    "status": "pending",
    "cosigns": [
      {
        "adminId": "string",
        "name": "string",
        "at": "string"
      }
    ],
    "requiredCosigns": 0,
    "weakening": [
      {
        "field": "string",
        "from": "string",
        "to": "string",
        "why": "string"
      }
    ],
    "blastRadius": {
      "banks": 0,
      "exact": false,
      "label": "string"
    },
    "proposedPolicyDigests": {},
    "createdAt": "string",
    "activatedAt": "string",
    "cancelledAt": "string",
    "kind": "string",
    "policyId": "string",
    "before": {
      "name": "string",
      "template": "single",
      "enabled": false,
      "requiredApprovals": 0,
      "allowSelfApproval": false,
      "perTransactionLimit": "string",
      "perJournalLimit": "string",
      "perTransactionMax": "string",
      "requireOneFromEachGroup": false,
      "orderedApproval": false,
      "groups": [
        {
          "id": "string",
          "name": "string",
          "userIds": []
        }
      ]
    },
    "proposed": {
      "name": "string",
      "template": "single",
      "enabled": false,
      "requiredApprovals": 0,
      "allowSelfApproval": false,
      "perTransactionLimit": "string",
      "perJournalLimit": "string",
      "perTransactionMax": "string",
      "requireOneFromEachGroup": false,
      "orderedApproval": false,
      "groups": [
        {
          "id": "string",
          "name": "string",
          "userIds": []
        }
      ]
    }
  }
}
POST/connections/{id}/activate
Mark SFTP connection active (after the bank has whitelisted the SSH key)

Switches a connection on for host-to-host delivery, the first time or again after it was deactivated. A deactivated connection is reactivated only when its setup is complete again; an EBICS connection also needs the bank's own record (ebics-fetch-htd), read after the deactivation and after any emergency suspend, to show every subscriber ready, and a technical subscriber suspended by SPR needs new keys first. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Connection activated
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`conflict`: the connection was deactivated, or switched on, while this request ran; nothing was changed. `invalid_state` when a setup step is missing, or a deactivated connection does not meet the reactivation rule; the message names what is missing. `invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/intro-email-sent
Mark intro email as sent (tracks wizard progress)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
introEmailTostringno
Example
{
  "companyId": "string",
  "introEmailTo": "string"
}
Responses
StatusDescription
200Updated
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "introEmailAutoSent": false
}
POST/connections/{id}/ws-environment
Toggle a Web Services connection between TEST and PRODUCTION (development servers only)

Requires an already-activated connection (certificates issued); does not re-run PKI. Development only: a production or deployed-sandbox server refuses this call with 403 ws_environment_toggle_disabled. A connection transmits under the environment it was created with, which cannot change.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
environmentstringno
Example
{
  "companyId": "string",
  "environment": "string"
}
Responses
StatusDescription
200Environment updated
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required, or the toggle is disabled on this server (development-only)
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/covered-banks
Set which member banks a shared connection covers

For a shared (group) connection. The store clamps the set to the bank's group and always includes the connection's own bank.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
coveredBankKeysstring[]noBank keys this connection serves (clamped to the bank's group).
Example
{
  "companyId": "string",
  "coveredBankKeys": [
    "string"
  ]
}
Responses
StatusDescription
200Covered banks updated
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
GET/connections/{id}/intro-email
Render the bank intro email (draft to send to the bank contact)
Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Rendered email (subject + body)
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
404Not found
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "email": {
    "to": "string",
    "subject": "string",
    "body": "string"
  }
}
GET/connections/{id}/capability-sheet
Download the host-to-host capability sheet (PDF, base64-encoded)

The 2-page sheet attached to the agreement-request email: the payment schemes we offer through this bank in each country it covers, the pain.001 version and packaging we send, the files we need back, and how we connect. Every value comes from the bank registry and the payment-type catalog. A value we cannot source is omitted from the document and named in unknowns.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200PDF as base64, plus the fields the sheet could not state
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
404Connection not found
409The bank agreement pins a pain.001 version this bank does not support
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "pdfBase64": "string",
  "filename": "string",
  "unknowns": [
    "string"
  ],
  "pages": 0
}
GET/banks/{bankKey}/setup-info
Per-bank setup descriptor for the wizard UI

Returns the channel kind, requirements text, field definitions, known server and endpoint details, and SFTP wizard screens for a bank. A bank outside Danske's, Bank Connect's, Nordea Corporate Access's and OP's Web Services is gated: until BankConnector approves the organisation's request (POST /banks/{bankKey}/guide-access-request), or while it has no connection to the bank, the descriptor is locked (unlockOn: access-request, titles only) and carries accessRequest.

Parameters
NameInRequiredDescription
bankKey BankKeypathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
testChannel enumquerynoWhether the bank offers the company a test channel: `no` leaves the test-payment steps out of the setup guide. Omit it for the guide before that question is answered. Any other value is ignored.
channel enumquerynoThe channel to describe the setup for, when the company's connection to this bank was created on a channel other than the bank's declared one (a connection keeps its channel). The response's `channelType`, `kind` and `wizard` then describe that channel. Omit it for the bank's declared channel. Any other value is ignored.
Responses
StatusDescription
200Setup descriptor
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
404Unknown bank
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "bankKey": "string",
  "bankName": "string",
  "countryCode": "string",
  "painVersion": "string",
  "painVersions": [
    "string"
  ],
  "batchBookingDefault": false,
  "approverCodesDefaultOn": false,
  "acceptedDebtorBics": [
    "string"
  ],
  "contactSupport": {
    "message": "string"
  },
  "unsupported": {
    "reason": "string"
  },
  "channelType": "string",
  "channelDeclared": false,
  "wsVariant": "string",
  "kind": "string",
  "requirementsText": "string",
  "fields": [
    {
      "name": "string",
      "label": "string",
      "placeholder": "string",
      "required": false,
      "prefill": "string",
      "help": "string",
      "fullWidth": false,
      "maxLength": 0,
      "pattern": "string",
      "setting": false,
      "secret": false,
      "options": [
        {
          "value": "string",
          "label": "string"
        }
      ],
      "answer": false,
      "perUserExempt": false,
      "sink": "server-info"
    }
  ],
  "bankConnect": {
    "title": "string",
    "badge": {
      "text": "string",
      "ink": "string",
      "bg": "string"
    },
    "subtitle": "string",
    "countryName": "string",
    "centralName": "string",
    "connection": {
      "label": "string",
      "ink": "string",
      "bg": "string"
    },
    "intro": "string",
    "agreementIntro": "string",
    "accountsText": "string",
    "materialsIntro": "string",
    "statementTypes": [
      {
        "code": "string",
        "label": "string",
        "shortLabel": "string",
        "description": "string",
        "recommended": false,
        "recommendTag": "string",
        "railLabel": "string",
        "tooltip": "string"
      }
    ],
    "approvalIntro": "string",
    "approval": [
      {
        "code": "string",
        "label": "string",
        "shortLabel": "string",
        "description": "string",
        "recommended": false,
        "recommendTag": "string",
        "railLabel": "string",
        "tooltip": "string"
      }
    ],
    "deliverables": {
      "heading": "string",
      "intro": "string",
      "items": [
        {
          "text": "string",
          "tooltip": "string"
        }
      ],
      "footer": "string"
    },
    "activateTitle": "string",
    "activateIntro": "string",
    "activateCta": "string",
    "activateNote": "string",
    "activateReassurance": "string",
    "goLivePending": "string",
    "goLiveConnected": "string",
    "statusUrl": "string"
  },
  "guide": {
    "title": "string",
    "badge": {
      "text": "string",
      "ink": "string",
      "bg": "string"
    },
    "subtitle": "string",
    "countryName": "string",
    "centralName": "string",
    "connection": {
      "label": "string",
      "ink": "string",
      "bg": "string"
    },
    "intro": "string",
    "agreementIntro": "string",
    "accountsText": "string",
    "materialsIntro": "string",
    "statementTypes": [
      {
        "code": "string",
        "label": "string",
        "shortLabel": "string",
        "description": "string",
        "recommended": false,
        "recommendTag": "string",
        "railLabel": "string",
        "tooltip": "string"
      }
    ],
    "approvalIntro": "string",
    "approval": [
      {
        "code": "string",
        "label": "string",
        "shortLabel": "string",
        "description": "string",
        "recommended": false,
        "recommendTag": "string",
        "railLabel": "string",
        "tooltip": "string"
      }
    ],
    "deliverables": {
      "heading": "string",
      "intro": "string",
      "items": [
        {
          "text": "string",
          "tooltip": "string"
        }
      ],
      "footer": "string"
    },
    "activateTitle": "string",
    "activateIntro": "string",
    "activateCta": "string",
    "activateNote": "string",
    "activateReassurance": "string",
    "goLivePending": "string",
    "goLiveConnected": "string",
    "statusUrl": "string"
  },
  "guidedFlow": false,
  "group": {
    "id": "string",
    "name": "string",
    "exclusiveCoverage": false,
    "members": [
      {
        "key": "string",
        "bankName": "string",
        "countryCode": "string",
        "requiresApproverSsn": false
      }
    ]
  },
  "brand": {
    "policyId": "string",
    "brandName": "string",
    "countries": [
      {
        "bankKey": "string",
        "bankName": "string",
        "countryCode": "string",
        "channelAlone": "ebics"
      }
    ],
    "rule": "string"
  },
  "wizard": {
    "kind": "string",
    "screens": [
      {
        "id": "string",
        "phase": "prepare",
        "title": "string",
        "short": "string",
        "summary": "string",
        "intro": "string",
        "bullets": [
          "string"
        ],
        "notice": "string",
        "wait": "string",
        "steps": [
          {}
        ],
        "stepCount": 0,
        "unnumbered": false
      }
    ],
    "turns": [
      {
        "id": "prepare",
        "title": "string",
        "short": "string",
        "intro": "string",
        "bullets": [
          "string"
        ],
        "notice": "string",
        "steps": [
          {}
        ],
        "stepCount": 0,
        "gate": {
          "unlocksAt": "created",
          "awaitsBankAt": "created",
          "resumesAt": "created",
          "completesAt": "created",
          "terminal": false
        }
      }
    ]
  },
  "knownServer": {
    "gateway": "tietoevry",
    "bankId": "string",
    "host": "string",
    "port": 0,
    "uploadPath": "string",
    "downloadPath": "string",
    "testHost": "string",
    "testPort": 0,
    "testLoginDiffers": false,
    "downloadHost": "string",
    "usernameHint": "string",
    "uploadTemplate": "string",
    "downloadPattern": "string",
    "inputs": [
      {
        "key": "string",
        "label": "string",
        "hint": "string"
      }
    ],
    "sshKeyBits": 0,
    "pgpKeyBits": 0,
    "dualAuth": false
  },
  "knownWebservice": {
    "wsVariant": "danske",
    "endpoint": "string",
    "pkiEndpoint": "string",
    "receiverId": "string",
    "environment": "TEST",
    "environmentEvidence": {
      "basis": "string",
      "source": "string",
      "checkedOn": "string",
      "detail": "string"
    },
    "registrationNumber": "string",
    "setupFields": {
      "add": [
        {
          "field": {},
          "after": "string"
        }
      ],
      "remove": [
        "string"
      ],
      "copy": {}
    }
  },
  "bankPgpPublicKeyKnown": false,
  "sshKeyType": "string",
  "keyAlgorithms": {
    "pgp": "string",
    "ssh": "string"
  },
  "supportsEnvironmentToggle": false,
  "generalSettingsEnabled": false,
  "ebics": {
    "hostId": "string",
    "url": "string",
    "notes": [
      "string"
    ],
    "h3k": false,
    "edsSupported": false,
    "publishedKeyHashes": {
      "authentication": "string",
      "encryption": "string"
    },
    "publishedCertHashes": {
      "authentication": "string",
      "encryption": "string"
    },
    "keyLength": {
      "bankMinimumBits": {
        "value": 0,
        "evidence": {
          "basis": "string",
          "source": "string",
          "checkedOn": "string",
          "detail": "string"
        }
      },
      "generatedBits": 0
    }
  },
  "operationalFacts": {
    "cutOffs": {
      "value": [
        {
          "scheme": "all",
          "time": "string",
          "timeZone": "Europe/Berlin",
          "currency": "string"
        }
      ],
      "evidence": {
        "basis": "string",
        "source": "string",
        "checkedOn": "string",
        "detail": "string"
      }
    },
    "statementFormats": {
      "value": {
        "offered": [
          "mt940"
        ],
        "notOffered": [
          "mt940"
        ]
      },
      "evidence": {
        "basis": "string",
        "source": "string",
        "checkedOn": "string",
        "detail": "string"
      }
    },
    "instantCreditTransfer": {
      "value": {
        "offered": false,
        "maxAmount": {
          "amount": 0,
          "currency": "string"
        },
        "since": "string"
      },
      "evidence": {
        "basis": "string",
        "source": "string",
        "checkedOn": "string",
        "detail": "string"
      }
    },
    "verificationOfPayee": {
      "value": {
        "offered": false,
        "since": "string"
      },
      "evidence": {
        "basis": "string",
        "source": "string",
        "checkedOn": "string",
        "detail": "string"
      }
    },
    "distributedSignature": {
      "value": false,
      "evidence": {
        "basis": "string",
        "source": "string",
        "checkedOn": "string",
        "detail": "string"
      }
    },
    "onboardingStart": {
      "value": "appointment",
      "evidence": {
        "basis": "string",
        "source": "string",
        "checkedOn": "string",
        "detail": "string"
      }
    },
    "onboardingDocuments": {
      "value": [
        {
          "name": "string",
          "role": "application",
          "url": "string"
        }
      ],
      "evidence": {
        "basis": "string",
        "source": "string",
        "checkedOn": "string",
        "detail": "string"
      }
    },
    "onboardingReturnRoutes": {
      "value": [
        {
          "carries": "application",
          "via": "email",
          "address": "string",
          "subject": "string"
        }
      ],
      "evidence": {
        "basis": "string",
        "source": "string",
        "checkedOn": "string",
        "detail": "string"
      }
    },
    "onboardingContacts": {
      "value": [
        {
          "label": "string",
          "phones": [],
          "email": "string",
          "hours": "string"
        }
      ],
      "evidence": {
        "basis": "string",
        "source": "string",
        "checkedOn": "string",
        "detail": "string"
      }
    }
  },
  "identifiers": [
    {
      "slot": "agreementId",
      "label": "string",
      "placement": "header",
      "writes": [
        {
          "at": "header",
          "scheme": "string"
        }
      ],
      "mandatory": false,
      "askedInSetup": false,
      "formatHint": "string",
      "evidence": {
        "basis": "string",
        "source": "string",
        "checkedOn": "string",
        "detail": "string"
      }
    }
  ],
  "locked": false,
  "unlockOn": "string",
  "lockNote": "string",
  "accessRequest": {
    "status": "string"
  }
}
GET/banks/{bankKey}/sftp-naming
Preview the SFTP logins, folders and file names a gateway bank's agreement gives

For a bank reached through TietoEvry's shared SFTP service: the server, the test and production logins, their folders and the name of a payment file, worked out from the agreement answers typed so far. An answer that is missing or malformed shows as a <placeholder>, and each malformed one is named in problems. complete is true once every answer is usable; the names are then the ones delivery uses. Nothing is saved. Gated like the bank's setup guide: an organisation that holds neither an approved access request nor a connection to the bank is refused with bank_guide_access_required.

Parameters
NameInRequiredDescription
bankKey BankKeypathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
code stringquerynoSFTP account code
orgNo stringqueryno9-digit organisation number
custId stringquerynoCustomer identifier (CUSTID)
Responses
StatusDescription
200The test and production logins, folders and file names
401Authentication required: the credential is missing, invalid or expired.
403`bank_guide_access_required`: the organisation has no access to this bank's setup guide yet, or the credential's role, scope or grant does not allow this operation.
404Unknown bank, or a bank whose server, logins and file names are not derived
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "complete": false,
  "problems": [
    "string"
  ],
  "test": {
    "host": "string",
    "port": 0,
    "username": "string",
    "uploadFolder": "string",
    "downloadFolder": "string",
    "uploadFile": "string",
    "uploadFilePath": "string"
  },
  "production": {
    "host": "string",
    "port": 0,
    "username": "string",
    "uploadFolder": "string",
    "downloadFolder": "string",
    "uploadFile": "string",
    "uploadFilePath": "string"
  }
}
POST/banks/{bankKey}/guide-feedback
Report that a bank's setup guide is wrong

Sends the customer's note about a bank's setup guide to BankConnector. The bank, company and platform are attached from the route and session, so a caller cannot file feedback as another company.

Parameters
NameInRequiredDescription
bankKey BankKeypathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
messagestringyesWhat was confusing, or what the bank did differently.
Example
{
  "companyId": "string",
  "message": "string"
}
Responses
StatusDescription
200Feedback sent
400Empty or over-long message
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
404Unknown bank
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
502The feedback could not be mailed, retry
Example response (200)
{
  "sent": false
}
POST/banks/{bankKey}/guide-access-request
Ask for a gated bank's setup guide

Asks BankConnector to open a gated bank's setup guide and setup for the whole organisation. Any signed-in member may ask. While a request is pending, asking again answers that request with 200. Once approved, setup-info serves the full guide and POST /connections accepts the bank; a declined organisation sees the message on the locked guide and may ask again.

Parameters
NameInRequiredDescription
bankKey BankKeypathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
notestringnoAnything BankConnector should know, such as when the organisation plans to go live.
Example
{
  "companyId": "string",
  "note": "string"
}
Responses
StatusDescription
200A request is already pending; it is answered as it stands
201Request made
400Over-long note
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
404Unknown bank
409The bank's guide is open to everyone, or the organisation already holds it
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "request": {
    "id": "string",
    "bankKey": "string",
    "status": "pending",
    "note": "string",
    "requestedAt": "string",
    "decidedAt": "string",
    "message": "string"
  }
}
POST/banks/{bankKey}/setup-telemetry
Record one setup-card measurement

Setup-card telemetry with three event names that are never summed: card-active is how long the customer worked on one card, bank-wait is how long the bank held that turn, and premature-advance counts a customer settling a turn the bank has not handed back. ms accompanies the first two and must be omitted for the third. environment (test or production) is required. A bank-wait reading only describes a real bank when it came from the production connection, so the operator aggregate groups on it. The payload is the bank, the channel, the environment, the served turn id and one duration; nothing a setup step collected travels here. Readable only on the operator plane, never by a tenant or a platform admin.

Parameters
NameInRequiredDescription
bankKey BankKeypathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
eventenumyes
channelenumyes
environmentenumyes
turnIdstringyes
msintegerno
Example
{
  "companyId": "string",
  "event": "card-active",
  "channel": "sftp",
  "environment": "test",
  "turnId": "string",
  "ms": 0
}
Responses
StatusDescription
202Measurement accepted (recording is fire-and-forget)
400Unknown event, malformed turn id, or a duration the event cannot carry
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
404Unknown bank
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (202)
{
  "accepted": false
}
GET/banks/{bankKey}/settings
Get per-company settings for a specific bank
Parameters
NameInRequiredDescription
bankKey BankKeypathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Bank settings (null if none saved)
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "settings": {
    "companyId": "string",
    "bankKey": "string",
    "agreementId": "string",
    "debtorAgreementId": "string",
    "chargeBearer": "DEBT",
    "executionDateOffsetDays": 0,
    "approvalPolicyId": "string",
    "painVersion": "pain.001.001.03",
    "batchBooking": false,
    "authorisationCode": "AUTH",
    "authorisationProprietary": "string",
    "noApproverCodesEnabled": false,
    "noApproverAuthVendor": "string",
    "noApproverAuthMethod": "string",
    "deriveHybridAddress": false,
    "fillDebtorAddressFromRegisteredAddress": false,
    "memberBankCode": "string",
    "selected": false,
    "setupStep": "string",
    "updatedAt": "string"
  }
}
PATCH/banks/{bankKey}/settings
Update per-company settings for a specific bank (partial patch)

Payment-affecting fields (agreementId, debtorAgreementId, chargeBearer, executionDateOffsetDays, approvalPolicyId, painVersion, batchBooking, authorisationCode, authorisationProprietary) require Admin. The selected pin is open to any member. debtorAgreementId is the bank's second agreement identifier (e.g. the Nordea CAW/CCM agreement number), filled into payments[i].debtor.organisationId (scheme BANK) when the payment omits it; agreementId fills initiatingParty.organisationId (scheme CUST). batchBooking and the authorisation pair are per-agreement pain.001 facts (PmtInf/BtchBookg and GrpHdr/Authstn): omit or send null to keep the bank profile's default. authorisationCode (ISO Authorisation1Code) and authorisationProprietary are mutually exclusive, sending both is a 400. deriveHybridAddress (Admin) turns on town derivation for DE/AT/FI/FR/NL/GB/JE/GG/IM parties whose postalAddress holds address lines but no townName: the postcode and town are taken from the one line shaped "12345 Town" (DE, FI, FR), "1234 Town" (AT), "1234 AB Town" (NL) or "Town AB1 2CD" (GB, JE, GG, IM) to build a hybrid address; a payment whose lines cannot be read with certainty is refused (422) naming the party and the lines, and every derived element is reported in autoFilled. Omit, false or null = off. fillDebtorAddressFromRegisteredAddress (Admin) gives a payment block whose debtor sends no postalAddress, and whose debtor name is the organisation's legal name or organisation name (ignoring case, spacing and punctuation), the organisation's registered address as the payer's address: its street, building number, postcode, town and country subdivision, and its country when the payment sends none. A supplied address element is never changed; a debtor it cannot fill (another name, a registered address without town or country, a different debtor country) carries a BANK_DEBTOR_ADDRESS_NOT_FILLED_* warning, and every filled element is reported in autoFilled. Omit, false or null = off. memberBankCode (any member) names the Sparkasse or cooperative bank the company banks with, on a group profile (sparkasse-de, volksbank-raiffeisenbank-de): a bank code of an institution GET /profiles/members lists under this bank key, a code it took over in a merger included; its own bank code is stored. Any other code is a 400. Null clears it. Once the company has a connection on the profile, or its setup in progress there (selected) names a member, a different member or a clear is refused with 409 member_bank_locked; sending the stored member again passes.

Parameters
NameInRequiredDescription
bankKey BankKeypathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
agreementIdstring | nullno
debtorAgreementIdstring | nullno
chargeBearerstring | nullno
executionDateOffsetDaysinteger | nullno
approvalPolicyIdstring | nullno
painVersionstring | nullno
batchBookingboolean | nullno
authorisationCodestring | nullno
authorisationProprietarystring | nullno
noApproverCodesEnabledboolean | nullno
noApproverAuthVendorstring | nullno
noApproverAuthMethodstring | nullno
deriveHybridAddressboolean | nullno
fillDebtorAddressFromRegisteredAddressboolean | nullno
memberBankCodestring | nullno
selectedbooleanno
setupStepstring | nullno
Example
{
  "companyId": "string",
  "agreementId": "string",
  "debtorAgreementId": "string",
  "chargeBearer": "string",
  "executionDateOffsetDays": 0,
  "approvalPolicyId": "string",
  "painVersion": "string",
  "batchBooking": false,
  "authorisationCode": "string",
  "authorisationProprietary": "string",
  "noApproverCodesEnabled": false,
  "noApproverAuthVendor": "string",
  "noApproverAuthMethod": "string",
  "deriveHybridAddress": false,
  "fillDebtorAddressFromRegisteredAddress": false,
  "memberBankCode": "string",
  "selected": false,
  "setupStep": "string"
}
Responses
StatusDescription
200Settings saved
202Settings saved, but the approval-policy re-bind needs a second Admin's co-sign
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required for payment-affecting fields
404Unknown bank, or `approvalPolicyId` names no approval policy in this company
409The approval-policy re-bind was refused: `approvalPolicyId` names a draft policy, a move for this bank is already awaiting co-sign, or it gives up approval control in a company with no second Admin to co-sign. Or `member_bank_locked`: `memberBankCode` would change the member of a group profile the company has a connection on, or a setup in progress for another member
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "settings": {
    "companyId": "string",
    "bankKey": "string",
    "agreementId": "string",
    "debtorAgreementId": "string",
    "chargeBearer": "DEBT",
    "executionDateOffsetDays": 0,
    "approvalPolicyId": "string",
    "painVersion": "pain.001.001.03",
    "batchBooking": false,
    "authorisationCode": "AUTH",
    "authorisationProprietary": "string",
    "noApproverCodesEnabled": false,
    "noApproverAuthVendor": "string",
    "noApproverAuthMethod": "string",
    "deriveHybridAddress": false,
    "fillDebtorAddressFromRegisteredAddress": false,
    "memberBankCode": "string",
    "selected": false,
    "setupStep": "string",
    "updatedAt": "string"
  }
}
GET/bank-settings
List all per-company bank settings in one call
Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200All saved bank settings for this company
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "settings": [
    {
      "companyId": "string",
      "bankKey": "string",
      "agreementId": "string",
      "debtorAgreementId": "string",
      "chargeBearer": "DEBT",
      "executionDateOffsetDays": 0,
      "approvalPolicyId": "string",
      "painVersion": "pain.001.001.03",
      "batchBooking": false,
      "authorisationCode": "AUTH",
      "authorisationProprietary": "string",
      "noApproverCodesEnabled": false,
      "noApproverAuthVendor": "string",
      "noApproverAuthMethod": "string",
      "deriveHybridAddress": false,
      "fillDebtorAddressFromRegisteredAddress": false,
      "memberBankCode": "string",
      "selected": false,
      "setupStep": "string",
      "updatedAt": "string",
      "setupStepInfo": {
        "index": 0,
        "total": 0,
        "label": "string"
      }
    }
  ]
}
POST/connections/{id}/registry-bank-key
Use BankConnector's copy of the bank's PGP key, or keep your own

Chooses where an SFTP connection takes the bank's PGP public key from: the copy BankConnector keeps for every customer of that bank (use: true), or the copy stored on this connection (use: false). use is required and must be a boolean: an omitted or non-boolean value is refused and nothing changes. fingerprintPin is the 40-hex fingerprint you confirmed with the bank, stored with the choice. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
usebooleanyes
fingerprintPinstringno
Example
{
  "companyId": "string",
  "use": false,
  "fingerprintPin": "string"
}
Responses
StatusDescription
200Updated connection and readiness
400`missing_fields` when `use` is not a boolean, or `validation_failed` when `fingerprintPin` is not the 40-hex fingerprint of the bank's current key
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/deactivate
Deactivate a connection (stop polling and delivery)

Takes an active connection out of service: inbound polling and host-to-host delivery stop. The connection, its keys and its history are kept. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Connection deactivated; updated connection and readiness
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/test-channel
Record whether the bank offers a separate SFTP test channel

SFTP setup: records whether the bank runs a test channel apart from production. supported is required and must be a boolean. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
supportedbooleanyes
Example
{
  "companyId": "string",
  "supported": false
}
Responses
StatusDescription
200Updated connection and readiness
400`missing_fields` when `supported` is not a boolean
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/testing-skipped
Skip, or resume, the SFTP test round

SFTP setup: records the choice to skip testing and go straight to production (skipped: true), or withdraws it (skipped: false) so the test round is part of the connection's flow again. skipped is required and must be a boolean. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
skippedbooleanyes
Example
{
  "companyId": "string",
  "skipped": false
}
Responses
StatusDescription
200Updated connection and readiness
400`missing_fields` when `skipped` is not a boolean
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/demo-scenario
Set the Demo Bank's reply scenario (sandbox and development only)

Sets how the Demo Bank answers the next payment on this connection: demoOutcome (accepted, rejected, partial-batch, delivery-failure or ambiguous-timeout), with an optional demoDelaySeconds, demoRejectReason and demoAuto (false is manual mode: no automatic reply). A field left out keeps its stored value. The Demo Bank only simulates and never reaches a real bank, so a production server refuses the call with 403 demo_bank_disabled_in_production. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
demoOutcomeenumno
demoDelaySecondsintegerno
demoAutobooleanno
demoRejectReasonstringno
Example
{
  "companyId": "string",
  "demoOutcome": "accepted",
  "demoDelaySeconds": 0,
  "demoAuto": false,
  "demoRejectReason": "string"
}
Responses
StatusDescription
200Updated connection and readiness
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required, or `demo_bank_disabled_in_production` on a production server
404`connection_not_found`: no such connection
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/resume-sends
Resume sends to a bank that was paused

Lifts the block on sending payments to this connection's bank after it was paused, either automatically because the approval quorum could not be reached or by an operator. Revise the approval policy or assign approvers first, then call this. The lift is recorded in the audit log. Admin only; a partner user cannot call it.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200The connection, with sends no longer paused
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404`connection_not_found`: no such connection
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  }
}
PUT/connections/{id}/sftp-password
Set the SFTP password (password-authentication banks)

Stores the SFTP password the bank issued, encrypted, for a bank that signs in with a password instead of, or as well as, an SSH key. The password is never returned and never written to the audit log; the log records only that it was set. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
passwordstringyes
Example
{
  "companyId": "string",
  "password": "string"
}
Responses
StatusDescription
200Password stored
400`password_required` when `password` is empty
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connectionId": "string",
  "updated": false
}
PUT/connections/{id}/ws-bank-signing-cert
Pin the certificate the bank signs its Web Services replies with

Stores the X.509 certificate (PEM or base64-DER) the bank published for signing its Web Services replies (Danske Bank, OP). Replies are then verified against it and a mismatch fails closed. Returns the certificate subject and expiry so you can confirm you pinned the right one; the raw certificate is never returned. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
certstringyes
Example
{
  "companyId": "string",
  "cert": "string"
}
Responses
StatusDescription
200Pinned
400`cert_required` when `cert` is empty, `invalid_certificate` when it does not parse
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connectionId": "string",
  "certSubject": "string",
  "certExpiry": "string"
}
PUT/connections/{id}/asic-signing-material
Set the ASiC-E signing certificate and private key (DNB)

Stores the enterprise certificate and the matching private key (both PEM) that sign DNB's ASiC-E payment containers. The key is encrypted at rest, never returned and never written to the audit log. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
certstringyes
keystringyes
Example
{
  "companyId": "string",
  "cert": "string",
  "key": "string"
}
Responses
StatusDescription
200Signing material stored
400`material_required` when `cert` or `key` is missing, or a refusal that says what to fix
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connectionId": "string",
  "updated": false
}
PUT/connections/{id}/abn-xml-signing-material
Set the XML-signature key pair (ABN AMRO)

Stores the private and public key (both PEM) that sign ABN AMRO Access Direct payment files. Send key2 and publicKey2 as well for an agreement that needs a second signature. The keys are encrypted at rest, never returned and never written to the audit log. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
keystringyes
publicKeystringyes
key2stringno
publicKey2stringno
Example
{
  "companyId": "string",
  "key": "string",
  "publicKey": "string",
  "key2": "string",
  "publicKey2": "string"
}
Responses
StatusDescription
200Signing material stored
400`material_required` when `key` or `publicKey` is missing, or a refusal that says what to fix
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connectionId": "string",
  "updated": false
}
POST/connections/{id}/detect-folders
Probe an SFTP connection for its inbox and outbox folders

Read-only SFTP setup helper. Lists the connection's configured upload and download paths and a set of common folder names (up to 20) on the bank's server, so you can pick the right inbox instead of guessing a path that only fails at the first poll. It suggests and never selects, and changes nothing on the server. When the connection holds an MD5 or SHA-1 fingerprint still to check (sftp.hostFingerprintToCheck, saved through server-info), it first compares it with the key the server presents and, on a match, pins that key's SHA-256 in sftp.hostFingerprint; that pin is the one change it can make. A key that does not match is refused, and nothing is stored. Needs the host, username and a key or password saved first. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200One probe result per candidate folder, and the candidate list
400`not_an_sftp_connection`: folder discovery is for SFTP connections
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404`connection_not_found`: no such connection
413The request body is larger than this operation accepts (`payload_too_large`).
422`sftp_not_configured`: enter the host, username and a key or password first
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`sftp_probe_failed`: the bank's SFTP server could not be reached
Example response (200)
{
  "probes": [
    {
      "path": "string",
      "exists": false,
      "fileCount": 0,
      "newestModifiedAt": "string",
      "error": "string",
      "errorCode": 0
    }
  ],
  "candidates": [
    "string"
  ]
}
POST/connections/{id}/folder-health
Check that the configured download folder exists and can be read

Read-only activation pre-check: lists the connection's configured download (inbox) folder on the bank's server, so a wrong path is caught before go-live rather than at the first poll. Changes nothing on the server. When the connection holds an MD5 or SHA-1 fingerprint still to check (sftp.hostFingerprintToCheck, saved through server-info), it first compares it with the key the server presents and, on a match, pins that key's SHA-256 in sftp.hostFingerprint; that pin is the one change it can make. A key that does not match is refused, and nothing is stored. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200The probe result for the download folder (`health`)
400`not_an_sftp_connection`: the check is for SFTP connections
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404`connection_not_found`: no such connection
413The request body is larger than this operation accepts (`payload_too_large`).
422`sftp_not_configured` or `no_download_path`: the host, credentials or download folder are not entered yet
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`sftp_probe_failed`: the bank's SFTP server could not be reached
Example response (200)
{
  "health": {
    "path": "string",
    "exists": false,
    "fileCount": 0,
    "newestModifiedAt": "string",
    "error": "string",
    "errorCode": 0
  }
}
POST/connections/{id}/test-connection
Check an SFTP connection: sign in and list both folders

Signs in to the bank's SFTP server and lists the upload and download folders on that one session. host, port, username, uploadPath and downloadPath in the body win over the saved values, so the check can run on what was just typed; omitted fields use what is saved. The key or password always comes from the stored connection. success is true only when all three checks (sign-in, upload-folder, download-folder) passed; each check reports passed, failed or skipped with a closed reason code, never the server's own text. The check never returns the server's host key. When the connection holds an MD5 or SHA-1 fingerprint still to check (sftp.hostFingerprintToCheck, saved through server-info), the check first compares it with the key the server presents and, on a match, pins that key's SHA-256 in sftp.hostFingerprint; that pin is the one change it can make. A key that does not match is refused, and nothing is stored. A refused key reads host_key_rejected. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
hoststringno
portnumberno
usernamestringno
uploadPathstringno
downloadPathstringno
Example
{
  "companyId": "string",
  "host": "string",
  "port": 0,
  "username": "string",
  "uploadPath": "string",
  "downloadPath": "string"
}
Responses
StatusDescription
200The overall result and one entry per check
400`not_an_sftp_connection`: the check is for SFTP connections
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404`connection_not_found`: no such connection
413The request body is larger than this operation accepts (`payload_too_large`).
422`sftp_not_configured`: enter the host, username and a key or password first
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "success": false,
  "host": "string",
  "port": 0,
  "username": "string",
  "checks": [
    {
      "check": "sign-in",
      "status": "passed",
      "reason": "string",
      "path": "string",
      "fileCount": 0
    }
  ]
}
POST/connections/{id}/ws-certificate
Activate or renew a Web Services connection's certificate

One route for every Web Services family. action: "activate" enrols the connection's certificate with the one-time code its bank issued; action: "renew" replaces the certificate in use before it expires. family must be the connection's own Web Services family, the kind GET /banks/{bankKey}/setup-info serves for its bank (danske-ws, nordea-ca, op-ws, samlink-ws, crosskey-ws, bankconnect); a body for another family is refused with 400 validation_failed before anything reaches the bank. An activation reads only the fields its family's setup-info lists. Refused on a sandbox deployment. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
Example
{
  "companyId": "string",
  "action": "string",
  "family": "danske-ws"
}
Responses
StatusDescription
200Activated or renewed: the connection and its readiness. OP's activation also carries OP's service certificates.
400The request or the act failed and the current credentials are unchanged. `bank_rejected` when the bank answered and refused: `error.details` carries `bankName`, `headline`, `bankText` and `returnCode` (the bank's own reply and code as it sent them, either may be null) and `nextSteps` (what to do next, one sentence each). `bank_connect_not_configured` or `bank_connect_registration_mismatch` on a Bank Connect activation. `validation_failed` for a malformed request, a `family` that is not the connection's own (422 from `BankConnector-Version: 2026-10-21`; before it, a connection that does not use Web Services is this 400 too), or any other failure.
401Sign in required: there is no valid session.
403Admin required, or `sandbox_only`: the act is refused on a sandbox deployment
404`connection_not_found`: no such connection for this company
409`connection_already_activated` (activate): the connection is already activated and live. Send `reenrol: true` with a fresh one-time code, or renew instead. `renewal_in_progress` (renew): a renewal of this connection's certificate is already running (the daily auto-renew sweep or another request); this request did not contact the bank and changed nothing, so reload the connection to see the new expiry when it finishes. `invalid_state` when the connection does not use Web Services, or has no certificate to renew. `invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the call to the bank failed. It was unreachable, timed out, dropped the connection, failed the TLS handshake or answered with a server error, so the act did not complete and the connection's own keys and certificates are unchanged. `error.details` carries `bankName`, `headline` and `nextSteps` (one sentence each); on an activation they say whether the one-time code was sent to the bank. Safe to retry.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "serviceCertificates": [
    {
      "name": "string",
      "sha256": "string",
      "certPem": "string"
    }
  ]
}
POST/connections/{id}/ebics-params
Save EBICS connection parameters (Host ID, Customer ID, User ID, …)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
urlstringnoEBICS server URL.
hostIdstringnoBank-assigned Host ID.
partnerIdstringnoCustomer ID (PartnerID) from the bank.
userIdstringnoSubscriber ID (UserID) from the bank.
protocolVersionenumno
signatureVersionenumnoThe version of the electronic signature (ES) the bank registers at INI. Before the keys go, a new value also moves every approver enrolled on the connection onto a key set in it. It stays fixed once the keys went to the bank: another value is then refused with `400`, because moving to it needs new keys after the bank resets the subscriber. Omit to leave the stored value unchanged.
subscriberModeenumnoDeprecated: use `authorisationMode`. One shared technical subscriber, or one EBICS subscriber per approver. Still accepted and still returned; sending it without `authorisationMode` re-derives that field so the two never disagree.
veuOnlybooleannoPer-user only: this agreement routes every order through VEU (refuses multi-signature uploads), delivery uploads one ES and adds the rest via HVE.
uploaderUserIdstringnoPer-user only: designated uploader (app user id), which subscriber transports payment uploads and acts for VEU orders. Must be a user in this company; the subscriber must be active at delivery time (delivery fails with a clear error otherwise). Empty string clears the designation (default: first active subscriber). May be a non-approver transport-class subscriber for veuOnly agreements.
signatureProfileenumnoDeprecated: use `authorisationMode`. The signature profile this agreement was CONTRACTED on (the French T vs TS), from the bank agreement, not a preference. "TS" (default; at a French bank an unset profile starts as "T") means the electronic signature travelling with an order authorises it inside EBICS. "T" means transport only: the order is authorised on a separate channel, so the signature it carries grants no authorisation and the order omits the EBICS signature flag. A "T" subscriber still holds a signature keypair and still completes INI. Still accepted and still returned; sending it without `authorisationMode` re-derives that field so the two never disagree. Omit to leave the stored value unchanged.
keyManagementenumnoWhich bytes of the bank's key material this agreement's fingerprints are taken over. A property of the AGREEMENT, not of the bank (one bank can offer both). "key" (default) is the SHA-256 of the RSA public key (exponent, blank, modulus); "certificate" is the SHA-256 of the DER-encoded X.509 certificate. The two hash different objects, so CHANGING this clears the "bank keys fetched" step: HPB must be re-run to take a fingerprint in the new mode before the connection can be activated again. Omit to leave the stored value unchanged.
authorisationModeenumnoWHERE this agreement authorises a payment, as the bank agreement names it. "outside-ebics": the order is authorised on a separate channel (the bank's portal, a signed mandate), so the signature riding the upload is transport-only and the order omits the EBICS signature flag (French profil T). "at-upload" (default; at a French bank the default is "outside-ebics", the only arrangement BankConnector offers in France): the signature travelling with the order authorises it inside EBICS. "at-bank": the order is uploaded short of the bank's quorum and the bank spools it, collecting the remaining signatures from the other subscribers (German EDS/VEU). This is the current spelling of what `subscriberMode` and `signatureProfile` say between them; sending it also sets those two, which stay accepted and returned for their deprecation window. Omit to leave the stored value unchanged.
Example
{
  "companyId": "string",
  "url": "string",
  "hostId": "string",
  "partnerId": "string",
  "userId": "string",
  "protocolVersion": "H005",
  "signatureVersion": "A006",
  "subscriberMode": "technical",
  "veuOnly": false,
  "uploaderUserId": "string",
  "signatureProfile": "T",
  "keyManagement": "key",
  "authorisationMode": "outside-ebics"
}
Responses
StatusDescription
200EBICS params saved
400`validation_failed` when the change asks for an arrangement the bank does not offer; the message says why
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`conflict` when an approver was enrolled on the connection while a `signatureVersion` change was being saved; nothing was changed, so save again. `invalid_state` for any field but `veuOnly` on an active connection, or a `signatureVersion` other than the one the bank holds once the keys went. `invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/ebics-generate-keys
Generate EBICS subscriber keys (authentication, encryption, signature)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
subscriberModeenumno
Example
{
  "companyId": "string",
  "subscriberMode": "technical"
}
Responses
StatusDescription
200Keys generated
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/ebics-fetch-htd
Fetch the bank's record of the EBICS agreement (HTD/HKD) and store the discovery snapshot

Runs EBICS HTD (technical subscriber) or HKD (per-user mode) against the bank and persists the result on the connection: accounts on the agreement, permitted order types/BTFs with bank-side signature quorums, and each subscriber's bank-side status + signature class. Requires the bank keys (run ebics-fetch-hpb first). Pre-activation returns notActivatedYet instead of failing, so it can be polled as an activation check. In per-user mode, approvers the bank reports as ready are advanced to active automatically. On a technical connection whose re-key waits for the bank's answer it also settles the re-key, sending no INI or HIA: the new keys become the connection's when the bank answers an HTD signed with them (the bank is then read again with them), and are discarded when the current keys read the subscriber ready after the re-key began.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Discovery result (fetched flag, message, and the parsed agreement data when available)
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the call to the bank failed. The bank could not be reached, timed out, dropped the connection, failed the TLS handshake or answered with a server error, or the host in the connection's address does not exist, so the step did not complete. `error.details` carries `bankName`, `headline` and `nextSteps` (one sentence each). Safe to retry; a host that does not exist needs the address corrected first.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "discovery": {
    "fetched": false,
    "notActivatedYet": false,
    "code": "string",
    "message": "string",
    "data": {
      "via": "HTD",
      "fallbackFrom": {
        "via": "HTD",
        "code": "string"
      },
      "customerName": "string",
      "hostId": "string",
      "accounts": [
        {
          "id": "string",
          "iban": "string",
          "accountNumber": "string",
          "currency": "string",
          "description": "string",
          "usageOrderTypes": []
        }
      ],
      "orderInfo": [
        {
          "adminOrderType": "string",
          "service": {},
          "description": "string",
          "numSigRequired": 0
        }
      ],
      "users": [
        {
          "ebicsUserId": "string",
          "status": 0,
          "statusLabel": "string",
          "name": "string",
          "permissions": []
        }
      ]
    }
  }
}
POST/connections/{id}/ebics-renew
Rotate the EBICS subscriber keys in-band (HCS)

Sends an HCS order: the new three keys (signature/authentication/encryption), authorised by the current signature key. No new INI letter or bank re-activation. Two-phase and key-loss safe: the new keyset is staged before sending and promoted only on a confirmed accept; an ambiguous (post-commit) outcome keeps both keysets and the next call resolves automatically by probing which keyset the bank accepts. Per-user mode rotates one approver at a time (pass userId), and only an approver whose state is active: the bank accepts HCS only from a subscriber it holds as Ready (EBICS 2.5 §4.6.1.1). A technical connection whose keys an emergency suspend locked is refused until a re-key's keys went (ebics-reinitialise with no userId), and one whose re-key waits for the bank answers 409; nothing is sent.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
userIdstringnoPer-user mode: the approver whose subscriber to rotate.
Example
{
  "companyId": "string",
  "userId": "string"
}
Responses
StatusDescription
200Renewal outcome (renewed | ambiguous | resolved-kept-old | resolved-promoted | unresolved)
400`validation_failed`: a renewal on a per-user agreement names no approver
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`conflict`: new keys are already staged on the connection and the bank may hold them, such as an approver's re-initialisation or a technical re-key waiting for the bank's answer, or an earlier renewal. Run `ebics-fetch-htd` ("Refresh from bank") to settle a re-initialisation first. `invalid_state` when a technical connection's keys are suspended by an emergency suspend no re-key has answered, or a per-user approver is not `active`; the message names the next step (the re-key, sending the approver's keys, or the bank's activation), and nothing is sent. `invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the call to the bank failed. The bank could not be reached, timed out, dropped the connection, failed the TLS handshake or answered with a server error, or the host in the connection's address does not exist. `error.details` carries `bankName`, `headline` and `nextSteps` (one sentence each). Where the request could not have left (unreachable, or a host that does not exist) the step did not complete and is safe to retry, once the address is corrected for a host that does not exist. Otherwise the bank may have received it and acted on it, and `headline` says that it cannot be told whether the step took effect; a retry the bank then refuses can mean the first attempt went through.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "renewal": {
    "status": "renewed",
    "message": "string"
  }
}
POST/connections/{id}/ebics-veu-pending
List the orders pending signature at the bank (EBICS VEU / HVU)

Read-only: queries the bank's VEU queue via HVU using the first active per-user subscriber as transport. Returns order type + order number, signature progress (done/required), and whether each order is still signable. Per-user connections only. Normally empty - payments arrive fully signed; a veuOnly agreement or an interrupted co-sign parks orders here.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Pending orders (veuPending array on the connection response)
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the call to the bank failed. The bank could not be reached, timed out, dropped the connection, failed the TLS handshake or answered with a server error, or the host in the connection's address does not exist, so the step did not complete. `error.details` carries `bankName`, `headline` and `nextSteps` (one sentence each). Safe to retry; a host that does not exist needs the address corrected first.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "veuPending": [
    {
      "orderType": "string",
      "orderId": "string",
      "dataDigest": "string",
      "requiredSignatures": 0,
      "doneSignatures": 0,
      "signable": false
    }
  ]
}
POST/connections/{id}/ebics-suspend
Emergency-suspend EBICS access (SPR)

Sends an authenticated SPR order telling the bank to immediately suspend a subscriber's access. For a compromised key. One-way: restoring access needs new keys and letters (a technical connection is re-keyed with ebics-reinitialise and no userId; a per-user approver is re-initialised). A technical connection already suspended from here is refused with 400 validation_failed, and one whose re-key waits for the bank with 409 conflict; nothing is sent. Also deactivates the connection locally so polling/delivery stops. Technical mode suspends the connection's one subscriber. Per-user mode suspends exactly the approvers named in userIds (or userId), one SPR each, and refuses a request naming none; the answer carries one outcome per named approver, and a partial suspend still answers 200.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
userIdsstring[]noPer-user mode: the approvers to suspend. Nobody else is suspended.
userIdstringnoPer-user mode: one approver to suspend (added to `userIds`).
Example
{
  "companyId": "string",
  "userIds": [
    "string"
  ],
  "userId": "string"
}
Responses
StatusDescription
200Suspend result: the bank return code (technical), or one outcome per named approver (per-user): suspended, not-suspended (nothing sent, or the bank refused) or unknown (sent, no readable answer)
400`validation_failed`: a per-user agreement with no approver named
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`conflict`: a technical connection's re-key waits for the bank's answer; nothing is sent. `invalid_state` when a technical connection's keys are already suspended. `invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the call to the bank failed. The bank could not be reached, timed out, dropped the connection, failed the TLS handshake or answered with a server error, or the host in the connection's address does not exist. `error.details` carries `bankName`, `headline` and `nextSteps` (one sentence each). Where the request could not have left (unreachable, or a host that does not exist) the step did not complete and is safe to retry, once the address is corrected for a host that does not exist. Otherwise the bank may have received it and acted on it, and `headline` says that it cannot be told whether the step took effect; a retry the bank then refuses can mean the first attempt went through.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "suspend": {
    "code": "string",
    "message": "string",
    "approvers": [
      {
        "userId": "string",
        "ebicsUserId": "string",
        "outcome": "suspended",
        "code": "string",
        "message": "string"
      }
    ]
  }
}
POST/connections/{id}/ebics-veu-complete
Complete an interrupted VEU co-sign for a pending order (HVE)

Re-drives the remaining approvers' HVE signatures for an order the bank is holding. Identify the payment by documentId, or by the pending order's dataDigest (matched server-side to the sent pain.001). Digest re-checked via HVD before signing. Never co-signs a mismatched order.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
documentIdstringnoThe sent payment (its frozen pain.001 is signed).
orderIdstringnoThe bank order number to select the pending order.
orderDigeststringnoThe pending order's dataDigest, to resolve the payment.
Example
{
  "companyId": "string",
  "documentId": "string",
  "orderId": "string",
  "orderDigest": "string"
}
Responses
StatusDescription
200Co-sign results (per approver) + executionReady
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No sent payment matches the pending order (`not_found`), or no such connection for this company (`connection_not_found`)
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the call to the bank failed. The bank could not be reached, timed out, dropped the connection, failed the TLS handshake or answered with a server error, or the host in the connection's address does not exist. `error.details` carries `bankName`, `headline` and `nextSteps` (one sentence each). Where the request could not have left (unreachable, or a host that does not exist) the step did not complete and is safe to retry, once the address is corrected for a host that does not exist. Otherwise the bank may have received it and acted on it, and `headline` says that it cannot be told whether the step took effect; a retry the bank then refuses can mean the first attempt went through.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "veuComplete": {
    "results": [
      {
        "userId": "string",
        "ebicsUserId": "string",
        "ok": false,
        "error": "string"
      }
    ],
    "executionReady": false
  }
}
GET/connections/{id}/ebics-letter
Download the EBICS initialisation letter (PDF, base64-encoded)

Returns the signed INI/HIA initialisation letter as a base64-encoded PDF. Print, sign, and send to the bank to complete EBICS subscriber activation. While a technical connection's re-key waits for the bank's answer, the letter is for the re-key's new keys.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
userId stringquerynoAn approver's user id: returns that person's own letter, carrying their key hashes and EBICS User ID, in place of the connection's letter.
type enumqueryno`ini` or `hia` returns that one letter; omit it for both. Any other value is ignored.
Responses
StatusDescription
200PDF as base64
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
404No such connection for this company (`connection_not_found`)
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "pdfBase64": "string",
  "filename": "string"
}
POST/connections/{id}/ebics-generate-user-keys
Generate one approver's EBICS subscriber keys (per-user mode)

Per-user EBICS: creates a distinct key set for one approver and enrols it on this connection with the EBICS User ID the bank issued to that person. The Partner ID and Host ID stay shared. The connection switches to per-user mode. A key set that already exists at the bank's key length and the connection's signature version (A005 or A006) is reused, and a key already sent to the bank is never replaced. Sending another ebicsUserId for an approver whose keys are generated but not yet sent corrects their User ID on this connection, keeping their keys; once their keys went to the bank, a different User ID is refused. userId must be a user of this company. The private keys are never returned. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
userIdstringyes
ebicsUserIdstringyes
Example
{
  "companyId": "string",
  "userId": "string",
  "ebicsUserId": "string"
}
Responses
StatusDescription
200Updated connection and readiness
400`missing_fields` when `userId` or `ebicsUserId` is missing, or `user_not_in_company` when the user is not in this company
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/ebics-subscriber-state
Record one approver's activation state at the bank (per-user mode)

Per-user EBICS: moves one approver's subscriber on this connection to ini-hia-sent or active. userId and a state of ini-hia-sent or active are required. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
userIdstringyes
statestringyes
Example
{
  "companyId": "string",
  "userId": "string",
  "state": "string"
}
Responses
StatusDescription
200Updated connection and readiness
400`missing_fields` when `userId` is missing or `state` is not `ini-hia-sent` or `active`
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404`ebics_subscriber_not_found`: that user has no subscriber on this connection; generate their keys first
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/ebics-letters-posted
Record that the signed EBICS initialisation letters were posted to the bank

Moves the connection from ini-hia-sent to awaiting the bank's activation. Nothing is sent to the bank: the call records that you posted the signed letters. A connection that has not yet sent INI and HIA is refused, and a connection already past this step is left as it is. Who recorded it and when is written to the audit log. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Updated connection and readiness
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/ebics-fingerprints-confirmed
Record that the bank's key fingerprints match the published values

Records that you compared the fingerprints of the bank's keys, as fetched with ebics-fetch-hpb, with the values the bank published through another channel, and that they match. The values recorded are the ones already pinned on the connection, never anything in the request. The record is refused before the bank's keys are fetched, and refused with 409 when a fingerprint the bank publishes contradicts the pinned value; it changes nothing once confirmed. It documents a decision; it does not make one, and nothing else is gated on it. Who confirmed it and when is written to the audit log. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Updated connection and readiness
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`ebics_bank_keys_untrusted` with `details.reason` `fingerprint_mismatch`: the keys this connection holds do not match a fingerprint the bank publishes, so nothing was recorded; the message says what to do next. `invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/ebics-authorisation-confirmed
Confirm where this EBICS agreement authorises payments

Settles where the agreement authorises a payment, once the bank's own record of it has been fetched and shown beside your answer. Send authorisationMode only to accept the bank's reading as a correction; send no mode to confirm what the connection already holds. A correction onto an arrangement the bank does not offer (outside-ebics is the only one at a French bank; at-bank is not offered at a bank that runs no distributed signature) is refused, and a connection already on such an arrangement can still confirm it. A correction that would give the bank a different set of subscriber keys is refused. Any other correction applies on an active connection too, and every approved payment over this connection that has not been sent goes back to approval: the first request changes nothing and answers 400 confirmation_required with those payments under error.details.reapproval; send their document ids in reapproveDocumentIds to make the change. No call is made to the bank. Who confirmed it and when is written to the audit log. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
authorisationModeenumno
reapproveDocumentIdsstring[]no
Example
{
  "companyId": "string",
  "authorisationMode": "outside-ebics",
  "reapproveDocumentIds": [
    "string"
  ]
}
Responses
StatusDescription
200Updated connection and readiness
400`validation_failed` for an arrangement the bank does not offer, or one that gives the bank a different set of subscriber keys; `confirmation_required` lists the approved, unsent payments the correction sends back to approval
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`conflict`: a payment on this connection is being sent right now; nothing was changed. `invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test"
}
POST/connections/{id}/ebics-hev
Ask the bank's EBICS host which protocol versions it supports (HEV)

A keyless connectivity check: sends an HEV request to the connection's EBICS URL and returns the versions the bank answers with, under hev. Nothing on the connection changes. A failure to reach the bank is 502 bank_unavailable; to be told reachability as an answer instead, use ebics-hev-probe. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Connection and readiness, with the bank's answer under `hev`
400`validation_failed`: the connection's EBICS address is refused (for example, not https)
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the call to the bank failed. The bank could not be reached, timed out, dropped the connection, failed the TLS handshake or answered with a server error, or the host in the connection's address does not exist, so the step did not complete. `error.details` carries `bankName`, `headline` and `nextSteps` (one sentence each). Safe to retry; a host that does not exist needs the address corrected first.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "hev": {
    "ok": false,
    "returnCode": "string",
    "reportText": "string",
    "message": "string",
    "versions": [
      {
        "protocol": "string",
        "revision": "string"
      }
    ]
  }
}
POST/connections/{id}/ebics-hev-probe
Check whether the bank's EBICS host answers (HEV, reported as an answer)

The reachability question asked on the customer's behalf. It never fails the request: a bank that has not opened its host to this customer yet, or answers with an error code, comes back as hevProbe.ok: false with a sentence, so a screen can show a note instead of an error. It can answer before the connection details are saved, from the bank profile held for that bank. Nothing on the connection changes. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
forcebooleannoAsk the bank again even when an answer for the same URL and Host ID is under ten minutes old.
Example
{
  "companyId": "string",
  "force": false
}
Responses
StatusDescription
200Connection and readiness, with the result under `hevProbe`
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "hevProbe": {
    "probed": false,
    "ok": false,
    "message": "string",
    "h005Supported": false,
    "versions": [
      {
        "protocol": "string",
        "revision": "string"
      }
    ],
    "source": "connection",
    "cached": false
  }
}
POST/connections/{id}/ebics-send-ini
Send the subscriber keys to the bank (INI and HIA, or H3K)

Live bank call. Sends the signature key (INI) and the authentication and encryption keys (HIA) to the bank, or one combined H3K order where the bank's profile documents it. The bank's return codes come back under ini and hia, and under keyHashes the hashes of the keys sent, which the initialisation letter prints. In per-user mode it runs for every approver, or only for userId when given, and advances each accepted subscriber; the results are under subscribers. A round the bank accepted but that was not recorded carries notRecorded saying why. Generate the keys first. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
userIdstringno
Example
{
  "companyId": "string",
  "userId": "string"
}
Responses
StatusDescription
200Connection and readiness, with the bank's answers under `ini`, `hia`, `keyHashes` and `subscribers`
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the call to the bank failed. The bank could not be reached, timed out, dropped the connection, failed the TLS handshake or answered with a server error, or the host in the connection's address does not exist. `error.details` carries `bankName`, `headline` and `nextSteps` (one sentence each). Where the request could not have left (unreachable, or a host that does not exist) the step did not complete and is safe to retry, once the address is corrected for a host that does not exist. Otherwise the bank may have received it and acted on it, and `headline` says that it cannot be told whether the step took effect; a retry the bank then refuses can mean the first attempt went through.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "ini": {
    "ok": false,
    "code": "string",
    "message": "string",
    "reportText": "string",
    "refusal": "string"
  },
  "hia": {
    "ok": false,
    "code": "string",
    "message": "string",
    "reportText": "string",
    "refusal": "string"
  },
  "subscribers": [
    {
      "userId": "string",
      "ebicsUserId": "string",
      "ini": {
        "ok": false,
        "code": "string",
        "message": "string",
        "reportText": "string",
        "refusal": "string"
      },
      "hia": {
        "ok": false,
        "code": "string",
        "message": "string",
        "reportText": "string",
        "refusal": "string"
      },
      "advanced": false,
      "keyHashes": [
        {
          "version": "string",
          "hashRows": []
        }
      ],
      "notRecorded": "user-id-moved"
    }
  ],
  "keyHashes": [
    {
      "version": "string",
      "hashRows": [
        "string"
      ]
    }
  ],
  "notRecorded": "user-id-moved"
}
POST/connections/{id}/ebics-fetch-hpb
Fetch and verify the bank's public keys (HPB)

Live bank call, made after the bank has activated the subscriber. Downloads the bank's authentication and encryption keys, verifies them against the fingerprints the bank profile publishes, and tries to take the connection live. The result is under hpb: whether the keys were fetched and verified, notActivatedYet when the bank has not activated the subscriber, whether the connection was activated, and for keys with no published fingerprint pendingTrust, the fingerprints to compare with the bank's own, and unverifiedRoles. A published fingerprint that does not match, a key-management mode mismatch and an answer naming another Host ID are refused with 409. In per-user mode it runs per subscriber, or only for userId when given. Refused with 400 before the bank is called once the connection has gone live (active or deactivated): use ebics-refetch-hpb, which compares the bank's fingerprints before it stores anything. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
userIdstringno
Example
{
  "companyId": "string",
  "userId": "string"
}
Responses
StatusDescription
200Connection and readiness, with the outcome under `hpb`
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`ebics_bank_keys_untrusted`: the bank's keys were refused and nothing was saved. `details.reason` is `fingerprint_mismatch` (a published fingerprint does not match), `key_mode_mismatch` (the bank publishes fingerprints only for the other key-management mode) or `host_id_mismatch` (the answer names another Host ID); the message says what to do next. `invalid_state` also when the connection has already gone live: fetch the bank's keys again with `ebics-refetch-hpb`. `invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the call to the bank failed. The bank could not be reached, timed out, dropped the connection, failed the TLS handshake or answered with a server error, or the host in the connection's address does not exist, so the step did not complete. `error.details` carries `bankName`, `headline` and `nextSteps` (one sentence each). Safe to retry; a host that does not exist needs the address corrected first.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "hpb": {
    "fetched": false,
    "verified": false,
    "notActivatedYet": false,
    "code": "string",
    "message": "string",
    "activated": false,
    "activationError": "string",
    "subscribers": [
      {
        "userId": "string",
        "ebicsUserId": "string",
        "fetched": false,
        "activated": false,
        "notActivatedYet": false,
        "code": "string",
        "message": "string"
      }
    ],
    "pendingTrust": {
      "authentication": {
        "keyHash": "string",
        "certHash": "string"
      },
      "encryption": {
        "keyHash": "string",
        "certHash": "string"
      },
      "signature": {
        "keyHash": "string",
        "certHash": "string"
      }
    },
    "unverifiedRoles": [
      "string"
    ]
  }
}
POST/connections/{id}/ebics-fetch-hac
Fetch the bank's technical acknowledgements of recent orders (HAC)

Live bank call. Downloads the bank's technical accept or reject acknowledgements of recent orders, which arrive earlier than and below the business pain.002. The result is under hac. An acknowledgement is consumed when it is received, so each entry is also written to the integration log, which is the durable record. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Connection and readiness, with the acknowledgements under `hac`
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the call to the bank failed. The bank could not be reached, timed out, dropped the connection, failed the TLS handshake or answered with a server error, or the host in the connection's address does not exist, so the step did not complete. `error.details` carries `bankName`, `headline` and `nextSteps` (one sentence each). Safe to retry; a host that does not exist needs the address corrected first.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "hac": {
    "fetched": false,
    "notActivatedYet": false,
    "code": "string",
    "message": "string",
    "entries": [
      {
        "orderId": "string",
        "orderType": {
          "orderType": "string",
          "adminOrderType": "string",
          "serviceName": "string",
          "scope": "string",
          "serviceOption": "string",
          "containerType": "string",
          "msgName": "string"
        },
        "action": "string",
        "positive": false,
        "reasonCode": "string",
        "timestamp": "string"
      }
    ]
  }
}
POST/connections/{id}/ebics-refetch-hpb
Fetch the bank's public keys again (HPB) on a connection that holds them

Live bank call for a connection that already holds the bank's keys, a live one included. Runs the same checks as ebics-fetch-hpb: a published fingerprint that does not match, a key-management mode mismatch and an answer naming another Host ID are refused, and nothing is stored. It never activates the connection or moves its setup state. The result is under refetch.outcome: unchanged when the bank presented the keys the connection holds; confirm when it presented different keys, with keyChange listing each role's stored and presented fingerprint and NOTHING stored; replaced when the request carried acceptBankKeys naming exactly the fingerprints the bank presented, in which case the new keys and their fingerprints are stored in one write; not-fetched when the bank answered with a code (code, message). Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
acceptBankKeysobjectno
Example
{
  "companyId": "string",
  "acceptBankKeys": {
    "authentication": "string",
    "encryption": "string"
  }
}
Responses
StatusDescription
200Connection and readiness, with the outcome under `refetch`
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`ebics_bank_keys_untrusted`: the bank's keys were refused and nothing was stored, with `details.reason` as on `ebics-fetch-hpb`. `invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the call to the bank failed. The bank could not be reached, timed out, dropped the connection, failed the TLS handshake or answered with a server error, or the host in the connection's address does not exist, so the step did not complete. `error.details` carries `bankName`, `headline` and `nextSteps` (one sentence each). Safe to retry; a host that does not exist needs the address corrected first.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "refetch": {
    "outcome": "unchanged",
    "verified": false,
    "unverifiedRoles": [
      "string"
    ],
    "keyChange": [
      {
        "role": "authentication",
        "expected": "string",
        "presented": "string"
      }
    ],
    "code": "string",
    "message": "string"
  }
}
POST/connections/{id}/ebics-reinitialise
Re-initialise a suspended EBICS approver, or re-key a technical connection, with new keys

Live bank call. Per-user agreement: for one approver whose subscriber the bank reports as suspended (status 6 or 8). Creates a new key set for that approver, sends INI and HIA, and produces new letters. It is refused unless the bank's own last reading says the approver is suspended. userId is required and must be a user of this company. Technical connection: omit userId to re-key the connection's one subscriber, the way back after an emergency suspend (ebics-suspend). It is refused unless the connection is deactivated. The result is under reinitialise: whether the keys reached the bank (sent), whether the new keys wait for the bank's answer (pendingBankAnswer), and for an approver their bank status and whether their old keys were replaced. Keys the bank does not take never replace the current ones: an approver keeps theirs, and a technical connection keeps its own until a later re-key sends the same new keys. Once a technical connection's new keys are sent, the new letters are the connection's own (ebics-letter), and it is reactivated after the bank activates them. The audit log records the subscriber and the outcome. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
userIdstringno
Example
{
  "companyId": "string",
  "userId": "string"
}
Responses
StatusDescription
200Connection and readiness, with the outcome under `reinitialise`
400`missing_fields` when `userId` is missing on a per-user agreement, or `user_not_in_company` when the user is not in this company
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such connection for this company (`connection_not_found`).
409`invalid_state`: the connection is not at a point that allows this request. A step before it is not done yet, or the connection is live, deactivated or on a channel this action does not apply to; the message says what to do first. Pin `BankConnector-Version: 2026-10-21` to get 409; earlier pins answer `validation_failed` (400, and 422 on `2026-10-20`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
502`bank_unavailable`: the call to the bank failed. The bank could not be reached, timed out, dropped the connection, failed the TLS handshake or answered with a server error, or the host in the connection's address does not exist. `error.details` carries `bankName`, `headline` and `nextSteps` (one sentence each). Where the request could not have left (unreachable, or a host that does not exist) the step did not complete and is safe to retry, once the address is corrected for a host that does not exist. Otherwise the bank may have received it and acted on it, and `headline` says that it cannot be told whether the step took effect; a retry the bank then refuses can mean the first attempt went through.
Example response (200)
{
  "connection": {
    "id": "string",
    "companyId": "string",
    "bankKey": "string",
    "bankName": "string",
    "coveredBankKeys": [
      "string"
    ],
    "status": "setup",
    "deliveryMode": "converted-only",
    "environment": "test",
    "channelType": "sftp",
    "sftp": {
      "host": "string",
      "port": 0,
      "username": "string",
      "uploadPath": "string",
      "downloadPath": "string",
      "downloadHost": "string",
      "answers": {},
      "filename": "string",
      "hostFingerprint": "string",
      "hostFingerprintToCheck": "string",
      "downloadHostFingerprint": "string",
      "allowPlaintext": false,
      "expectedInboundEncryption": "pgp",
      "nextKeys": {
        "pgp": {
          "publicKey": "string",
          "fingerprint": "string",
          "expiresAt": "string",
          "preparedAt": "string"
        },
        "ssh": {
          "publicKey": "string",
          "publicKeyArmored": "string",
          "fingerprint": "string",
          "type": "ed25519",
          "preparedAt": "string"
        }
      },
      "tietoevry": {
        "code": "string",
        "orgNo": "string",
        "custId": "string",
        "bankId": "string",
        "env": "test"
      },
      "demo": {
        "outcome": "accepted",
        "delaySeconds": 0,
        "rejectReason": "string",
        "auto": false
      }
    },
    "webservice": {
      "wsVariant": "danske",
      "endpoint": "string",
      "pkiEndpoint": "string",
      "customerId": "string",
      "senderId": "string",
      "functionId": "string",
      "targetId": "string",
      "receiverId": "string",
      "environment": "TEST",
      "signingCertFingerprint": "string",
      "signingCertSerial": "string",
      "encryptionCertSerial": "string",
      "bankCertAdded": false,
      "bankConnectCamt052": false,
      "answers": {}
    },
    "ebics": {
      "url": "string",
      "hostId": "string",
      "partnerId": "string",
      "userId": "string",
      "protocolVersion": "string",
      "subscriberMode": "technical",
      "signatureVersion": "A005",
      "state": "created",
      "lettersPostedAt": "string",
      "fingerprintConfirmation": {
        "confirmedAt": "string",
        "confirmedBy": "string",
        "confirmedByName": "string",
        "keyManagement": "key",
        "fingerprints": {
          "authentication": "string",
          "encryption": "string"
        }
      },
      "modulusLength": 0,
      "subscriberId": "string",
      "subscriberSignatureCertPem": "string",
      "subscriberAuthCertPem": "string",
      "subscriberEncryptionCertPem": "string",
      "bankAuthPublicKeyPem": "string",
      "bankEncryptionPublicKeyPem": "string",
      "bankKeyHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "bankCertHashesPinned": {
        "authentication": "string",
        "encryption": "string"
      },
      "perUserActivation": {
        "required": 0,
        "active": 0
      },
      "signatureProfile": "T",
      "keyManagement": "key",
      "authorisationMode": "outside-ebics",
      "authorisationConfirmation": {
        "mode": "outside-ebics",
        "bankMode": "outside-ebics",
        "confirmedAt": "string"
      },
      "veuOnly": false,
      "uploaderUserId": "string",
      "bankParams": {
        "bankName": "string",
        "url": "string",
        "hostId": "string",
        "protocolVersions": [
          "string"
        ],
        "authenticationVersions": [
          "string"
        ],
        "encryptionVersions": [
          "string"
        ],
        "signatureVersions": [
          "string"
        ],
        "recoverySupported": false,
        "preValidationSupported": false,
        "clientDataDownloadSupported": false,
        "downloadableOrderDataSupported": false,
        "fetchedAt": "string"
      },
      "hev": {
        "checkedAt": "string",
        "versions": [
          {}
        ],
        "h005Supported": false,
        "profileMismatch": {
          "profile": [],
          "host": []
        },
        "ok": false,
        "message": "string",
        "source": "connection",
        "url": "string",
        "hostId": "string"
      },
      "discovery": {
        "via": "HTD",
        "fallbackFrom": {
          "via": "HTD",
          "code": "string"
        },
        "customerName": "string",
        "hostId": "string",
        "accounts": [
          {}
        ],
        "orderInfo": [
          {}
        ],
        "users": [
          {}
        ],
        "fetchedAt": "string"
      },
      "agreementMismatches": [
        {
          "kind": "signature-class",
          "configured": "string",
          "bank": "string",
          "consequence": "string",
          "blocking": false
        }
      ],
      "agreementRefresh": {
        "attemptedAt": "string",
        "ok": false,
        "message": "string"
      },
      "reportCoverage": {
        "source": "contract",
        "fallback": "no-agreement-record",
        "reports": [
          "string"
        ],
        "noStatusReportFor": [
          "string"
        ]
      },
      "stagedRenewal": {
        "subscriberMode": "technical",
        "userId": "string",
        "ebicsUserId": "string",
        "startedAt": "string",
        "ambiguous": false
      },
      "deactivatedAt": "string",
      "sprSuspension": {
        "at": "string",
        "mode": "technical",
        "userIds": [
          "string"
        ],
        "unconfirmedUserIds": [
          "string"
        ]
      },
      "technicalRekey": {
        "stagedAt": "string",
        "sentAt": "string"
      }
    },
    "pgpFingerprint": "string",
    "pgpPublicKey": "string",
    "pgpExpiresAt": "string",
    "bankPgpPublicKey": "string",
    "useRegistryBankKey": false,
    "bankKeyFingerprintPin": "string",
    "bankPgpKeyInfo": {
      "keyId": "string",
      "fingerprint": "string",
      "userId": "string",
      "algorithm": "string",
      "createdAt": "string",
      "expiresAt": "string"
    },
    "sshPublicKey": "string",
    "sshPublicKeyArmored": "string",
    "sshFingerprint": "string",
    "sshKeyType": "ed25519",
    "abnXmlSigningPublicKey": "string",
    "abnXmlSigningFingerprint": "string",
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "sftpTestingSkipped": false,
      "wsConfigAdded": false,
      "bankCertAdded": false,
      "certsIssued": false,
      "hevChecked": false,
      "ebicsKeysGenerated": false,
      "ebicsIniHiaSent": false,
      "ebicsLetterSent": false,
      "ebicsBankKeysFetched": false,
      "abnXmlSigningKeyGenerated": false,
      "sftpPasswordSet": false,
      "approversAssigned": false
    },
    "ingestedFiles": [
      "string"
    ],
    "productionVerifiedAt": "string",
    "connectedAt": "string",
    "testChannelSupported": false,
    "signingCertExpiresAt": "string",
    "tlsPins": [
      "string"
    ],
    "wsCertExpiresAt": "string",
    "wsBankCertExpiresAt": "string",
    "wsBankSigningCertExpiresAt": "string",
    "asicCertExpiresAt": "string",
    "certAlertSent": {},
    "pollIntervalSeconds": 0,
    "lastPolledAt": "string",
    "consecutivePollFailures": 0,
    "pollFailureAlertSentAt": "string",
    "sendsPaused": false,
    "sendsPausedAt": "string",
    "sendsPausedReason": "string",
    "createdAt": "string",
    "updatedAt": "string",
    "signingCertSubject": "string",
    "signingCertExpiry": "string",
    "inboundHealth": {
      "status": "live",
      "consecutiveFailures": 0,
      "threshold": 0,
      "reasons": [
        "string"
      ]
    }
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ]
  },
  "group": {
    "groupId": "string",
    "groupName": "string",
    "members": [
      "string"
    ],
    "suggestedCoveredBankKeys": [
      "string"
    ]
  },
  "productionState": "test",
  "reinitialise": {
    "userId": "string",
    "ebicsUserId": "string",
    "bankStatus": 0,
    "sent": false,
    "keysReplaced": false,
    "pendingBankAnswer": false,
    "send": {
      "userId": "string",
      "ebicsUserId": "string",
      "ini": {
        "ok": false,
        "code": "string",
        "message": "string",
        "reportText": "string",
        "refusal": "string"
      },
      "hia": {
        "ok": false,
        "code": "string",
        "message": "string",
        "reportText": "string",
        "refusal": "string"
      },
      "advanced": false,
      "keyHashes": [
        {
          "version": "string",
          "hashRows": []
        }
      ],
      "notRecorded": "user-id-moved"
    },
    "previousKeysetDestroyed": false,
    "previousKeysStillAt": [
      "string"
    ],
    "message": "string"
  }
}
GET/connections/{id}/ebics-subscribers
List the approvers enrolled on an EBICS connection (per-user mode)

Each approver enrolled on this connection with the EBICS User ID this bank issued, their activation state at the bank (keys-generated, ini-hia-sent or active), signature version and key length. An approver whose key set serves only another bank is not listed. Key material is never returned.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The enrolled subscribers
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "subscribers": [
    {
      "userId": "string",
      "ebicsUserId": "string",
      "state": "keys-generated",
      "signatureVersion": "A005",
      "modulusLength": 0
    }
  ]
}

Approvals

Maker-checker approval policies + the pending-approval queue (session, Admin/Approver)

GET/approvals/pending
List payments awaiting approval

For a signed-in user this is a PERSONAL queue: only the requests waiting on that user's own signature: they are a designated approver for it, they did not raise it under maker-checker, and they have not already signed it. Two approvers in one company therefore get different lists. An API-key caller has no user and receives the company's whole list, as does any caller asking for the decided trail (?status=approved / ?status=rejected), except a person signed in inside the ERP add-on, who receives, for every status, exactly the requests GET /approvals/{id} opens for them, each with its erpDecision.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
status enumqueryno`pending` (the default) is the queue described above; `approved` or `rejected` is the company's decided trail.
cursor stringquerynoThe previous page's `nextCursor`: the page continues after that request.
after stringquerynoDeprecated alias of `cursor`; `cursor` wins when both are sent.
limit integerquerynoPage size, at most 500.
Responses
StatusDescription
200Pending approval requests
400A `status` or `limit` that is not valid (`invalid_parameter`), or a malformed `cursor` (`invalid_cursor`).
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "companyId": "string",
      "documentId": "string",
      "paymentRef": "string",
      "source": {
        "reference": "string",
        "name": "string"
      },
      "erpNotes": [
        {
          "kind": "payee-account-changed",
          "paymentRef": "string",
          "from": "string",
          "to": "string",
          "shownTo": "string",
          "shownAt": "string"
        }
      ],
      "makerUserId": "string",
      "makerName": "string",
      "makerClaimedEmail": "string",
      "maxTransaction": "string",
      "journalTotal": "string",
      "currency": "string",
      "currencies": [
        "string"
      ],
      "payeeName": "string",
      "payeeCount": 0,
      "fundingAccount": {
        "iban": "string",
        "accountOther": "string",
        "bankKey": "string",
        "accounts": [
          {}
        ]
      },
      "policyVersionId": "string",
      "requiredApprovals": 0,
      "allowSelfApproval": false,
      "approverLimits": {},
      "requireOneFromEachGroup": false,
      "orderedApproval": false,
      "groups": [
        {
          "id": "string",
          "name": "string",
          "userIds": []
        }
      ],
      "approverUserIds": [
        "string"
      ],
      "approvals": [
        {
          "userId": "string",
          "userName": "string",
          "at": "string",
          "identity": {},
          "ebicsEs": {},
          "channel": "string",
          "authorityLapsed": "deactivated"
        }
      ],
      "rejections": [
        {
          "userId": "string",
          "userName": "string",
          "at": "string",
          "identity": {},
          "ebicsEs": {},
          "reason": "string",
          "channel": "string"
        }
      ],
      "status": "pending",
      "createdAt": "string",
      "updatedAt": "string",
      "evaluation": {
        "satisfied": false,
        "missing": [
          "string"
        ],
        "approverCount": 0,
        "uncompletableReason": "string"
      },
      "twoFactorRequired": false,
      "erpDecision": {
        "allowed": false,
        "reason": "string"
      }
    }
  ],
  "nextCursor": "string"
}
GET/approvals/oversight
List every payment awaiting approval in the company (Admin, read-only)

The Admin OVERSIGHT view of GET /approvals/pending, which is a PERSONAL queue: an Admin who is not a designated approver is waiting on nothing and correctly sees an empty queue there. This returns the company's whole pending list instead, within the caller's own organisation. It is VISIBILITY only and confers no eligibility: approving and rejecting stay on POST /approvals/{id}/approve and /reject, which admit a designated approver alone. Rows therefore carry no twoFactorRequired: that field is the decide queue's per-caller step-up signal for a signature this caller does not record. Pending only; the decided trail is already company-wide on /approvals/pending?status=approved|rejected.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
cursor stringquerynoThe previous page's `nextCursor`: the page continues after that request.
after stringquerynoDeprecated alias of `cursor`; `cursor` wins when both are sent.
limit integerquerynoPage size, at most 500.
Responses
StatusDescription
200Every pending approval request in the company. The standard { items, nextCursor } envelope
400A `limit` that is not valid (`invalid_parameter`), or a malformed `cursor` (`invalid_cursor`).
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "companyId": "string",
      "documentId": "string",
      "paymentRef": "string",
      "source": {
        "reference": "string",
        "name": "string"
      },
      "erpNotes": [
        {
          "kind": "payee-account-changed",
          "paymentRef": "string",
          "from": "string",
          "to": "string",
          "shownTo": "string",
          "shownAt": "string"
        }
      ],
      "makerUserId": "string",
      "makerName": "string",
      "makerClaimedEmail": "string",
      "maxTransaction": "string",
      "journalTotal": "string",
      "currency": "string",
      "currencies": [
        "string"
      ],
      "payeeName": "string",
      "payeeCount": 0,
      "fundingAccount": {
        "iban": "string",
        "accountOther": "string",
        "bankKey": "string",
        "accounts": [
          {}
        ]
      },
      "policyVersionId": "string",
      "requiredApprovals": 0,
      "allowSelfApproval": false,
      "approverLimits": {},
      "requireOneFromEachGroup": false,
      "orderedApproval": false,
      "groups": [
        {
          "id": "string",
          "name": "string",
          "userIds": []
        }
      ],
      "approverUserIds": [
        "string"
      ],
      "approvals": [
        {
          "userId": "string",
          "userName": "string",
          "at": "string",
          "identity": {},
          "ebicsEs": {},
          "channel": "string",
          "authorityLapsed": "deactivated"
        }
      ],
      "rejections": [
        {
          "userId": "string",
          "userName": "string",
          "at": "string",
          "identity": {},
          "ebicsEs": {},
          "reason": "string",
          "channel": "string"
        }
      ],
      "status": "pending",
      "createdAt": "string",
      "updatedAt": "string",
      "evaluation": {
        "satisfied": false,
        "missing": [
          "string"
        ],
        "approverCount": 0,
        "uncompletableReason": "string"
      }
    }
  ],
  "nextCursor": "string"
}
GET/approvals/{id}
One approval request, with what it decides on

The request, its evaluation, its payment lines (payee, account, amount, currency, execution date, remittance), per-currency totals and the contentDigest a decision from the ERP add-on must echo. A person signed in inside the ERP add-on reads only a request that names them as an approver; any other id answers 404. erpDecision says whether the add-on may decide it.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The request
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
404No such request in this organisation (or not one that names this ERP sign-in)
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "request": {
    "id": "string",
    "companyId": "string",
    "documentId": "string",
    "paymentRef": "string",
    "source": {
      "reference": "string",
      "name": "string"
    },
    "erpNotes": [
      {
        "kind": "payee-account-changed",
        "paymentRef": "string",
        "from": "string",
        "to": "string",
        "shownTo": "string",
        "shownAt": "string"
      }
    ],
    "makerUserId": "string",
    "makerName": "string",
    "makerClaimedEmail": "string",
    "maxTransaction": "string",
    "journalTotal": "string",
    "currency": "string",
    "currencies": [
      "string"
    ],
    "payeeName": "string",
    "payeeCount": 0,
    "fundingAccount": {
      "iban": "string",
      "accountOther": "string",
      "bankKey": "string",
      "accounts": [
        {
          "iban": "string",
          "accountOther": "string",
          "totals": []
        }
      ]
    },
    "policyVersionId": "string",
    "requiredApprovals": 0,
    "allowSelfApproval": false,
    "approverLimits": {},
    "requireOneFromEachGroup": false,
    "orderedApproval": false,
    "groups": [
      {
        "id": "string",
        "name": "string",
        "userIds": [
          "string"
        ]
      }
    ],
    "approverUserIds": [
      "string"
    ],
    "approvals": [
      {
        "userId": "string",
        "userName": "string",
        "at": "string",
        "identity": {
          "approverUserId": "string",
          "approverName": "string",
          "approvedAt": "string",
          "authMethod": "totp",
          "ssnFirst6": "string",
          "approvalReference": "string"
        },
        "ebicsEs": {
          "signatureVersion": "A005",
          "signatureB64": "string",
          "ebicsUserId": "string",
          "orderSha256B64": "string"
        },
        "channel": "string",
        "authorityLapsed": "deactivated"
      }
    ],
    "rejections": [
      {
        "userId": "string",
        "userName": "string",
        "at": "string",
        "identity": {
          "approverUserId": "string",
          "approverName": "string",
          "approvedAt": "string",
          "authMethod": "totp",
          "ssnFirst6": "string",
          "approvalReference": "string"
        },
        "ebicsEs": {
          "signatureVersion": "A005",
          "signatureB64": "string",
          "ebicsUserId": "string",
          "orderSha256B64": "string"
        },
        "reason": "string",
        "channel": "string"
      }
    ],
    "status": "pending",
    "createdAt": "string",
    "updatedAt": "string"
  },
  "evaluation": {
    "satisfied": false,
    "missing": [
      "string"
    ],
    "approverCount": 0,
    "uncompletableReason": "string"
  },
  "lines": [
    {
      "paymentId": "string",
      "executionDate": "string",
      "endToEndId": "string",
      "payee": "string",
      "account": "string",
      "amount": "string",
      "currency": "string",
      "remittance": [
        "string"
      ]
    }
  ],
  "totals": [
    {
      "currency": "string",
      "amount": "string",
      "count": 0
    }
  ],
  "contentDigest": "string",
  "bankKey": "string",
  "environment": "string",
  "erpDecision": {
    "allowed": false,
    "reason": "string"
  }
}
POST/approvals/{id}/approve
Approve a pending payment (maker ≠ checker enforced)

An approver other than the maker approves the request; once the policy's required approvals are met the payment proceeds to delivery.

Step-up: when the approver is enrolled in 2FA, or their company requires it, every approval carries a current authenticator code (or a backupCode); there is no recently-verified window. twoFactorRequired on the pending request says so up front. A passed step-up rotates a cookie session (fresh bc_session and bc_csrf cookies on the response); a header-token session is left as it is.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
reasonstringno
codestringno2FA TOTP code (if step-up required).
backupCodestringno
contentDigeststringnoERP add-on only (required there): the `contentDigest` GET /approvals/{id} returned. A mismatch is 409 `content_changed`.
Example
{
  "companyId": "string",
  "reason": "string",
  "code": "string",
  "backupCode": "string",
  "contentDigest": "string"
}
Responses
StatusDescription
200Approval recorded (and payment dispatched if fully approved)
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`), and so is a signed-in user without the Approver role.
404No approval request with this id (`not_found`)
409The decision conflicts with the request's state or the caller's role in it: `maker_checker_conflict` (maker cannot approve own payment), `approver_not_designated`, `already_approved`, `not_pending`, `approval_out_of_order`, `document_unavailable` (the payment's document is gone, retention destroyed it while this request was still pending)
413The request body is larger than this operation accepts (`payload_too_large`).
422Step-up refused: `totp_required` (the 2FA code is missing or wrong) or `totp_enrollment_required` (the company requires 2FA and this approver has not set it up). Also `approver_ssn_required` or `ebics_signer_missing` when the bank needs a credential only the approver can supply, and `validation_failed` for a body that fails the route's schema (pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400).
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
500The decision could not be recorded (`internal_error`)
Example response (200)
{
  "request": {
    "id": "string",
    "companyId": "string",
    "documentId": "string",
    "paymentRef": "string",
    "source": {
      "reference": "string",
      "name": "string"
    },
    "erpNotes": [
      {
        "kind": "payee-account-changed",
        "paymentRef": "string",
        "from": "string",
        "to": "string",
        "shownTo": "string",
        "shownAt": "string"
      }
    ],
    "makerUserId": "string",
    "makerName": "string",
    "makerClaimedEmail": "string",
    "maxTransaction": "string",
    "journalTotal": "string",
    "currency": "string",
    "currencies": [
      "string"
    ],
    "payeeName": "string",
    "payeeCount": 0,
    "fundingAccount": {
      "iban": "string",
      "accountOther": "string",
      "bankKey": "string",
      "accounts": [
        {
          "iban": "string",
          "accountOther": "string",
          "totals": []
        }
      ]
    },
    "policyVersionId": "string",
    "requiredApprovals": 0,
    "allowSelfApproval": false,
    "approverLimits": {},
    "requireOneFromEachGroup": false,
    "orderedApproval": false,
    "groups": [
      {
        "id": "string",
        "name": "string",
        "userIds": [
          "string"
        ]
      }
    ],
    "approverUserIds": [
      "string"
    ],
    "approvals": [
      {
        "userId": "string",
        "userName": "string",
        "at": "string",
        "identity": {
          "approverUserId": "string",
          "approverName": "string",
          "approvedAt": "string",
          "authMethod": "totp",
          "ssnFirst6": "string",
          "approvalReference": "string"
        },
        "ebicsEs": {
          "signatureVersion": "A005",
          "signatureB64": "string",
          "ebicsUserId": "string",
          "orderSha256B64": "string"
        },
        "channel": "string",
        "authorityLapsed": "deactivated"
      }
    ],
    "rejections": [
      {
        "userId": "string",
        "userName": "string",
        "at": "string",
        "identity": {
          "approverUserId": "string",
          "approverName": "string",
          "approvedAt": "string",
          "authMethod": "totp",
          "ssnFirst6": "string",
          "approvalReference": "string"
        },
        "ebicsEs": {
          "signatureVersion": "A005",
          "signatureB64": "string",
          "ebicsUserId": "string",
          "orderSha256B64": "string"
        },
        "reason": "string",
        "channel": "string"
      }
    ],
    "status": "pending",
    "createdAt": "string",
    "updatedAt": "string"
  },
  "evaluation": {
    "satisfied": false,
    "missing": [
      "string"
    ],
    "approverCount": 0,
    "uncompletableReason": "string"
  },
  "documentStatus": "string"
}
POST/approvals/{id}/reject
Reject a pending payment

A veto, and final for the payment. In the same transaction as the request's rejected, the payment document moves to the terminal status rejected-by-approver: it will never be sent, and no later approval can revive it. Sending the payment anyway means submitting a new payment, with a new messageId (the vetoed one's is refused with 409 message_id_already_used). The webhook for a veto is approval.rejected; no payment.* event fires for it. rejected-by-approver is distinct from rejected, which only ever means the bank rejected a file it received.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
reasonstringno
codestringno
backupCodestringno
contentDigeststringno
Example
{
  "companyId": "string",
  "reason": "string",
  "code": "string",
  "backupCode": "string",
  "contentDigest": "string"
}
Responses
StatusDescription
200Rejection recorded
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`), and so is a signed-in user without the Approver role.
404No approval request with this id (`not_found`)
409The decision conflicts with the request's state or the caller's role in it: `maker_checker_conflict`, `approver_not_designated`, `already_approved`, `not_pending`, `approval_out_of_order`
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
500The decision could not be recorded (`internal_error`)
Example response (200)
{
  "request": {
    "id": "string",
    "companyId": "string",
    "documentId": "string",
    "paymentRef": "string",
    "source": {
      "reference": "string",
      "name": "string"
    },
    "erpNotes": [
      {
        "kind": "payee-account-changed",
        "paymentRef": "string",
        "from": "string",
        "to": "string",
        "shownTo": "string",
        "shownAt": "string"
      }
    ],
    "makerUserId": "string",
    "makerName": "string",
    "makerClaimedEmail": "string",
    "maxTransaction": "string",
    "journalTotal": "string",
    "currency": "string",
    "currencies": [
      "string"
    ],
    "payeeName": "string",
    "payeeCount": 0,
    "fundingAccount": {
      "iban": "string",
      "accountOther": "string",
      "bankKey": "string",
      "accounts": [
        {
          "iban": "string",
          "accountOther": "string",
          "totals": []
        }
      ]
    },
    "policyVersionId": "string",
    "requiredApprovals": 0,
    "allowSelfApproval": false,
    "approverLimits": {},
    "requireOneFromEachGroup": false,
    "orderedApproval": false,
    "groups": [
      {
        "id": "string",
        "name": "string",
        "userIds": [
          "string"
        ]
      }
    ],
    "approverUserIds": [
      "string"
    ],
    "approvals": [
      {
        "userId": "string",
        "userName": "string",
        "at": "string",
        "identity": {
          "approverUserId": "string",
          "approverName": "string",
          "approvedAt": "string",
          "authMethod": "totp",
          "ssnFirst6": "string",
          "approvalReference": "string"
        },
        "ebicsEs": {
          "signatureVersion": "A005",
          "signatureB64": "string",
          "ebicsUserId": "string",
          "orderSha256B64": "string"
        },
        "channel": "string",
        "authorityLapsed": "deactivated"
      }
    ],
    "rejections": [
      {
        "userId": "string",
        "userName": "string",
        "at": "string",
        "identity": {
          "approverUserId": "string",
          "approverName": "string",
          "approvedAt": "string",
          "authMethod": "totp",
          "ssnFirst6": "string",
          "approvalReference": "string"
        },
        "ebicsEs": {
          "signatureVersion": "A005",
          "signatureB64": "string",
          "ebicsUserId": "string",
          "orderSha256B64": "string"
        },
        "reason": "string",
        "channel": "string"
      }
    ],
    "status": "pending",
    "createdAt": "string",
    "updatedAt": "string"
  },
  "evaluation": {
    "satisfied": false,
    "missing": [
      "string"
    ],
    "approverCount": 0,
    "uncompletableReason": "string"
  },
  "documentStatus": "string"
}
GET/approvals/policies
List approval policies for a company
Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Policies: the standard { items } envelope, one row per policy
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "name": "string",
      "template": "single",
      "enabled": false,
      "requiredApprovals": 0,
      "allowSelfApproval": false,
      "perTransactionLimit": "string",
      "perJournalLimit": "string",
      "perTransactionMax": "string",
      "requireOneFromEachGroup": false,
      "orderedApproval": false,
      "groups": [
        {
          "id": "string",
          "name": "string",
          "userIds": []
        }
      ],
      "id": "string",
      "isDefault": false,
      "status": "draft",
      "createdBy": "string",
      "locked": false,
      "lockedAt": "string",
      "lockedBy": "string",
      "revisionRequired": false,
      "activeApprovers": 0,
      "requiredApprovers": 0,
      "governsBanksWithoutPolicy": false,
      "selfApprovalCappedByOrgSetting": false
    }
  ]
}
POST/approvals/policies
Create an approval policy (Admin)

Defines required approver count + amount thresholds. Admin only.

Request body required
PropertyTypeRequiredDescription
companyIdstringyes
idstringno
namestringno
templatestringno
approversstring[]no
isDefaultbooleanno
enabledbooleanno
requiredApprovalsnumberno
allowSelfApprovalbooleanno
approverLimitsobjectno
perTransactionLimitstring | nullno
perJournalLimitstring | nullno
perTransactionMaxstring | nullno
requireOneFromEachGroupbooleanno
orderedApprovalbooleanno
groupsobject[]no
lockedbooleanno
lockedAtstringno
lockedBystringno
Example
{
  "companyId": "string",
  "id": "string",
  "name": "string",
  "template": "string",
  "approvers": [
    "string"
  ],
  "isDefault": false,
  "enabled": false,
  "requiredApprovals": 0,
  "allowSelfApproval": false,
  "approverLimits": {},
  "perTransactionLimit": "string",
  "perJournalLimit": "string",
  "perTransactionMax": "string",
  "requireOneFromEachGroup": false,
  "orderedApproval": false,
  "groups": [
    {
      "id": "string",
      "name": "string",
      "userIds": [
        "string"
      ]
    }
  ],
  "locked": false,
  "lockedAt": "string",
  "lockedBy": "string"
}
Responses
StatusDescription
201Policy created
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (201)
{
  "policy": {
    "name": "string",
    "template": "single",
    "enabled": false,
    "requiredApprovals": 0,
    "allowSelfApproval": false,
    "perTransactionLimit": "string",
    "perJournalLimit": "string",
    "perTransactionMax": "string",
    "requireOneFromEachGroup": false,
    "orderedApproval": false,
    "groups": [
      {
        "id": "string",
        "name": "string",
        "userIds": [
          "string"
        ]
      }
    ],
    "id": "string",
    "isDefault": false,
    "status": "draft",
    "createdBy": "string",
    "locked": false,
    "lockedAt": "string",
    "lockedBy": "string"
  },
  "pending": false,
  "selfApprovalCappedByOrgSetting": false
}
POST/approvals/policies/{id}
Edit an approval policy (Admin)

Edit a policy's name / approvers / required approver count / thresholds. The policy is changed in place and keeps its id; every change is logged with the rule before and after. A DRAFT is saved as a draft. On an ACTIVE policy a change that gives up no approval control is in force at once (200); a change that weakens control is held on a change request until a second, distinct Admin co-signs it (202), and the policy keeps its current rule until then. A body that changes nothing writes nothing (200 with unchanged: true).

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
idstringno
namestringno
templatestringno
approversstring[]no
isDefaultbooleanno
enabledbooleanno
requiredApprovalsnumberno
allowSelfApprovalbooleanno
approverLimitsobjectno
perTransactionLimitstring | nullno
perJournalLimitstring | nullno
perTransactionMaxstring | nullno
requireOneFromEachGroupbooleanno
orderedApprovalbooleanno
groupsobject[]no
lockedbooleanno
lockedAtstringno
lockedBystringno
Example
{
  "companyId": "string",
  "id": "string",
  "name": "string",
  "template": "string",
  "approvers": [
    "string"
  ],
  "isDefault": false,
  "enabled": false,
  "requiredApprovals": 0,
  "allowSelfApproval": false,
  "approverLimits": {},
  "perTransactionLimit": "string",
  "perJournalLimit": "string",
  "perTransactionMax": "string",
  "requireOneFromEachGroup": false,
  "orderedApproval": false,
  "groups": [
    {
      "id": "string",
      "name": "string",
      "userIds": [
        "string"
      ]
    }
  ],
  "locked": false,
  "lockedAt": "string",
  "lockedBy": "string"
}
Responses
StatusDescription
200Saved and IN FORCE now, or nothing to change (`unchanged: true`)
202Accepted: not in force; `change` is the request a second Admin must co-sign
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
409A change to this policy is already awaiting co-sign / conflict
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "policy": {
    "name": "string",
    "template": "single",
    "enabled": false,
    "requiredApprovals": 0,
    "allowSelfApproval": false,
    "perTransactionLimit": "string",
    "perJournalLimit": "string",
    "perTransactionMax": "string",
    "requireOneFromEachGroup": false,
    "orderedApproval": false,
    "groups": [
      {
        "id": "string",
        "name": "string",
        "userIds": [
          "string"
        ]
      }
    ],
    "id": "string",
    "isDefault": false,
    "status": "draft",
    "createdBy": "string",
    "locked": false,
    "lockedAt": "string",
    "lockedBy": "string"
  },
  "pending": false,
  "unchanged": false,
  "resumedBanks": [
    "string"
  ],
  "selfApprovalCappedByOrgSetting": false
}
POST/approvals/policies/{id}/lock
Activate (lock) a draft approval policy (Admin)

Locks a DRAFT policy → Active. Runs the quorum check (a dual policy needs ≥2 named approvers); fails 409 if it can't be met. An Active policy is changed by editing it (POST /approvals/policies/{id}).

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
idstringno
namestringno
templatestringno
approversstring[]no
isDefaultbooleanno
enabledbooleanno
requiredApprovalsnumberno
allowSelfApprovalbooleanno
approverLimitsobjectno
perTransactionLimitstring | nullno
perJournalLimitstring | nullno
perTransactionMaxstring | nullno
requireOneFromEachGroupbooleanno
orderedApprovalbooleanno
groupsobject[]no
lockedbooleanno
lockedAtstringno
lockedBystringno
Example
{
  "companyId": "string",
  "id": "string",
  "name": "string",
  "template": "string",
  "approvers": [
    "string"
  ],
  "isDefault": false,
  "enabled": false,
  "requiredApprovals": 0,
  "allowSelfApproval": false,
  "approverLimits": {},
  "perTransactionLimit": "string",
  "perJournalLimit": "string",
  "perTransactionMax": "string",
  "requireOneFromEachGroup": false,
  "orderedApproval": false,
  "groups": [
    {
      "id": "string",
      "name": "string",
      "userIds": [
        "string"
      ]
    }
  ],
  "locked": false,
  "lockedAt": "string",
  "lockedBy": "string"
}
Responses
StatusDescription
200Policy activated
202Accepted: not active; `change` is the request a second Admin must co-sign
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
409Quorum not met / conflict
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "policy": {
    "name": "string",
    "template": "single",
    "enabled": false,
    "requiredApprovals": 0,
    "allowSelfApproval": false,
    "perTransactionLimit": "string",
    "perJournalLimit": "string",
    "perTransactionMax": "string",
    "requireOneFromEachGroup": false,
    "orderedApproval": false,
    "groups": [
      {
        "id": "string",
        "name": "string",
        "userIds": [
          "string"
        ]
      }
    ],
    "id": "string",
    "isDefault": false,
    "status": "draft",
    "createdBy": "string",
    "locked": false,
    "lockedAt": "string",
    "lockedBy": "string"
  },
  "pending": false,
  "unchanged": false,
  "resumedBanks": [
    "string"
  ],
  "selfApprovalCappedByOrgSetting": false
}
GET/approvals/bank-rosters
Who may approve payments on each covered bank

One row per covered bank (danske-dk). Never per connection: one connection may serve several country banks. bound: false means the bank inherits the company default (which is also what a bank added tomorrow gets); sharedWith names the other banks in the query that resolve to the same policy.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
bankKeys stringqueryyesComma-separated covered bank keys (repeatable).
Responses
StatusDescription
200One roster row per covered bank
400No bank keys named
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "bankKey": "string",
      "policyId": "string",
      "policyName": "string",
      "builtIn": false,
      "bound": false,
      "approverUserIds": [
        "string"
      ],
      "requiredApprovals": 0,
      "sharedWith": [
        "string"
      ]
    }
  ]
}
POST/approvals/bank-rosters
Set who may approve payments on covered banks (Admin)

All or nothing across the set: if any bank's roster shrinks nothing moves until a second Admin co-signs the one request naming them all. 200 = in force now; 202 = accepted and not in force, change is the request awaiting that signature. A roster change never edits a policy: each bank is bound to a policy carrying the wanted roster on its current rule, so a policy shared with other banks is left untouched.

Request body required
PropertyTypeRequiredDescription
companyIdstringyes
targetsobject[]yes
Example
{
  "companyId": "string",
  "targets": [
    {
      "bankKey": "string",
      "approverUserIds": [
        "string"
      ]
    }
  ]
}
Responses
StatusDescription
200In force now
202Accepted: not in force; awaiting a second Admin's co-sign
400Malformed roster set
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
409Refused: the change would weaken approval (e.g. only one Admin), or a change is already awaiting co-sign
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "banks": [
    {
      "bankKey": "string",
      "approverUserIds": [
        "string"
      ],
      "fromPolicyId": "string",
      "fromRule": {
        "name": "string",
        "template": "single",
        "enabled": false,
        "requiredApprovals": 0,
        "allowSelfApproval": false,
        "perTransactionLimit": "string",
        "perJournalLimit": "string",
        "perTransactionMax": "string",
        "requireOneFromEachGroup": false,
        "orderedApproval": false,
        "groups": [
          {}
        ]
      },
      "toPolicyId": "string"
    }
  ],
  "pending": false
}
GET/approvals/changes
List approval-policy change requests (Admin)

The dual-co-sign change requests for the company. ?status=pending (default) | activated | cancelled.

Parameters
NameInRequiredDescription
status enumqueryno
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Change requests: the standard { items } envelope
400A `status` that is not valid (`invalid_parameter`).
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "proposedBy": {
        "userId": "string",
        "name": "string"
      },
      "status": "pending",
      "cosigns": [
        {
          "adminId": "string",
          "name": "string",
          "at": "string"
        }
      ],
      "requiredCosigns": 0,
      "weakening": [
        {
          "field": "string",
          "from": "string",
          "to": "string",
          "why": "string"
        }
      ],
      "blastRadius": {
        "banks": 0,
        "exact": false,
        "label": "string"
      },
      "proposedPolicyDigests": {},
      "createdAt": "string",
      "activatedAt": "string",
      "cancelledAt": "string",
      "kind": "string",
      "policyId": "string",
      "before": {
        "name": "string",
        "template": "single",
        "enabled": false,
        "requiredApprovals": 0,
        "allowSelfApproval": false,
        "perTransactionLimit": "string",
        "perJournalLimit": "string",
        "perTransactionMax": "string",
        "requireOneFromEachGroup": false,
        "orderedApproval": false,
        "groups": [
          {}
        ]
      },
      "proposed": {
        "name": "string",
        "template": "single",
        "enabled": false,
        "requiredApprovals": 0,
        "allowSelfApproval": false,
        "perTransactionLimit": "string",
        "perJournalLimit": "string",
        "perTransactionMax": "string",
        "requireOneFromEachGroup": false,
        "orderedApproval": false,
        "groups": [
          {}
        ]
      }
    }
  ]
}
POST/approvals/changes/{changeId}/{action}
Co-sign / cancel a policy change (Admin)

The proposer's signature is the write that proposed the change. action=cosign: a second, distinct Admin co-signs and the change takes effect (for a policy edit, the policy's rule is replaced in place by the rule the change carries). action=cancel: any Admin cancels a pending change; nothing it proposed takes effect. A 2nd co-sign by the same Admin is refused (409).

Parameters
NameInRequiredDescription
changeId stringpathyes
action enumpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Change updated: one shape per outcome; `change` is always present
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
409Same-admin co-sign / conflict
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "change": {
    "id": "string",
    "proposedBy": {
      "userId": "string",
      "name": "string"
    },
    "status": "pending",
    "cosigns": [
      {
        "adminId": "string",
        "name": "string",
        "at": "string"
      }
    ],
    "requiredCosigns": 0,
    "weakening": [
      {
        "field": "string",
        "from": "string",
        "to": "string",
        "why": "string"
      }
    ],
    "blastRadius": {
      "banks": 0,
      "exact": false,
      "label": "string"
    },
    "proposedPolicyDigests": {},
    "createdAt": "string",
    "activatedAt": "string",
    "cancelledAt": "string",
    "kind": "string",
    "policyId": "string",
    "before": {
      "name": "string",
      "template": "single",
      "enabled": false,
      "requiredApprovals": 0,
      "allowSelfApproval": false,
      "perTransactionLimit": "string",
      "perJournalLimit": "string",
      "perTransactionMax": "string",
      "requireOneFromEachGroup": false,
      "orderedApproval": false,
      "groups": [
        {
          "id": "string",
          "name": "string",
          "userIds": []
        }
      ]
    },
    "proposed": {
      "name": "string",
      "template": "single",
      "enabled": false,
      "requiredApprovals": 0,
      "allowSelfApproval": false,
      "perTransactionLimit": "string",
      "perJournalLimit": "string",
      "perTransactionMax": "string",
      "requireOneFromEachGroup": false,
      "orderedApproval": false,
      "groups": [
        {
          "id": "string",
          "name": "string",
          "userIds": []
        }
      ]
    }
  },
  "policy": {
    "name": "string",
    "template": "single",
    "enabled": false,
    "requiredApprovals": 0,
    "allowSelfApproval": false,
    "perTransactionLimit": "string",
    "perJournalLimit": "string",
    "perTransactionMax": "string",
    "requireOneFromEachGroup": false,
    "orderedApproval": false,
    "groups": [
      {
        "id": "string",
        "name": "string",
        "userIds": [
          "string"
        ]
      }
    ],
    "id": "string",
    "isDefault": false,
    "status": "draft",
    "createdBy": "string",
    "locked": false,
    "lockedAt": "string",
    "lockedBy": "string"
  },
  "resumedBanks": [
    "string"
  ]
}
GET/approvals/policy
The company's active approval policy

The policy the send path enforces for the company, with the organisation's self-approval setting applied. selfApprovalCappedByOrgSetting inside policy is true when that setting caps what the stored policy allows.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The active policy (`policy`)
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "policy": {
    "name": "string",
    "template": "single",
    "enabled": false,
    "requiredApprovals": 0,
    "allowSelfApproval": false,
    "perTransactionLimit": "string",
    "perJournalLimit": "string",
    "perTransactionMax": "string",
    "requireOneFromEachGroup": false,
    "orderedApproval": false,
    "groups": [
      {
        "id": "string",
        "name": "string",
        "userIds": [
          "string"
        ]
      }
    ],
    "id": "string",
    "isDefault": false,
    "status": "draft",
    "createdBy": "string",
    "locked": false,
    "lockedAt": "string",
    "lockedBy": "string",
    "selfApprovalCappedByOrgSetting": false
  }
}
POST/approvals/policies/{id}/default
Make an approval policy the company default (Admin)

Sets the policy every bank without its own policy follows. Switching the default moves all of those banks at once, so a second, distinct Admin must co-sign it: the call answers 202 and the default has not moved until they do (change is the request to co-sign).

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
idstringno
namestringno
templatestringno
approversstring[]no
isDefaultbooleanno
enabledbooleanno
requiredApprovalsnumberno
allowSelfApprovalbooleanno
approverLimitsobjectno
perTransactionLimitstring | nullno
perJournalLimitstring | nullno
perTransactionMaxstring | nullno
requireOneFromEachGroupbooleanno
orderedApprovalbooleanno
groupsobject[]no
lockedbooleanno
lockedAtstringno
lockedBystringno
Example
{
  "companyId": "string",
  "id": "string",
  "name": "string",
  "template": "string",
  "approvers": [
    "string"
  ],
  "isDefault": false,
  "enabled": false,
  "requiredApprovals": 0,
  "allowSelfApproval": false,
  "approverLimits": {},
  "perTransactionLimit": "string",
  "perJournalLimit": "string",
  "perTransactionMax": "string",
  "requireOneFromEachGroup": false,
  "orderedApproval": false,
  "groups": [
    {
      "id": "string",
      "name": "string",
      "userIds": [
        "string"
      ]
    }
  ],
  "locked": false,
  "lockedAt": "string",
  "lockedBy": "string"
}
Responses
StatusDescription
200The policy is the default now (`pending: false`)
202Accepted, not in force: `change` is the request a second Admin must co-sign
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404`policy_not_found`: no such policy in this company
409A change to this policy is already awaiting co-sign, or the policy cannot be the default
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "policy": {
    "name": "string",
    "template": "single",
    "enabled": false,
    "requiredApprovals": 0,
    "allowSelfApproval": false,
    "perTransactionLimit": "string",
    "perJournalLimit": "string",
    "perTransactionMax": "string",
    "requireOneFromEachGroup": false,
    "orderedApproval": false,
    "groups": [
      {
        "id": "string",
        "name": "string",
        "userIds": [
          "string"
        ]
      }
    ],
    "id": "string",
    "isDefault": false,
    "status": "draft",
    "createdBy": "string",
    "locked": false,
    "lockedAt": "string",
    "lockedBy": "string"
  },
  "pending": false,
  "unchanged": false,
  "resumedBanks": [
    "string"
  ],
  "selfApprovalCappedByOrgSetting": false
}

OAuth

OAuth 2.0 authorization server for ERP add-ons (RFC 6749/7636/8252): authorization code + PKCE, rotating refresh tokens. The /oauth plane is snake_case on the wire by spec.

GET/oauth/userinfo
Who this OAuth access token is (ERP add-ons)

An ERP add-on's access token describes itself, so the add-on can show who is signed in, choose scopes by the person's role, and link its own users to BankConnector's. kind: "person" for a token on a person's own sign-in (identity grant): the user id, name, email and current roles. kind: "install" for an application install's token: the install id. Both carry the organisation (id, name, and demo: whether it is a demo organisation whose add-on may offer Reset demo), the application's slug and the grant (id, scopes, and when it was minted). Any OAuth token whose grant carries at least one scope may call it, whatever the scopes are: a setup:read sign-in included. A browser session or an API key is refused: the browser reads GET /auth/me.

Responses
StatusDescription
200The token's person or install.
401Authentication required: the credential is missing, invalid or expired.
403Not an OAuth access token, or (a person's sign-in) the organisation does not allow approving in the ERP (`erp_approval_unavailable`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "kind": "string",
  "userId": "string",
  "name": "string",
  "email": "string",
  "roles": [
    "string"
  ],
  "organisation": {
    "id": "string",
    "name": "string",
    "demo": false
  },
  "application": {
    "slug": "string"
  },
  "grant": {
    "id": "string",
    "scopes": [
      "string"
    ],
    "createdAt": "string"
  }
}
POST/oauth/token
OAuth 2.0 token endpoint (authorization_code + PKCE, refresh_token)

RFC 6749 token endpoint. application/x-www-form-urlencoded only. Possession of the single-use authorization code plus its PKCE code_verifier (S256, mandatory for every client) proves the request. A public client (a desktop add-on, a mobile app) sends client_id alone; a confidential web client registered with a client secret (bc_ocs_…) also authenticates with it, by HTTP Basic (client_secret_basic) or as client_secret in the form (client_secret_post), never both, on every grant. grant_type=refresh_token rotates the refresh token on every use, with reuse detection: replaying an already-rotated token revokes the whole token family. Errors are the flat RFC 6749 §5.2 bodies (invalid_request, invalid_client, invalid_grant, unsupported_grant_type), not this API's usual error envelope. Rate-limited per IP and per client+IP; responses are never cacheable (Cache-Control: no-store).

Responses
StatusDescription
200The token pair. `access_token` (`bc_oat_…`, opaque, 1 hour) is sent as `Authorization: Bearer` against the product API; `refresh_token` (`bc_ort_…`, rotating, 180 days) returns here.
400RFC 6749 §5.2 error body: `{ error, error_description }`.
401`invalid_client`: a confidential client's secret is missing or wrong, or a public client sent one. `WWW-Authenticate: Basic` is set.
413The request body is larger than this operation accepts (`payload_too_large`).
429Over the per-IP or per-client throttle. `Retry-After` is set.
Example response (200)
{
  "access_token": "string",
  "token_type": "string",
  "expires_in": 0,
  "refresh_token": "string",
  "scope": "string"
}
GET/oauth/authorize
Describe an authorization request for the consent screen

The session-authenticated authorization endpoint (the client opens a browser here). Validates the request: registered client, a registered redirect, mandatory S256 PKCE, delegable scopes: and returns it as data for the consent screen. A desktop add-on's redirect is its exact loopback (http://127.0.0.1, any port, the registered path; localhost is always refused, RFC 8252 §7.3). A web or mobile app's is one of its registered redirect URIs, compared as an exact string: https, or a reverse-domain private-use scheme such as com.example.app:/callback (RFC 8252 §7.1). Query parameters are the RFC 6749 §4.1.1 set: response_type=code, client_id, redirect_uri, scope (space-delimited), state, code_challenge, code_challenge_method=S256, plus the optional erp_company_id: an application install's ERP identifier of the company being paired (a Uniconta company number, 1-64 characters of letters, digits, ., _ and -), echoed as erpCompanyId and recorded on the install for its life. Every install paired for the same company shares one payment messageId duplicate check, and each reads the payments the others submitted and the events about them, so a company that pairs again keeps its payments in flight. The Uniconta add-on (uniconta-addon) may add identity scopes to an install request, for the signed-in person's own sign-in beside the install: the response then lists the install's scopes as scopes and the others as identityScopes, and the decision mints both. Any other client asks for identity scopes on a request of their own. Refusals that arrive AFTER the redirect target is validated are answered as a redirectTo carrying the RFC error parameters; an unknown client or an unmatched redirect_uri is a dead-end 400, never a redirect.

Parameters
NameInRequiredDescription
response_type enumqueryyesAlways `code`.
client_id stringqueryyesThe application's registered client id.
redirect_uri stringqueryyesA redirect the client registered: for a desktop add-on, `http://127.0.0.1`, any port, the registered path; for a web or mobile app, one of its registered redirect URIs, exactly.
scope stringqueryyesThe scopes requested, space-delimited.
state stringquerynoReturned unchanged on the redirect.
code_challenge stringqueryyesThe PKCE code challenge.
code_challenge_method enumqueryyesAlways `S256`.
erp_company_id stringquerynoOptional, for an application install: the ERP's own identifier of the company being paired (a Uniconta company number), 1-64 characters of letters, digits, `.`, `_` and `-`. Every install paired for the same company shares one messageId duplicate check and reads the payments the others sent; installs paired without one share the organisation's check and read each other's.
Responses
StatusDescription
200The validated request, or a redirectable refusal.
400Unknown client, or a redirect_uri the client did not register.
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "status": "string",
  "client": {
    "clientId": "string",
    "name": "string"
  },
  "scopes": [
    "string"
  ],
  "redirectUri": "string",
  "state": "string",
  "codeChallenge": "string",
  "codeChallengeMethod": "string",
  "requestedFromIp": "string",
  "requestedAt": "string",
  "grantLifetimeYears": 0,
  "erpCompanyId": "string",
  "grantKind": "install",
  "identityScopes": [
    "string"
  ]
}
POST/oauth/authorize/decision
Record the consent decision and mint the authorization code

The consent screen's post-back (Admin session). Approval creates the pairing's grant material and answers redirectTo: the validated redirect carrying the single-use code (10-minute TTL) and state. Decline answers redirectTo with error=access_denied. The organisation is the deciding admin's own; it is never read from the request. A request with identity scopes beside the install (identityScopes on GET /oauth/authorize) also asks for the deciding person's own sign-in, decided by the same checks as /oauth/authorize/identity-decision. When the person passes them, redirectTo also carries identity_code: a second single-use code, redeemed at /oauth/token with the same code_verifier to the person's own grant. One code (twofaCode or backupCode) covers both halves. When a check refuses the person in a way they cannot fix on the consent page, only the install's code is returned, with error_reason (one of the values that route documents) and error_description; error stays absent, because the install was granted. A missing or wrong code for that half is answered 422 totp_required and mints nothing.

Request body required
PropertyTypeRequiredDescription
clientIdstringyes
redirectUristringyes
scopestringyes
statestringno
codeChallengestringyes
codeChallengeMethodstringyes
erpCompanyIdstringno
approvebooleanyes
twofaCodestringno
backupCodestringno
Example
{
  "clientId": "string",
  "redirectUri": "string",
  "scope": "string",
  "state": "string",
  "codeChallenge": "string",
  "codeChallengeMethod": "string",
  "erpCompanyId": "string",
  "approve": false,
  "twofaCode": "string",
  "backupCode": "string"
}
Responses
StatusDescription
200Where to send the browser next.
400Validation failed (unknown client, unmatched redirect, bad PKCE parameters).
401Sign in required: there is no valid session.
403Not an Admin session, or no company context selected.
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "redirectTo": "string"
}
POST/oauth/authorize/identity-decision
Consent, for yourself, to sign in to an ERP add-on (identity grant)

The consent screen's post-back when GET /oauth/authorize described grantKind: "identity": a person signing in to an ERP add-on as themselves, to approve there or (an Admin) to send capped invites. Any signed-in member of the organisation may reach it; it mints a code only when the organisation has approving in the ERP switched on, requires two-factor authentication and names the approvers of every active policy, the person holds the role each scope needs, is enrolled in two-factor authentication and presents a fresh code (twofaCode or backupCode). A grant of setup:read alone needs no code when this session proved a second factor within the last five minutes (a sign-in or two-factor setup with a code); the request then proves nothing new and the session is not rotated. Decline answers redirectTo with error=access_denied. A refusal the person cannot fix on the consent page (not a member, a precondition unmet, a role missing, two-factor authentication not set up) keeps its status and code and adds details.returnTo: the client's redirect with error=access_denied, the refusal as error_description, and error_reason: one of not_a_member, erp_approval_disabled, require_2fa_off, policy_names_nobody, role_missing:approver, role_missing:admin, totp_enrollment_required. A wrong code carries none.

Request body required
PropertyTypeRequiredDescription
clientIdstringyes
redirectUristringyes
scopestringyes
statestringno
codeChallengestringyes
codeChallengeMethodstringyes
erpCompanyIdstringno
approvebooleanyes
twofaCodestringno
backupCodestringno
Example
{
  "clientId": "string",
  "redirectUri": "string",
  "scope": "string",
  "state": "string",
  "codeChallenge": "string",
  "codeChallengeMethod": "string",
  "erpCompanyId": "string",
  "approve": false,
  "twofaCode": "string",
  "backupCode": "string"
}
Responses
StatusDescription
200Where to send the browser next.
400Validation failed, or the request is for an application install (with or without identity scopes beside it).
401Sign in required: there is no valid session.
403Not a member of the organisation, the organisation does not allow approving in the ERP (`erp_approval_unavailable`, with `details.reason` naming the precondition that is not met: `disabled`, `require-2fa-off` or `policy-names-nobody`), or the role a scope needs is missing.
413The request body is larger than this operation accepts (`payload_too_large`).
422Two-factor authentication is not set up, or the code is missing or wrong.
429Too many wrong codes, locked out for a while.
Example response (200)
{
  "redirectTo": "string"
}
POST/oauth/revoke
Revoke an access or refresh token (RFC 7009)

Public, like /oauth/token: a public client identifies itself with client_id, and a confidential client authenticates with its client secret exactly as at the token endpoint. Always answers 200, including for an already-revoked, expired, unknown, or wrong-client token (RFC 7009 §2.2), so the endpoint cannot be used to probe which tokens exist. token_type_hint only narrows which token is tried first; an absent or wrong hint still finds the token. Revoking a refresh token revokes every access token from the same authorization grant (RFC 7009 §2.1); revoking a bare access token does not touch its refresh token. Revoking an application install's current refresh token also ends that install: it was the install's only credential, and GET /installs then lists it as revoked with accessReason: disconnected. Call it with the old refresh token when a new connection replaces it, and on disconnect.

Responses
StatusDescription
200The token has been revoked, or was already invalid. RFC 7009 does not distinguish.
400Malformed request: `token` or `client_id` missing.
401`invalid_client`: a confidential client's secret is missing or wrong.
413The request body is larger than this operation accepts (`payload_too_large`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
GET/.well-known/oauth-authorization-server
OAuth 2.0 Authorization Server Metadata (RFC 8414)

The discovery document a standard OAuth client fetches to learn this server's endpoints and capabilities. scopes_supported and grant_types_supported match what the authorization and token endpoints accept. scopes_supported is what an application install may be granted; identity_scopes_supported is what a person may carry into an ERP add-on on their own sign-in. Public by definition (RFC 8414 §3): no tenant data, no internal hostnames, nothing that varies by caller. The issuer and every endpoint URL are this deployment's own configured public origin, so the same document is served whatever Host the request carries (RFC 8414 §3.3: fetch it from the issuer you intend to use).

Responses
StatusDescription
200The metadata document.
503This server has no configured public origin, so it cannot name itself.
Example response (200)
{
  "issuer": "string",
  "authorization_endpoint": "string",
  "token_endpoint": "string",
  "revocation_endpoint": "string",
  "scopes_supported": [
    "string"
  ],
  "identity_scopes_supported": [
    "string"
  ],
  "response_types_supported": [
    "string"
  ],
  "grant_types_supported": [
    "string"
  ],
  "token_endpoint_auth_methods_supported": [
    "string"
  ],
  "revocation_endpoint_auth_methods_supported": [
    "string"
  ],
  "code_challenge_methods_supported": [
    "string"
  ]
}

Auth

Login, session, and 2FA. Login + demo are PUBLIC; the rest need a session.

POST/auth/login
Log in (PUBLIC): sets the httpOnly session cookie

PUBLIC. Exchanges email + password for a signed session, delivered only as the httpOnly bc_session cookie (the raw token is never in the response body; programmatic callers should use API keys). The email address identifies the account on its own, it is unique across the whole service, so there is no workspace to name. Where a step-up is owed, returns a challenge instead of a session (complete it at POST /auth/2fa): twofaRequired when 2FA is enabled, and stepUpRequired: "proof-of-work" when the identity is over the per-identity failure threshold and has no second factor.

Request body required
PropertyTypeRequiredDescription
emailstringyes
passwordstringyes
Example
{
  "email": "string",
  "password": "string"
}
Responses
StatusDescription
200Logged in (session cookie set) or a 2FA step-up challenge
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Invalid credentials
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "twofaRequired": false,
  "twofaToken": "string",
  "forcedEnroll": false,
  "stepUpRequired": "string",
  "stepUpToken": "string",
  "proofOfWork": {
    "algorithm": "string",
    "bits": 0
  },
  "expiresAt": "string",
  "user": {
    "id": "string",
    "companyId": "string",
    "email": "string",
    "name": "string",
    "roles": [
      "admin"
    ],
    "status": "active",
    "settings": {
      "locale": "string",
      "timezone": "string",
      "dateFormat": "iso",
      "notifications": {
        "paymentNeedsApproval": false,
        "paymentApproved": false,
        "paymentRejected": false,
        "statementReceived": false,
        "erpDecisionReceipt": false
      }
    },
    "totpEnabledAt": "string",
    "emailDeliveryFlag": {
      "kind": "hard_bounce",
      "at": "string"
    },
    "createdAt": "string"
  },
  "csrfToken": "string"
}
Code samples
curl -X POST https://your-host/api/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"you@acme.com","password":"…"}'
const res = await fetch("https://your-host/api/auth/login", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"email":"you@acme.com","password":"…"}),
});
const data = await res.json();
import requests

resp = requests.request(
  "POST", "https://your-host/api/auth/login",
  json={"email":"you@acme.com","password":"…"},
)
resp.raise_for_status()
data = resp.json()
POST/2fa/setup
Begin 2FA enrollment (signed-in user); returns a TOTP secret and otpauth URI

Generates a NOT-yet-active TOTP secret for the signed-in user and returns its otpauth:// URI (render as a QR). Activate it with POST /2fa/confirm. Session-only. It never replaces a live authenticator: an enrolled user re-enrols through POST /2fa/disable (current password and a code), then this.

Responses
StatusDescription
200Pending secret + otpauth URI
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
409Already enrolled (`conflict`). Disable 2FA first, then set it up again.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "secret": "string",
  "otpauthUri": "string",
  "issuer": "string"
}
POST/2fa/confirm
Confirm 2FA enrollment with the current password and a TOTP code; returns one-time backup codes

Re-authenticates with the caller's current password (ASVS 7.5.1; a session alone cannot switch 2FA on), then verifies a code against the pending secret and activates 2FA. The password is checked first, so a refused password spends no code. The confirming code is single-use: it is consumed, so it cannot be replayed as a sign-in or approval step-up within its time window. The backup codes are returned exactly once, surface + warn. Session-only; throttled per user (a wrong password counts, a missing one does not).

Every other session of the user is revoked; this one survives. A cookie session is rotated: the response sets fresh bc_session and bc_csrf cookies and carries the new csrfToken, which replaces the token the client holds, or its next write is refused. A header-token caller is not rotated and gets no csrfToken.

Request body required
PropertyTypeRequiredDescription
companyIdstringno
codestringyes6-digit TOTP code
backupCodestringno
passwordstringyesThe caller's current password (re-authentication).
Example
{
  "companyId": "string",
  "code": "string",
  "backupCode": "string",
  "password": "string"
}
Responses
StatusDescription
200Enabled + one-time backup codes
400`setup_required`: no pending secret, call POST /2fa/setup first; or a body that is not JSON (`validation_failed`)
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
409Already enabled
413The request body is larger than this operation accepts (`payload_too_large`).
422`reauth_required`: the password is missing or wrong; `invalid_code`: the code didn't match
429Too many wrong passwords or codes by this user (`rate_limited`): five lock it for a while. The `Retry-After` header and `error.details.retryAfterSeconds` both give the wait in seconds.
Example response (200)
{
  "enabled": false,
  "backupCodes": [
    "string"
  ],
  "csrfToken": "string"
}
POST/2fa/disable
Disable 2FA (needs the current password and a fresh code; blocked when the company requires 2FA)

Turns off the signed-in user's 2FA after re-authenticating with their current password (ASVS 7.5.1) and verifying a fresh TOTP or backup code. The password first, so a refused password spends no code; refused (403) when the company requires 2FA. Revokes the user's other sessions and every ERP add-on sign-in they hold. A cookie session is rotated on success (fresh bc_session and bc_csrf cookies on the response); a header-token session is left as it is. Session-only; throttled (a wrong password counts, a missing one does not).

Request body required
PropertyTypeRequiredDescription
companyIdstringno
codestringno
backupCodestringno
passwordstringyesThe caller's current password (re-authentication).
Example
{
  "companyId": "string",
  "code": "string",
  "backupCode": "string",
  "password": "string"
}
Responses
StatusDescription
200Disabled
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Company requires 2FA
409Not enabled
413The request body is larger than this operation accepts (`payload_too_large`).
422`reauth_required`: the password is missing or wrong; `invalid_code`: a valid code is required
429Too many wrong passwords or codes by this user (`rate_limited`): five lock it for a while. The `Retry-After` header and `error.details.retryAfterSeconds` both give the wait in seconds.
Example response (200)
{
  "enabled": false
}
POST/company/require-2fa
Admin: set the company-wide 2FA requirement

Admin-only. When enabled, every user in the company must enroll in 2FA. Distinct from the per-user enabled state. The response field is require2fa (company policy).

Request body required
PropertyTypeRequiredDescription
companyIdstringno
enabledbooleanyes
Example
{
  "companyId": "string",
  "enabled": false
}
Responses
StatusDescription
200Updated company policy
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "require2fa": false
}
PUT/company/registration-number
System admin: set the company's national registration number

System-admin-only: the customer's own Admin cannot call this; changing it is a support action. Records the number the national business register issues. CVR (DK), Y-tunnus (FI), organisationsnummer (SE/NO): which every bank asks for when it opens an agreement file. Send null to clear it; omit the field and the request is refused as nothing_to_update. The value is stored unstructured (the format varies by country) and is read back on GET /auth/me as companyRegistrationNumber. Names the organisation with the companyId query param, fenced to whichever one the system admin has assumed.

Parameters
NameInRequiredDescription
companyId stringqueryyesThe organisation this system-admin action applies to. The one the caller has assumed. A system admin has no company of its own to fall back to, so this is always required.
Request body required
PropertyTypeRequiredDescription
companyIdstringno
registrationNumberstring | nullyes
Example
{
  "companyId": "string",
  "registrationNumber": "string"
}
Responses
StatusDescription
200The company's registration number after the write
400Nothing to update, a value longer than the bound, or companyId missing
401Authentication required: the credential is missing, invalid or expired.
403System admin required
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "registrationNumber": "string"
}
PATCH/company/registration-number
Add the organisation's registration number, or correct one the company register has not confirmed

An Admin of the organisation adds its registration number where none is stored, or corrects it for as long as the company register has not confirmed it: the register did not know the number at signup, listed the company as inactive, could not be reached, or the country has no register lookup (GET /company/legal-identity answers registrationNumberEditable). A number the register confirmed, and a stored number with no register answer kept, are changed by support (PUT, system admin) and refused here with 409 legal_identity_locked; an added number keeps no register answer, so it is added once. The register is not asked. A Danish, Norwegian or Swedish number must pass its check digit and is stored in the register's form (digits only). Where the stored VAT number was the old registration number (a Danish CVR as DK + CVR), it follows the new one; an added Danish CVR is stored as the VAT number DK + CVR when none is stored. A VAT change is pushed onto the organisation's Stripe Customer. Recorded on the activity feed as company.registration-number-changed. Delegated partner access is refused at every tier.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body required
PropertyTypeRequiredDescription
registrationNumberstringyesThe corrected number: CVR, organisasjonsnummer, organisationsnummer or equivalent.
Example
{
  "registrationNumber": "string"
}
Responses
StatusDescription
200The company's registration number after the write
400The body is not valid
401Sign in required: there is no valid session.
403Not an Admin of this organisation, or delegated partner access
409`legal_identity_locked`: the register confirmed the number, or no register answer is kept. Contact support to change it
413The request body is larger than this operation accepts (`payload_too_large`).
422No number, or a Danish, Norwegian or Swedish number whose check digit is wrong (`details.field: registrationNumber`)
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "registrationNumber": "string"
}
GET/auth/me
Current principal (who am I)
Responses
StatusDescription
200The signed-in user + roles + company
401No session, or the session's company no longer exists
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "user": {
    "id": "string",
    "email": "string",
    "name": "string",
    "roles": [
      "admin"
    ],
    "kind": "partner",
    "companyId": "string",
    "userId": "string",
    "companyName": "string",
    "activeCompanyId": "string",
    "activeName": "string",
    "partnerFirmName": "string",
    "partnerAccessLevel": "status",
    "partnerLook": {
      "firmId": "string",
      "firmName": "string"
    },
    "bankChannelsHidden": {
      "managedBy": "string"
    },
    "otherArea": {
      "kind": "string",
      "firmName": "string"
    },
    "sandboxOnly": false,
    "settings": {
      "locale": "string",
      "timezone": "string",
      "dateFormat": "iso",
      "notifications": {
        "paymentNeedsApproval": false,
        "paymentApproved": false,
        "paymentRejected": false,
        "statementReceived": false,
        "erpDecisionReceipt": false
      }
    },
    "twoFactor": {
      "enrolled": false,
      "companyRequired": false,
      "recentlyVerified": false
    },
    "companyRegistrationNumber": "string"
  },
  "session": {
    "idleMinutes": 0,
    "maxMinutes": 0,
    "maxRemainingSeconds": 0
  }
}
GET/me/organisations
The organisations this identity administers

The organisations the signed-in identity holds a live grant on, unrevoked, unexpired, and with no revoked or expired ancestor. This is the set POST /auth/company-context will accept, so a row listed here can be entered. Revoking a grant removes its organisation from the next read.

Parameters
NameInRequiredDescription
limit integerquerynoPage size.
cursor stringquerynoThe previous page's `nextCursor`, opaque. A malformed one is 400 `invalid_cursor`; any other answers only organisations the caller holds a live grant on.
Responses
StatusDescription
200The organisations this identity administers, newest first.
400A `limit` that is not a number (`invalid_parameter`), or a malformed `cursor` (`invalid_cursor`).
401Sign in required: there is no valid session.
403Not an identity that can hold a grant (an API key, an install, or dev open mode).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "name": "string",
      "createdAt": "string",
      "accessLevel": "admin",
      "expiresAt": "string",
      "userCount": 0,
      "bankConnectionCount": 0
    }
  ],
  "nextCursor": "string"
}
POST/auth/2fa/setup
Forced 2FA enrollment during login; returns a TOTP secret and otpauth URI

PUBLIC, but gated by a login challenge token, not a session: used when a company REQUIRES 2FA and the signing-in user has not enrolled yet. Exchange the challenge from POST /auth/login for a pending TOTP secret (same shape as the self-service POST /2fa/setup); activate it by sending a code to POST /auth/2fa, which both enrolls and completes the sign-in. Refused (409) if the account is already enrolled. The challenge alone must never be able to replace a working authenticator.

Request body required
PropertyTypeRequiredDescription
twofaTokenstringnoThe challenge token from POST /auth/login.
Example
{
  "twofaToken": "string"
}
Responses
StatusDescription
200Pending secret + otpauth URI
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401The sign-in challenge expired. Sign in again.
409Already enrolled, or the token is a step-up challenge rather than an enrollment one.
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many attempts from this IP (Retry-After)
Example response (200)
{
  "secret": "string",
  "otpauthUri": "string",
  "issuer": "string"
}
GET/me/sessions
List the signed-in user's own active sessions

Every live session belonging to the caller. Never another user's, even for an admin. current marks the session this very request is using. Session-only; an API key answers 401.

Responses
StatusDescription
200The caller's own sessions.
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "current": false,
      "createdAt": 0,
      "expiresAt": 0,
      "deviceLabel": "string",
      "lastSeenAt": 0
    }
  ],
  "nextCursor": "string",
  "total": 0
}
DELETE/me/sessions
Sign out everywhere else (revokes every other session)

Revokes every one of the caller's sessions EXCEPT the one making this request, which stays alive. Use this after a suspected compromise elsewhere. Session-only. Re-authentication (ASVS 7.5.2): a current 2FA code (or backupCode) when the caller has two-factor authentication, otherwise their current password. A cookie session is rotated on success (fresh cookies on the response).

Request body required
PropertyTypeRequiredDescription
passwordstringnoThe caller's current password, when no second factor applies to them.
codestringnoA current 2FA TOTP code, when the caller has 2FA.
backupCodestringnoA 2FA backup code, in place of `code`.
Example
{
  "password": "string",
  "code": "string",
  "backupCode": "string"
}
Responses
StatusDescription
200How many other sessions were revoked.
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
413The request body is larger than this operation accepts (`payload_too_large`).
422Re-authentication needed: `totp_required` (code missing or wrong), `totp_enrollment_required` (the company requires 2FA and the caller has none), `reauth_required` (password missing or wrong), or `invalid_code` / `reauth_required` for a system admin's code
429Too many requests from this network, or too many wrong codes or passwords (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "revoked": 0
}
DELETE/me/sessions/{id}
Revoke one of the caller's own sessions by id

Revokes exactly one session the caller owns, named by its opaque id. If it was this request's own session, the auth cookies are cleared too (the browser app then returns to the login screen), identical to an explicit logout, and needs nothing else. Ending ANOTHER session needs the same re-authentication as DELETE /me/sessions, in an optional JSON body. current in the response says which case happened. Session-only.

Parameters
NameInRequiredDescription
id stringpathyesThe session's opaque id, as listed by GET /me/sessions.
Request body
PropertyTypeRequiredDescription
passwordstringnoThe caller's current password, when no second factor applies to them.
codestringnoA current 2FA TOTP code, when the caller has 2FA.
backupCodestringnoA 2FA backup code, in place of `code`.
Example
{
  "password": "string",
  "code": "string",
  "backupCode": "string"
}
Responses
StatusDescription
200Revoked.
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
404No such active session. It may already have ended. Answered before any code or password is checked.
413The request body is larger than this operation accepts (`payload_too_large`).
422Re-authentication needed: `totp_required` (code missing or wrong), `totp_enrollment_required` (the company requires 2FA and the caller has none), `reauth_required` (password missing or wrong), or `invalid_code` / `reauth_required` for a system admin's code
429Too many requests from this network, or too many wrong codes or passwords (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "revoked": false,
  "current": false
}
GET/me/erp-grants
List the signed-in user's own ERP add-on sign-ins

The caller's live identity grants to ERP clients: their own sign-ins inside an ERP add-on, each consented to by them in the browser. Never another user's. Session-only; an API key answers 401.

Responses
StatusDescription
200The caller's live sign-ins
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "grantId": "string",
      "application": "string",
      "scopes": [
        "string"
      ],
      "createdAt": "string",
      "expiresAt": "string"
    }
  ]
}
POST/me/erp-grants/{grantId}/revoke
End one of the caller's own ERP add-on sign-ins

Ends one of the caller's own ERP add-on sign-ins; every token it issued stops working on its next request, and the person signs in to the add-on again. Session-only; journalled.

Parameters
NameInRequiredDescription
grantId stringpathyesThe sign-in's id, as listed by GET /me/erp-grants.
Responses
StatusDescription
200Ended
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
404No live ERP add-on sign-in with that id is the caller's
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "revoked": false
}
POST/me/password
Change the signed-in user's own password

Requires the current password, a live session alone is not enough, and a fresh 2FA code when the caller is enrolled. On success, revokes every other session and every ERP add-on sign-in the caller holds and, for a cookie-borne caller, rotates this one (returning a fresh csrfToken). Password-only for a workspace admin: it changes no other credential of theirs. A system-admin session is refused (403).

Request body required
PropertyTypeRequiredDescription
currentPasswordstringyes
newPasswordstringyes
twofaCodestringnoRequired when the caller has 2FA enabled.
backupCodestringnoA one-time backup code, in place of twofaCode.
Example
{
  "currentPassword": "string",
  "newPassword": "string",
  "twofaCode": "string",
  "backupCode": "string"
}
Responses
StatusDescription
200Password changed.
400Missing fields, or the new password fails the strength/breached-password policy.
401Sign in first, or the current password is incorrect.
403A system-admin session: the system console manages its own credentials.
413The request body is larger than this operation accepts (`payload_too_large`).
422A valid two-factor code is required.
429Too many attempts from this IP (Retry-After)
Example response (200)
{
  "ok": false,
  "revokedOtherSessions": 0,
  "csrfToken": "string"
}
POST/auth/logout
Log out (invalidates the session)
Responses
StatusDescription
200Logged out
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "ok": false
}
POST/auth/area
Switch between your organisation and your partner area

For a person who is a partner AND a member of their own organisation, with one login: moves this session to the partner area (partner) or back to their own organisation (organisation). Decided off the person's own login, never the request: anyone else is refused 403. The session keeps its deadlines and its second-factor stamp; a cookie session is rotated, so the answer carries a new csrfToken.

Request body required
PropertyTypeRequiredDescription
areaenumyes
Example
{
  "area": "partner"
}
Responses
StatusDescription
200The session sits in the place asked for
400`area` is missing or not one of the two
401Sign in required: there is no valid session.
403Not a person who is both a partner and a member of their own organisation
409The session is already there
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "ok": false,
  "area": "partner",
  "csrfToken": "string"
}
GET/auth/password-reset
Whether a self-service password reset link can be sent (PUBLIC)

PUBLIC: read before sign-in. available is true when this instance can deliver a reset link (an email transport is configured); the sign-in page shows "Forgot password?" only then. A fact about the deployment: nothing in the request changes the answer, and POST /auth/password-reset answers 503 exactly when it is false.

Responses
StatusDescription
200Reset-link availability
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "available": false
}
POST/auth/password-reset
Request a self-service password reset link (PUBLIC)

PUBLIC. The sign-in page's "Forgot password?". Answers 202 with the same body whether or not an account exists for the address, unknown, invited, deactivated and throttled addresses included, and sends a one-time link (valid for an hour, superseded by the next request) only when an active account matches. The current password keeps working until the link is redeemed. Throttled per source IP and per address; a throttled request gets the same 202. 503 when no email transport is configured.

Request body required
PropertyTypeRequiredDescription
emailstringyesThe address to send the reset link to, if an account exists.
Example
{
  "email": "string"
}
Responses
StatusDescription
202Accepted: the neutral answer, identical for every address
400Malformed body, or not an email address
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
503Password reset is unavailable on this instance (no email transport)
Example response (202)
{
  "message": "string"
}
POST/auth/password-reset/confirm
Redeem a password reset link: set a new password (PUBLIC)

PUBLIC. Redeems the one-time token from a POST /auth/password-reset email and sets the password. Every session and ERP add-on sign-in of the account is revoked and a password-changed notice is emailed. NO session is issued: sign in at POST /auth/login afterwards, where a second factor still applies. An invalid, expired, used or superseded token is refused with one message.

Request body required
PropertyTypeRequiredDescription
tokenstringyesThe one-time token from the reset email link.
passwordstringyesThe new password.
Example
{
  "token": "string",
  "password": "string"
}
Responses
StatusDescription
200Password reset
400Invalid, expired or already-used link, or a password the policy refuses
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many attempts: IP rate-limited
Example response (200)
{
  "ok": false,
  "email": "string"
}
POST/auth/2fa-reset/confirm
Confirm a support operator's two-factor reset (PUBLIC)

PUBLIC. Redeems the one-time token from the email BankConnector support sends when it is asked to reset an account's two-factor authentication (the account holder lost their authenticator and their backup codes). Nothing about the account changes until this is called: on success the account's second factor is cleared and every one of its sessions is revoked, in one transaction, then every ERP add-on sign-in it holds is ended, and a two-factor-changed notice is emailed. NO session is issued: sign in at POST /auth/login with the account's password, then enrol a new authenticator. The token is single-use and expires 30 minutes after it was sent; an invalid, expired, used or superseded token is refused with one message, and each refusal counts toward the per-IP sign-in lockout.

Request body required
PropertyTypeRequiredDescription
tokenstringyesThe one-time token from the confirmation email's link.
Example
{
  "token": "string"
}
Responses
StatusDescription
200Two-factor authentication reset
400Missing token, or an invalid, expired, already-used or superseded link
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many attempts: IP rate-limited
Example response (200)
{
  "reset": false,
  "email": "string"
}
GET/auth/signup
Whether self-service signup is reachable on this instance (PUBLIC)

PUBLIC: read before sign-in. available is true only in production, with a way to deliver credentials (an email transport configured, or a dev box whose transport writes to stderr). The same two conditions POST /signup itself refuses on (404 outside production, 503 without a transport). The sign-in page shows its "Create an account" link only when this is true.

Responses
StatusDescription
200Signup availability
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "available": false
}
POST/auth/2fa
Complete a login step-up (PUBLIC)

PUBLIC. Submits the proof the challenge from POST /auth/login demands, to obtain the session (delivered only as the httpOnly bc_session cookie; the raw token is never in the response body). A twofaToken is cleared by code or backupCode; a stepUpToken (the proof-of-work class, sent in the same twofaToken field) is cleared by solution and by nothing else. Under forced enrolment (forcedEnroll at login, after POST /auth/2fa/setup) the first valid code activates 2FA and completes the sign-in in one step, revokes every earlier session of the user, and returns backupCodes, shown exactly once.

Request body required
PropertyTypeRequiredDescription
twofaTokenstringyesThe `twofaToken` or `stepUpToken` returned by POST /auth/login.
codestringnoTOTP code: the proof a `twofaToken` demands.
backupCodestringno
solutionstringnoProof-of-work solution: the proof a `stepUpToken` demands. Any string for which sha256("<stepUpToken>.<solution>") begins with the response's `proofOfWork.bits` zero bits.
Example
{
  "twofaToken": "string",
  "code": "string",
  "backupCode": "string",
  "solution": "string"
}
Responses
StatusDescription
200Session granted (session cookie set)
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401The sign-in challenge expired (`unauthorized`). Sign in again.
409`enrollment_required` (`details.forcedEnroll: true`): the company requires 2FA and this user has no pending secret yet. Call POST /auth/2fa/setup first.
413The request body is larger than this operation accepts (`payload_too_large`).
422`invalid_code`: the code or backup code is wrong or expired; `invalid_proof_of_work`: the solution does not solve the challenge. A body that fails the route's schema is `validation_failed` (pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400).
429Too many failed attempts for this user or from this network (`rate_limited`). Try again later.
Example response (200)
{
  "expiresAt": "string",
  "user": {
    "id": "string",
    "companyId": "string",
    "email": "string",
    "name": "string",
    "roles": [
      "admin"
    ],
    "status": "active",
    "settings": {
      "locale": "string",
      "timezone": "string",
      "dateFormat": "iso",
      "notifications": {
        "paymentNeedsApproval": false,
        "paymentApproved": false,
        "paymentRejected": false,
        "statementReceived": false,
        "erpDecisionReceipt": false
      }
    },
    "totpEnabledAt": "string",
    "emailDeliveryFlag": {
      "kind": "hard_bounce",
      "at": "string"
    },
    "createdAt": "string"
  },
  "csrfToken": "string",
  "backupCodes": [
    "string"
  ]
}
GET/approver-identity
Read the signed-in user's own approver identity (masked)

Whether the caller has enrolled a Norwegian national ID (fødselsnummer) used by NO banks' payment files, and, on the GET only, banksRequiringId: the display names of this company's connected banks whose files carry it. An empty array means no connected bank needs it; the key is absent on POST/DELETE, which do not recompute it. Never returns the cleartext SSN, only its masked ssnFirst6 (the first 6 digits, the DDMMYY birth date; never the last 5) when one is enrolled: and even that only to the identity's own owner. districtUserId is the caller's own Danske Bank District user ID when one is on file, and banksAcceptingDistrictUserId (GET only, [] included) names the connected banks whose files take it in place of a national ID.

Responses
StatusDescription
200The caller's own approver-identity enrolment (masked).
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "enrolled": false,
  "ssnFirst6": "string",
  "districtUserId": "string",
  "enrolledAt": "string",
  "banksRequiringId": [
    "string"
  ],
  "banksAcceptingDistrictUserId": [
    "string"
  ]
}
POST/approver-identity
Enroll (or replace) the signed-in user's own approver identity

Accepts the raw SSN once, stores it encrypted, and answers the same masked shape as the GET, the cleartext value is never echoed back. A malformed fødselsnummer is refused (validation_failed). districtUserId sets the Danske Bank District user ID beside it (at most 35 characters, validation_failed otherwise). Each field is set by a string and removed by null; a field left out is unchanged, and at least one must be given. Both are checked before either is written. A user may only ever write their own identity (self-scoped by session, enforced again at the field-authz layer as defence-in-depth).

Request body required
PropertyTypeRequiredDescription
ssnstring | nullnoThe Norwegian national ID (fødselsnummer), cleartext, once. `null` removes it.
districtUserIdstring | nullnoThe approver's Danske Bank District user ID, sent as the `USER` approver code at Danske Bank Norway when no national ID is on file. `null` removes it.
Example
{
  "ssn": "string",
  "districtUserId": "string"
}
Responses
StatusDescription
200The caller's own approver-identity enrolment (masked).
400Neither ssn nor districtUserId given or a blank ssn (`ssn_required`); before `BankConnector-Version: 2026-10-20`, a malformed request body, a fødselsnummer that is not valid or a District user ID that is empty or over 35 characters (`validation_failed`).
401Sign in required: there is no valid session.
403Attempted to write an identity that is not the caller's own.
413The request body is larger than this operation accepts (`payload_too_large`).
422From `BankConnector-Version: 2026-10-20`: a malformed request body, a fødselsnummer that is not valid, or a District user ID that is empty or over 35 characters (`validation_failed`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "enrolled": false,
  "ssnFirst6": "string",
  "districtUserId": "string",
  "enrolledAt": "string",
  "banksRequiringId": [
    "string"
  ],
  "banksAcceptingDistrictUserId": [
    "string"
  ]
}
DELETE/approver-identity
Remove the signed-in user's own approver identity

Deletes the caller's own enrolled identity. Idempotent: always answers enrolled: false.

Responses
StatusDescription
200The caller's own approver-identity enrolment (masked).
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "enrolled": false,
  "ssnFirst6": "string",
  "districtUserId": "string",
  "enrolledAt": "string",
  "banksRequiringId": [
    "string"
  ],
  "banksAcceptingDistrictUserId": [
    "string"
  ]
}

User Management

Create, invite, and manage users within a company.

GET/users
List users in a company

Returns all users in the company (name, email, roles, status). Readable by any authenticated company member.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Company users
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "email": "string",
      "name": "string",
      "roles": [
        "admin"
      ],
      "status": "active",
      "totpEnabledAt": "string",
      "emailDeliveryFlag": {
        "kind": "hard_bounce",
        "at": "string"
      },
      "erpLinked": false,
      "namedInPolicy": false,
      "approverBanks": [
        {
          "bankKey": "string",
          "displayName": "string"
        }
      ]
    }
  ]
}
POST/users
Invite a company user

Company admin only. Sends an invite email: the user receives a link to /auth/set-password where they set their own password. Nobody else ever chooses it, so the request takes no password.

The user must be given at least one role (admin, approver, and/or viewer). Users who will be assigned as payment approvers need the approver role.

Step-up (ASVS 7.5.3): creating a user with the admin or approver role needs the acting admin's current authenticator code (or a backupCode) when they are enrolled in 2FA or their company requires it, and a passed step-up rotates a cookie session. A viewer-only user needs no code. An API key can invite viewer users only: it has no second factor to give, so an admin or approver is refused (403). A person signed in from the ERP add-on may invite approver and viewer users only, with a current authenticator code on every invite.

Request body required
PropertyTypeRequiredDescription
companyIdstringyes
emailstringyes
namestringyes
rolesstring[]yes
codestringnoThe acting admin's 2FA TOTP code (when step-up applies; an `admin` or `approver` role).
backupCodestringnoA 2FA backup code, in place of `code`.
Example
{
  "companyId": "string",
  "email": "approver@acme.com",
  "name": "Bob Approver",
  "roles": [
    "approver"
  ],
  "code": "string",
  "backupCode": "string"
}
Responses
StatusDescription
201User invited
400Invalid request (`bad_request`), or no valid roles (`invalid_roles`)
401Authentication required: the credential is missing, invalid or expired.
403Company admin required; or an API key or a system admin creating an `admin` or `approver`
409The email address is already registered (`conflict`)
413The request body is larger than this operation accepts (`payload_too_large`).
422Step-up refused: `totp_required` (the 2FA code is missing or wrong) or `totp_enrollment_required` (the company requires 2FA and this admin has not set it up)
429Too many wrong 2FA codes (`rate_limited`); see `Retry-After`
503An invite with no email transport to deliver it (`invites_unavailable`), refused before the code is checked so a single-use code is not spent
Example response (201)
{
  "id": "string",
  "companyId": "string",
  "email": "string",
  "name": "string",
  "roles": [
    "admin"
  ],
  "status": "active",
  "settings": {
    "locale": "string",
    "timezone": "string",
    "dateFormat": "iso",
    "notifications": {
      "paymentNeedsApproval": false,
      "paymentApproved": false,
      "paymentRejected": false,
      "statementReceived": false,
      "erpDecisionReceipt": false
    }
  },
  "totpEnabledAt": "string",
  "emailDeliveryFlag": {
    "kind": "hard_bounce",
    "at": "string"
  },
  "createdAt": "string",
  "invited": false,
  "emailDeliveryPending": false,
  "inviteLink": "string"
}
GET/users/{id}
Get a single user

Returns one user's record. Readable by any authenticated company member, but the response shape depends on who is asking:

  • An API key, the subject themselves, or a session holding the admin role receive the whole record: settings, companyId and createdAt included.
  • Any other signed-in company member receives the narrower roster projection (id, email, name, roles, status, totpEnabledAt). The same six fields GET /users publishes. A colleague's preferences are not theirs to read.

Both are a 200; the status code does not distinguish them, so read the 200 schema's two arms.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The user: the whole record for an API key / the subject / an admin session, the roster projection for any other company member. See the operation description; the schema's two arms are that condition, not a caller's free choice.
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
404Unknown user in this company
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "id": "string",
  "companyId": "string",
  "email": "string",
  "name": "string",
  "roles": [
    "admin"
  ],
  "status": "active",
  "settings": {
    "locale": "string",
    "timezone": "string",
    "dateFormat": "iso",
    "notifications": {
      "paymentNeedsApproval": false,
      "paymentApproved": false,
      "paymentRejected": false,
      "statementReceived": false,
      "erpDecisionReceipt": false
    }
  },
  "totpEnabledAt": "string",
  "totpLastStep": 0,
  "emailDeliveryFlag": {
    "kind": "hard_bounce",
    "at": "string"
  },
  "createdAt": "string"
}
POST/auth/set-password
Complete an invite: set password from email token (PUBLIC)

PUBLIC. Called when an invited user clicks their invite link. Validates the one-time token and sets the user's password. Any existing sessions and ERP add-on sign-ins for the user are revoked. The token comes from the invite email.

Request body required
PropertyTypeRequiredDescription
tokenstringyesThe one-time invite token from the email link.
passwordstringyesThe user's chosen password.
Example
{
  "token": "string",
  "password": "string"
}
Responses
StatusDescription
200Password set
400Invalid or expired token
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many attempts: IP rate-limited
Example response (200)
{
  "ok": false,
  "email": "string",
  "twofaRequired": false,
  "twofaToken": "string",
  "forcedEnroll": false,
  "expiresAt": "string",
  "user": {
    "id": "string",
    "companyId": "string",
    "email": "string",
    "name": "string",
    "roles": [
      "admin"
    ],
    "status": "active",
    "settings": {
      "locale": "string",
      "timezone": "string",
      "dateFormat": "iso",
      "notifications": {
        "paymentNeedsApproval": false,
        "paymentApproved": false,
        "paymentRejected": false,
        "statementReceived": false,
        "erpDecisionReceipt": false
      }
    },
    "totpEnabledAt": "string",
    "emailDeliveryFlag": {
      "kind": "hard_bounce",
      "at": "string"
    },
    "createdAt": "string"
  },
  "csrfToken": "string"
}

Workspace

Company dashboard, API keys, and per-bank test payments

GET/dashboard/kpis
Home KPI tiles: exact company-wide payment figures for one calendar day

Counts and per-currency payment totals for the Home screen's KPI row and payment-pipeline card, aggregated in SQL over every outbound payment the company holds, not a page of them. The window is the calendar day named by day, resolved in the IANA zone named by timezone (the signed-in user's preference zone), so the day boundary matches every timestamp rendered beside these figures. Payment totals are returned as exact decimal strings keyed by ISO 4217 code.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
day stringqueryyesThe calendar day to window on, as YYYY-MM-DD. A value carrying a time is rejected.
timezone stringquerynoIANA zone the day is resolved in, e.g. Europe/Copenhagen. Defaults to UTC.
Responses
StatusDescription
200KPI aggregate for the requested day
400Missing or malformed `day`, or an unknown `timezone`
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "day": "string",
  "timezone": "string",
  "yesterdayCount": 0,
  "pendingCount": 0,
  "execCount": 0,
  "execCountByCurrency": {},
  "rejectedOpenCount": 0,
  "todayByStatus": [
    {
      "status": "string",
      "currency": "string",
      "count": 0,
      "bankKeys": [
        "string"
      ]
    }
  ],
  "execMoney": {},
  "awaitMoney": {}
}
POST/client-errors
Report a browser-side crash

The browser app posts here when a screen fails to render, so the operator sees a crash on a payments or approvals screen. Tenant-scoped by the session, never by the body.

Always answers 202, even when nothing is stored. recorded says which happened.

ON BY DEFAULT. The operator can disable capture with BANKCONNECTOR_CLIENT_ERROR_CAPTURE=0, and while it is disabled the payload is not even parsed. Payloads are encrypted at rest, purged after 30 days, and readable only by an audited operator via GET /ops/client-errors. Credentials and national identity numbers are stripped before storage; other detail is kept, so a report identifies the record that broke.

Probe first: POST an empty body {} to ask whether capture is on. The answer carries capture: true only when capture is enabled and the session could have a row recorded for it. The browser sends no report content until it sees that.

Request body required
PropertyTypeRequiredDescription
islandstringnoScreen label, e.g. "approvals-queue".
routestringnoRoute in view. Query string is dropped by client and server.
messagestringno
stackstringno
componentStackstringnoComponent stack.
userAgentstringno
Example
{
  "island": "string",
  "route": "string",
  "message": "string",
  "stack": "string",
  "componentStack": "string",
  "userAgent": "string"
}
Responses
StatusDescription
202Accepted. `recorded` distinguishes stored from dropped (capture off, no session, empty).
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (202)
{
  "ok": false,
  "recorded": false,
  "capture": false
}
POST/client-absence
Report that a screen rendered nothing

Errors are covered by POST /client-errors; ABSENCES were not. Nothing in the running app noticed 'this container was populated and is now empty with no navigation' or 'this mount point has had no root for N seconds', so a blank screen in front of a customer could coexist with every dashboard green.

PRIVACY SHAPE: the whole of it. The payload is a route TEMPLATE and a kind, and nothing else: no user id, no tenant id, no DOM content, no message, no stack, no user agent. The browser sends the request with credentials: "omit", so no session cookie arrives and the server cannot attribute the beacon even in principle; the handler reads no session. Route templates are identical for every tenant, and a concrete deep link is normalised to its pattern (/app/policy/edit/$id) before it leaves the browser. Nothing is stored: it increments the Prometheus counter client_absence_total{route,kind}, readable only through the ops-token-gated GET /metrics.

Public: a screen that never rendered has no session to present.

An unrecognised route or kind is dropped. Always answers 202.

Request body required
PropertyTypeRequiredDescription
kindstringnoWhich invariant broke. `no-root-for-Ns` keeps the literal N: the threshold is a client constant, and baking its value in would re-key the series whenever it is tuned.
routestringnoA route template of the browser app, e.g. `/app/approvals` or `/app/policy/edit/$id`: never a concrete URL, never a query string.
Example
{
  "kind": "string",
  "route": "string"
}
Responses
StatusDescription
202Accepted. `recorded` distinguishes counted from dropped (unknown route/kind, oversized, throttled).
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (202)
{
  "ok": false,
  "recorded": false
}
POST/setup-lessons
Report something a bank asked for that the setup wizard didn't cover

Available on the SFTP and Web Services setup wizards, for something the bank asked for that the wizard did not cover (a division number, say). Tenant-scoped by the session. Any signed-in user with an organisation may file one.

The note is encrypted at rest and reviewed by a system admin; it is not applied to a bank definition automatically. Credentials and national identity numbers are stripped before storage; other detail (a division or VAT number the bank asked for) is kept.

Request body required
PropertyTypeRequiredDescription
wizardenumyesWhich setup wizard filed it.
stepstringnoThe wizard's own step key in view when filed, if any.
bankKeystringnoThe bank being set up, when the wizard had resolved one.
notestringyesThe free-typed lesson: what the bank asked for.
Example
{
  "wizard": "sftp",
  "step": "string",
  "bankKey": "string",
  "note": "string"
}
Responses
StatusDescription
201Recorded.
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (201)
{
  "ok": false,
  "id": "string",
  "createdAt": "string"
}
GET/bank-coverage-requests
List all bank coverage requests (Admin only)
Parameters
NameInRequiredDescription
status enumquerynoNarrow the list to one lifecycle state. The tenant scope is unaffected.
limit integerqueryno
cursor stringqueryno
Responses
StatusDescription
200All bank coverage requests
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "query": "string",
      "email": "string",
      "requestedByUserId": "string",
      "requestedByName": "string",
      "companyId": "string",
      "createdAt": "string",
      "status": "open",
      "statusChangedAt": "string",
      "statusNote": "string",
      "bankKey": "string",
      "notifiedAt": "string",
      "demandKey": "string"
    }
  ],
  "nextCursor": "string"
}
POST/bank-coverage-requests
Ask BankConnector to add coverage for a bank we don't support yet

Any signed-in user (or anonymous) can submit a BIC or bank name for a bank BankConnector does not yet cover. Not a request sent to the bank itself. It is queued for the development team.

Request body required
PropertyTypeRequiredDescription
querystringyesBIC code or bank name.
emailobjectno
Example
{
  "query": "string",
  "email": "string"
}
Responses
StatusDescription
201Request recorded
400Empty query
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (201)
{
  "ok": false,
  "request": {
    "id": "string",
    "query": "string",
    "createdAt": "string"
  }
}
GET/bank-coverage-requests/demand
Which banks customers are waiting on, most-wanted first (system operator only)

The roadmap signal. The per-request list answers "who asked what?"; this answers "what should we build next?". Requests are grouped by the operator-assigned bank where one exists, else by a database-generated fold of what the customer typed (case/punctuation folded; a BIC folded to its 8-character institution+country prefix). 🔒 The response carries NO requester PII, only counts, dates and the customer's own typed bank text, which is what makes a cross-tenant aggregate safe to serve at all. System operator only: a per-tenant slice of a cross-tenant count would let one tenant infer another's bank interest.

Parameters
NameInRequiredDescription
limit integerqueryno
Responses
StatusDescription
200Demand per bank, most-wanted first
401Sign in required: there is no valid session.
403System operator only
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "key": "string",
      "bankKey": "string",
      "bankLive": false,
      "sampleQuery": "string",
      "total": 0,
      "waiting": 0,
      "open": 0,
      "acknowledged": 0,
      "shipped": 0,
      "declined": 0,
      "companies": 0,
      "contactable": 0,
      "firstRequestedAt": "string",
      "lastRequestedAt": "string"
    }
  ]
}
PATCH/bank-coverage-requests/{id}
Move a bank coverage request's status, and optionally tell the requester (system operator only)

open → acknowledged → shipped | declined. The status is the PROVIDER's roadmap state, so only the system operator moves it. bankKey links the request to a registry bank, which is what makes the demand aggregate countable and a notification possible.

notify: true sends the requester one message saying their bank is now supported. It is an explicit operator action, never automatic, and it is REFUSED (409) unless the request is shipped, is linked to a bank, that bank is connectivity-proven, and the row carries an address: and it can happen at most once per request.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
statusenumyes
notestringnoInternal operator note. Never sent to the requester.
bankKeystringnoRegistry bank key, `<slug>-<cc>`.
notifybooleannoTell the requester their bank shipped.
Example
{
  "status": "open",
  "note": "string",
  "bankKey": "string",
  "notify": false
}
Responses
StatusDescription
200Updated request; `notified` says whether a message actually went out
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403System operator only
404No such request, or an unknown bankKey
409Refused: not notifiable in this state, or already notified
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "request": {
    "id": "string",
    "query": "string",
    "email": "string",
    "requestedByUserId": "string",
    "requestedByName": "string",
    "companyId": "string",
    "createdAt": "string",
    "status": "open",
    "statusChangedAt": "string",
    "statusNote": "string",
    "bankKey": "string",
    "notifiedAt": "string",
    "demandKey": "string"
  },
  "notified": false
}

Billing

GET/billing/packages
The public package catalogue (Starter / Growth / Scale)

Every publicly offered package, presentation-ordered, each merged with its live Stripe price. The amount, currency, billing interval and included-payment allowance are read from Stripe on every request (and cached, Stripe Prices are immutable), never stored in this platform's own database, so the number shown here can never disagree with what Checkout actually charges. overageRatePerPayment is what each payment past the allowance costs, an exact decimal string in the package's currency excluding VAT, read from the package's metered overage Price; null when that Price cannot be read as a free tier up to the allowance followed by one rate.

Responses
StatusDescription
200List of packages
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "stripePriceId": "string",
      "displayName": "string",
      "marketingCopy": "string",
      "featureBullets": [
        "string"
      ],
      "sortOrder": 0,
      "mostPopular": false,
      "price": {
        "amount": "string",
        "currency": "string",
        "interval": "string"
      },
      "includedPayments": 0,
      "overageRatePerPayment": "string"
    }
  ]
}
POST/billing/checkout
Start hosted Stripe Checkout for a package

Creates a hosted Stripe Checkout Session (mode: subscription) for the chosen package and returns its URL: redirect the browser there. The session carries both the package's flat recurring Price and its metered overage Price, so the subscription is complete the moment Checkout does. Session-only (Admin); an API key cannot call this. stripePriceId must be one of the ids GET /billing/packages publishes.

Request body required
PropertyTypeRequiredDescription
companyIdstringyes
stripePriceIdstringyesThe chosen package's flat recurring Price id.
continueWithoutVatNumberbooleannoThe answer to a 409 `vat_number_not_confirmed`: subscribe although the VAT register does not recognise the organisation's VAT number. In the EU outside Denmark the number is then not put on the Stripe Customer, so the invoices carry Danish VAT until a valid number is confirmed; a Norwegian number is kept on the Customer.
Example
{
  "companyId": "string",
  "stripePriceId": "string",
  "continueWithoutVatNumber": false
}
Responses
StatusDescription
200Hosted Checkout URL
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404Unknown or unavailable package
409The organisation already holds a subscription (`already_subscribed`). Stripe allows any number of subscriptions per Customer, so a second Checkout would charge a second flat fee and meter the same usage twice; change its package with `POST /billing/change-package`, or cancel it through the Customer Portal (`POST /billing/portal`), instead. Or the organisation holds no live subscription but its Stripe Customer still owes an invoice from an earlier one, open after a failed collection attempt or uncollectible (`invoice_unpaid`): pay it through the Customer Portal first, and no Checkout Session is created until then. Or the organisation has recorded no legal name, no registered-address country, or, outside the EU, no VAT number of the kind its country requires (a Norwegian organisation number, a Swiss number ending MWST/TVA/IVA, a business tax ID elsewhere), or Stripe refused such a required number (`legal_identity_incomplete`). The invoice has to name the customer's legal entity, the country is the location Stripe Tax taxes on, and outside the EU the number is the evidence that the buyer is a business; a VAT number is optional in Denmark and the rest of the EU. The message names every field that is missing. The rest of the registered address and the billing contact are each optional and each reach the Stripe Customer when present. Or the VAT register (VIES for a number in the EU, the Norwegian register of companies for Norway) does not recognise the organisation's VAT number (`vat_number_not_confirmed`): it is checked once, for at most about 3 seconds, before Checkout opens, and a register that does not answer in time lets Checkout go on. `details.register` names the register and `details.continuesWith` says what sending the request again with `continueWithoutVatNumber` subscribes with: `danish_vat`, or the `number` as it is. A number the register confirmed is locked from then on. Or BankConnector put the organisation on the Free plan (`conflict`; `GET /billing/subscription` reports it as `freePlan`): it needs no package.
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
503Billing is not configured on this deployment, Stripe could not be reached, or Stripe did not take the organisation's legal identity onto its billing account. Checkout is not started against a Customer whose first invoice would carry no legal name. Nothing is undone; a retry pushes the identity again. Or Stripe REFUSED the Checkout Session itself (`billing_unavailable`: a permission error on the API key, an account-default conflict); Stripe's own text reaches only the operator's log and Sentry, never this response.
Example response (200)
{
  "url": "string"
}
GET/billing/subscription
Whether this organisation already holds a subscription

Reads the organisation's subscription STATE from Stripe: subscribed, the Stripe subscription status behind it (active, trialing, past_due, unpaid, or null when there is none), and hasBillingAccount: whether a Stripe Customer exists at all, which is what makes the Customer Portal reachable. Carries no amounts, price ids or period dates; Stripe holds them. Session-only (Admin); an API key cannot call this. Answers 503 rather than guessing when Stripe cannot be reached.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Subscription state
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
503Stripe could not be reached
Example response (200)
{
  "subscribed": false,
  "status": "string",
  "hasBillingAccount": false,
  "taxLocationRequired": false,
  "nextInvoice": {
    "date": "string",
    "amount": "string",
    "currency": "string"
  },
  "freePlan": false,
  "freePlanSource": "bankconnector"
}
GET/billing/usage
Payments used in the current billing period

The organisation's usage in its current billing period, as it will be invoiced: paymentsUsed (the billable payments this period's invoice bills: those delivered since periodStart, the subscription's own period in Stripe, never the calendar month, plus paymentsCarriedIn, those delivered before it and billed in it), ownAccountTransfers (transfers to the organisation's own accounts delivered since periodStart: not billed, so not in paymentsUsed), the package's includedPayments and its packagePriceId (the id GET /billing/packages publishes for it), paymentsOver the allowance and the overageSoFar at the package's overageRatePerPayment (exact decimal strings, excluding VAT), and resetsAt, when the period ends and the allowance resets. In the subscription's firstPeriod (signup to the first 1st, flat fee waived) the whole allowance is free and the overage past it is billed on the first invoice, so overageSoFar is that period's charge too. A package change inside the period splits it, as Stripe bills each package's part against that package's own allowance: the count, the allowance, paymentsOver and overageSoFar are then the current package's part since the change, and beforePackageChange is the part before the period's last change (changedAt, the payments delivered before it and the overage the invoice bills for them, 0.00 in the first period, where none of it is billed); null without a change. packagePrices lists each public package in currency at the flat monthly price this subscription pays on it, its list price: the price POST /billing/change-package lands on (null when Stripe could not be read for them). state is metered with usage, not_subscribed when there is no live subscription, or unreadable when the subscription's package cannot be read exactly from Stripe. The amounts are the subscription's own Stripe Prices. Session-only (Admin); an API key cannot call this. Answers 503 rather than guessing when Stripe cannot be reached.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Usage in the current billing period
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
503Stripe could not be reached
Example response (200)
{
  "state": "metered",
  "usage": {
    "packageName": "string",
    "packagePriceId": "string",
    "includedPayments": 0,
    "paymentsUsed": 0,
    "paymentsCarriedIn": 0,
    "ownAccountTransfers": 0,
    "paymentsOver": 0,
    "overageRatePerPayment": "string",
    "overageSoFar": "string",
    "beforePackageChange": {
      "changedAt": "string",
      "payments": 0,
      "overage": "string"
    },
    "firstPeriod": false,
    "currency": "EUR",
    "periodStart": "string",
    "resetsAt": "string",
    "countedAt": "string",
    "packagePrices": [
      {
        "stripePriceId": "string",
        "amount": "string"
      }
    ]
  }
}
POST/billing/change-package
Change the organisation's package

Moves the organisation's live subscription to another package: both the monthly package price and the per-payment overage price change together. stripePriceId must be one of the ids GET /billing/packages publishes. A change made in the subscription's first period (signup to the first 1st, which is free) costs nothing extra: the new package's full price applies from the 1st (charge: free_first_period). A change in any later period is prorated: a credit for the unused part of the old package and a charge for the new one for the rest of the month, both on the next invoice (charge: prorated). Payments sent before the change are billed at the old package's overage rate and payments after it at the new one's. Asking for the package the subscription is already on changes nothing and answers changed: false, so a repeated request is safe. Session-only (Admin); an API key cannot call this.

Request body required
PropertyTypeRequiredDescription
companyIdstringyes
stripePriceIdstringyesThe chosen package's flat recurring Price id.
Example
{
  "companyId": "string",
  "stripePriceId": "string"
}
Responses
StatusDescription
200The package the subscription is on now, and how the change is charged
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404Unknown or unavailable package
409The organisation holds no live subscription (`not_subscribed`). Subscribe with `POST /billing/checkout` first. Or the subscription changed while the request was running, or its items are not the flat and metered pair a package change moves (`conflict`); the message says which.
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
503Billing is not configured on this deployment, Stripe could not be reached, or Stripe REFUSED the subscription update itself (`billing_unavailable`: a permission error on the API key, an account-default conflict); Stripe's own text reaches only the operator's log and Sentry, never this response.
Example response (200)
{
  "changed": false,
  "packageName": "string",
  "charge": "free_first_period"
}
POST/billing/portal
Open the Stripe Customer Portal

Creates a hosted Stripe Customer Portal session and returns its URL. Redirect the browser there. The Portal offers cancellation at the end of the billing period, payment-method updates and the invoice history; nothing here is rendered by this application itself. It does not change packages: Stripe's Portal cannot update a subscription that has a flat and a metered item, so a package change is POST /billing/change-package. Session-only (Admin). 409 when the company has never started Checkout, since there is then no Stripe Customer for the Portal to manage.

Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Hosted Customer Portal URL
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
409No billing account yet. Start Checkout first
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
503Billing is not configured on this deployment, or Stripe REFUSED the Portal session itself (`billing_unavailable`: a permission error on the API key, an account-default conflict); Stripe's own text reaches only the operator's log and Sentry, never this response.
Example response (200)
{
  "url": "string"
}

Workspace Admin

POST/auth/company-context
Enter a company context (platform admin acts AS a company)

Workspace (platform) admin only. Sets the session's active company so the admin acts as an ADMIN of that company. The company must belong to the admin's platform. Cleared with DELETE.

Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Context set
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Not a workspace admin: a company session, an API key or an install is refused (`forbidden`).
404Unknown company in your platform
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "ok": false,
  "csrfToken": "string"
}
DELETE/auth/company-context
Exit the company context (back to pure platform-admin scope)
Responses
StatusDescription
200Context cleared
401Sign in required: there is no valid session.
403Not a workspace admin: a company session, an API key or an install is refused (`forbidden`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "ok": false
}

Tenancy

GET/company/approval-settings
Read this organisation's approval-governance settings

Readable by any authenticated member of the organisation, forbidSelfApproval decides whether the person who created a payment may approve it, so everyone subject to it can see it. Scope comes from the caller's own context (or an explicit companyId query param for a per-request caller).

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Approval settings
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "approvalSettings": {
    "forbidSelfApproval": false,
    "updatedAt": "string",
    "updatedBy": "string"
  }
}
PATCH/company/approval-settings
Patch this organisation's approval-governance settings

Sanitised partial patch of forbidSelfApproval: the organisation-wide maker-checker rule, and the whole of the writable surface. Unknown fields are stripped; an empty effective patch is a 400. There is no way to turn approvals off: approvalMode / externalApprovalAuthority were removed from the product, so a body naming them stores nothing and is answered 400 rather than 200. Requires a signed-in Admin of this organisation. An API key or an application install is refused, because an integration is usually the maker. Every write is journalled; clearing the ban carries weakening: true in the audit metadata.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body required
Responses
StatusDescription
200Updated settings
400Nothing to update
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "approvalSettings": {
    "forbidSelfApproval": false,
    "updatedAt": "string",
    "updatedBy": "string"
  }
}
GET/company/currency
Read the currency Home totals are converted into

Readable by any authenticated member. currency is the Admin's choice, else the currency of the registered address's country, else EUR; source says which.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The company currency
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "currency": {
    "currency": "string",
    "source": "chosen",
    "updatedAt": "string",
    "updatedBy": "string"
  }
}
PATCH/company/currency
Choose the currency Home totals are converted into

Requires a signed-in Admin of this organisation; journalled. currency: null clears the choice, so the currency follows the registered address's country again. A display and aggregation setting: it never changes the currency or amount of a payment, a file or a statement.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body required
PropertyTypeRequiredDescription
currencystring | nullyes
Example
{
  "currency": "string"
}
Responses
StatusDescription
200The setting as stored
400The body is not `{ currency: string | null }` with an active ISO 4217 code
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "currency": {
    "currency": "string",
    "source": "chosen",
    "updatedAt": "string",
    "updatedBy": "string"
  }
}
GET/company/product
Read what this organisation buys

Readable by any authenticated member. product is erp-addon (with the ERP in erp), direct-api or embedded, chosen at signup; packageChosen says whether an Admin may still change it.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The organisation's product
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "product": "erp-addon",
  "erp": "string",
  "packageChosen": false
}
PATCH/company/product
Change what this organisation buys

Requires a signed-in Admin of this organisation; journalled (org.product-changed). Body { product: "direct-api" } or { product: "erp-addon", erp: "uniconta" }. Refused once the organisation has chosen a package (409 package_chosen): BankConnector support changes it then. embedded is set up by BankConnector: choosing it is refused (422), and so is any change to an organisation already on it (409 product_embedded).

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body required
PropertyTypeRequiredDescription
productenumyes
erpstring | nullno
Example
{
  "product": "erp-addon",
  "erp": "string"
}
Responses
StatusDescription
200The product as stored
400The body is not `{ product, erp? }`
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
409The organisation has chosen a package, or is on Embedded
413The request body is larger than this operation accepts (`payload_too_large`).
422`embedded`, or an `erp` that is missing, unknown or sent with another product
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "product": "erp-addon",
  "erp": "string",
  "packageChosen": false
}
GET/company/erp-approval
Read whether approvers may decide inside the ERP add-on

Readable by any authenticated member. Carries the switch and the two preconditions it stands on, whether the organisation requires two-factor authentication, and which policies in force name no approvers. The switch is off by default; for an organisation an ERP add-on signed up it turns on by itself the first time both preconditions hold, unless an Admin has set it first.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The ERP-approval setting
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "erpApproval": {
    "enabled": false,
    "updatedAt": "string",
    "updatedBy": "string",
    "require2fa": false,
    "policiesNamingNobody": [
      {
        "id": "string",
        "name": "string"
      }
    ]
  }
}
PATCH/company/erp-approval
Turn approving in the ERP add-on on or off

Requires a signed-in Admin of this organisation; journalled. Turning it on is refused (409) unless the organisation requires two-factor authentication (erp_approval_requires_two_factor) and every policy in force names its approvers (erp_approval_requires_named_approvers). Turning it off is never refused, and stands: an organisation an ERP add-on signed up does not have it turn back on by itself.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body required
PropertyTypeRequiredDescription
enabledbooleanyes
Example
{
  "enabled": false
}
Responses
StatusDescription
200The setting as stored
400The body is not `{ enabled: boolean }`
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
409A precondition is missing
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "erpApproval": {
    "enabled": false,
    "updatedAt": "string",
    "updatedBy": "string",
    "require2fa": false,
    "policiesNamingNobody": [
      {
        "id": "string",
        "name": "string"
      }
    ]
  }
}
GET/company/payee-verification
Read payee verification on this organisation's files of several payments

Readable by any authenticated member. Whether a SEPA file of several payments sent over EBICS to a bank in Germany, or to Oberbank, Raiffeisen Bank International, UniCredit Bank Austria or Erste Group Bank in Austria, goes out with the bank's payee check (Verification of Payee, opt-in) or without it (opt-out); at every other Austrian bank each file keeps the opt-out order type whatever this setting says. A file of one payment at a covered bank is always checked. opt-in when never set.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The payee-verification setting
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "payeeVerification": {
    "batches": "opt-in",
    "updatedAt": "string",
    "updatedBy": "string"
  }
}
PATCH/company/payee-verification
Choose payee verification on this organisation's files of several payments

Requires a signed-in Admin of this organisation; journalled (org.payee-verification-changed, with weakening: true when it turns the check off). Body { batches: "opt-in" | "opt-out" }. An opted-in file waits at the bank after the check until your own signers release it (awaiting-signer-release); BankConnector never releases it without one of them deciding.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body required
PropertyTypeRequiredDescription
batchesenumyes
Example
{
  "batches": "opt-in"
}
Responses
StatusDescription
200The setting as stored
400The body is not `{ batches: "opt-in" | "opt-out" }`
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "payeeVerification": {
    "batches": "opt-in",
    "updatedAt": "string",
    "updatedBy": "string"
  }
}
PATCH/company/name
Rename this organisation

Sets the organisation's display name: how it reads in lists, on invoices and in the activity log. Not the legal name (PATCH /company/legal-identity), which is the name invoices are addressed to. name is trimmed and must be 1 to 70 characters. Requires a signed-in Admin of this organisation; an API key, an application install and delegated partner access are refused. A change is recorded on the organisation's activity feed as company.renamed; saving the name it already has changes and records nothing.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body required
PropertyTypeRequiredDescription
namestringyesThe organisation's display name, as it appears in lists, invoices and the activity log.
Example
{
  "name": "string"
}
Responses
StatusDescription
200The organisation's name after the write
400`name` missing, empty, or longer than 70 characters
401Sign in required: there is no valid session.
403Not an Admin of this organisation, or `partner_grant_cannot_rename`: delegated partner access does not include renaming it
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "name": "string"
}
GET/company/alert-settings
Read this organisation's operational-alert inbox and switches

Where alerts about problems that stop money moving are emailed, and which of them: a certificate or key about to expire, the bank rejecting a batch, a bank channel that stops responding. An organisation that has never set it answers the defaults. No inbox, every switch on. Requires a signed-in Admin of this organisation.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Alert settings
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "alertSettings": {
    "email": "string",
    "pendingEmail": "string",
    "certExpiring": false,
    "batchRejected": false,
    "channelDown": false,
    "statementMissing": false,
    "updatedAt": "string",
    "updatedBy": "string"
  }
}
PATCH/company/alert-settings
Change this organisation's operational-alert inbox and switches

Partial patch of email / certExpiring / batchRejected / channelDown / statementMissing. A field present overrides, an absent one keeps its value, and email: null clears the inbox. An unknown field, an email that is not an email address, or an empty body is a 400. Requires a signed-in Admin of this organisation; every change is recorded on the organisation's activity feed.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body required
PropertyTypeRequiredDescription
emailstring | nullnoThe inbox alerts are sent to. `null` clears it, and then nothing is sent.
certExpiringbooleannoAlert when a certificate or key is about to expire, or has.
batchRejectedbooleannoAlert when the bank rejects a batch.
channelDownbooleannoAlert when a bank channel stops responding.
statementMissingbooleannoAlert when an expected end-of-day statement has not arrived by 10:00 on a bank day. Off by default.
Example
{
  "email": "string",
  "certExpiring": false,
  "batchRejected": false,
  "channelDown": false,
  "statementMissing": false
}
Responses
StatusDescription
200Updated alert settings
400Invalid body, or nothing to update
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "alertSettings": {
    "email": "string",
    "pendingEmail": "string",
    "certExpiring": false,
    "batchRejected": false,
    "channelDown": false,
    "statementMissing": false,
    "updatedAt": "string",
    "updatedBy": "string"
  }
}
POST/company/alert-settings/resend-confirmation
Resend the operational-alert inbox's confirmation link

Mints a fresh, single-use link for whichever address is currently pending and emails it, superseding any earlier outstanding link. Requires a signed-in Admin of this organisation and is rate-limited per organisation. A 400 when nothing is pending.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200A fresh link was sent
400Nothing is pending
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many resend requests for this organisation
Example response (200)
{
  "ok": false,
  "pendingEmail": "string"
}
GET/alert-inbox/confirm
The operational-alert inbox confirmation page (HTML, public)

The page an emailed confirmation link opens. Its button POSTs to redeem the token. The link carries the token in the URL fragment (#token=…), which a browser never sends, so this GET takes no parameters; the page's script reads the fragment, and a missing or malformed token renders the same refused state a POST would.

Responses
StatusDescription
200HTML page
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
POST/alert-inbox/confirm
Redeem an operational-alert inbox confirmation link

PUBLIC: the token is the only credential this needs. A not-found, an already-redeemed and an expired token all answer the identical 400 refusal. There is nothing here for a caller to enumerate. On success the pending address becomes the organisation's confirmed alert inbox.

Request body required
PropertyTypeRequiredDescription
tokenstringno
Example
{
  "token": "string"
}
Responses
StatusDescription
200Confirmed
400Unknown, already-redeemed or expired token
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "ok": false,
  "email": "string"
}
GET/company/api-keys
List this organisation's API keys (metadata only: never the secret)

Requires a signed-in Admin of this organisation. Returns this organisation's active (non-revoked) self-service keys: id, label, createdAt, lastUsedAt. The raw key is never returned here: it is shown once, at creation.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
limit integerqueryno
cursor stringqueryno
Responses
StatusDescription
200API keys (no secret)
400A `limit` that is not a number (`invalid_parameter`), or a malformed `cursor` (`invalid_cursor`).
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "label": "string",
      "createdAt": "string",
      "lastUsedAt": "string"
    }
  ],
  "nextCursor": "string"
}
POST/company/api-keys
Create an API key (the raw key is shown once)

Requires a signed-in Admin of this organisation. Mints a new key bound to this organisation; the raw key value appears only in this 201 response and is never stored or retrievable again. Store it securely. Step-up (ASVS 7.5.3): when the admin is enrolled in 2FA, or their company requires it, the body must carry a current authenticator code (or a backupCode), on every mint: there is no recently-verified window. A passed step-up rotates a cookie session.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body required
PropertyTypeRequiredDescription
labelstringyesHuman name, e.g. "Production ERP".
codestringno2FA TOTP code (when step-up applies).
backupCodestringnoA 2FA backup code, in place of `code`.
Example
{
  "label": "string",
  "code": "string",
  "backupCode": "string"
}
Responses
StatusDescription
201Key created: raw key shown once
400A blank `label` (`bad_request`), refused before the code is checked so a single-use code is not spent; or a body that is not JSON (`validation_failed`)
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422Step-up refused: `totp_required` (the 2FA code is missing or wrong) or `totp_enrollment_required` (the company requires 2FA and this admin has not set it up)
429Too many wrong 2FA codes (`rate_limited`); see `Retry-After`
Example response (201)
{
  "id": "string",
  "key": "string",
  "label": "string",
  "createdAt": "string"
}
DELETE/company/api-keys/{keyId}
Revoke an API key

Requires a signed-in Admin of this organisation. Soft-revokes the key (it stays for audit but stops authenticating immediately). Step-up (ASVS 7.5.3): the same second factor as creating a key, in an optional JSON body.

Parameters
NameInRequiredDescription
keyId stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body
PropertyTypeRequiredDescription
codestringno2FA TOTP code (when step-up applies).
backupCodestringnoA 2FA backup code, in place of `code`.
Example
{
  "code": "string",
  "backupCode": "string"
}
Responses
StatusDescription
200Revoked
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404Unknown or already-revoked key for this organisation, refused before the code is checked so a single-use code is not spent
413The request body is larger than this operation accepts (`payload_too_large`).
422Step-up refused: `totp_required` (the 2FA code is missing or wrong) or `totp_enrollment_required` (the company requires 2FA and this admin has not set it up)
429Too many wrong 2FA codes (`rate_limited`); see `Retry-After`
Example response (200)
{
  "id": "string",
  "revoked": false
}
GET/partner-access/requests
The CUSTOMER's own incoming partner-access requests

Every request made against the caller's own organisation, most recent first. Readable by any authenticated member: the same 'everyone governed by it may see it' posture /company/approval-settings uses.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Incoming requests
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "orgId": "string",
      "firmId": "string",
      "firmName": "string",
      "requestedBy": "string",
      "requestedByName": "string",
      "requestedLevel": "status",
      "status": "pending",
      "createdAt": "string",
      "decidedAt": "string",
      "decidedBy": "string"
    }
  ]
}
POST/partner-access/requests
A partner consultant asks, for its firm, for an access level on a customer's organisation

A partner consultant's login asks, on behalf of its FIRM, for status / payments / administer on orgId: an organisation the firm referred and holds no live grant on yet. An orgId naming no organisation, or one the firm did not refer, is the same 404: asking is not a way to look up who is a customer. A pending, non-expired request for the same (organisation, firm, level) already existing is a 409, whichever of the firm's consultants filed it. Any other caller is a 403. Silently expires after 14 days and may be re-sent.

Request body required
PropertyTypeRequiredDescription
orgIdstringyes
levelenumyes
Example
{
  "orgId": "string",
  "level": "status"
}
Responses
StatusDescription
201Request recorded
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403The caller is not a partner firm's consultant
404No such organisation
409A pending request for this (organisation, level) already exists
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (201)
{
  "request": {
    "id": "string",
    "orgId": "string",
    "firmId": "string",
    "firmName": "string",
    "requestedBy": "string",
    "requestedByName": "string",
    "requestedLevel": "status",
    "status": "pending",
    "createdAt": "string",
    "decidedAt": "string",
    "decidedBy": "string"
  }
}
GET/partner-access/my-requests
A partner firm's own asks, across every organisation

Every request the caller's FIRM has made, by any of its consultants, most recent first, across all organisations (the firm holds no scope on any of them yet). A partner login only.

Responses
StatusDescription
200The firm's requests
401Sign in required: there is no valid session.
403The caller is not a partner firm's consultant
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "orgId": "string",
      "firmId": "string",
      "firmName": "string",
      "requestedBy": "string",
      "requestedByName": "string",
      "requestedLevel": "status",
      "status": "pending",
      "createdAt": "string",
      "decidedAt": "string",
      "decidedBy": "string"
    }
  ]
}
POST/partner-access/requests/{id}/approve
The customer approves a partner-access request

Mints a live partner:<level> grant for the requesting FIRM on this organisation, replacing any grant the firm already held here: every active consultant of the firm reaches the organisation at that level. level approves at a LOWER level than asked (a higher one is validation_failed: a 400 before BankConnector-Version: 2026-10-20, a 422 from it); absent, at the level asked. Requires a signed-in Admin of this organisation. A request that is already decided, has read-time-expired past 14 days, or was made before partner firms existed, is a 409.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body
PropertyTypeRequiredDescription
companyIdstringno
levelenumno
Example
{
  "companyId": "string",
  "level": "status"
}
Responses
StatusDescription
200Approved
400Before `BankConnector-Version: 2026-10-20`: a level higher than the one asked for (`validation_failed`).
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such request in this organisation
409Already decided, or expired
413The request body is larger than this operation accepts (`payload_too_large`).
422From `BankConnector-Version: 2026-10-20`: a level higher than the one asked for (`validation_failed`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "request": {
    "id": "string",
    "orgId": "string",
    "firmId": "string",
    "firmName": "string",
    "requestedBy": "string",
    "requestedByName": "string",
    "requestedLevel": "status",
    "status": "pending",
    "createdAt": "string",
    "decidedAt": "string",
    "decidedBy": "string"
  }
}
POST/partner-access/requests/{id}/deny
The customer denies a partner-access request

Mints nothing. Requires a signed-in Admin of this organisation. Same 404/409 shape as approve.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body
PropertyTypeRequiredDescription
companyIdstringno
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Denied
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such request in this organisation
409Already decided, or expired
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "request": {
    "id": "string",
    "orgId": "string",
    "firmId": "string",
    "firmName": "string",
    "requestedBy": "string",
    "requestedByName": "string",
    "requestedLevel": "status",
    "status": "pending",
    "createdAt": "string",
    "decidedAt": "string",
    "decidedBy": "string"
  }
}
POST/partner-access/grants/{userId}/revoke
The customer withdraws a partner-tier grant naming one person

Revokes a live partner-tier grant the named identity holds on this organisation in its own name: the shape partner access took before partner firms. A firm's access is withdrawn with POST /partner-access/firms/{firmId}/revoke. A no-op (never an error) when the identity held nothing to revoke. Requires a signed-in Admin of this organisation.

Parameters
NameInRequiredDescription
userId stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body
PropertyTypeRequiredDescription
companyIdstringno
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Revocation outcome
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "revoked": false
}
GET/partner-access/firms
The partner firms that reach this organisation, and the named people they reach it through

Each partner firm holding a live grant on the caller's organisation: its level, when and by whom it was granted, and every ACTIVE person of the firm, each of whom can enter this organisation now. Readable by any authenticated member.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The firms with access
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "firmId": "string",
      "firmName": "string",
      "level": "status",
      "grantedAt": "string",
      "grantedBy": "string",
      "consultants": [
        {
          "userId": "string",
          "name": "string",
          "email": "string",
          "role": "partner-admin"
        }
      ]
    }
  ]
}
GET/partner-access/firm-choices
The partner firms a customer can give access to

Every active partner firm on BankConnector, whether or not the general signup lists it: an id and a display name each, and nothing else. The id is what POST /partner-access/firms/{firmId}/grant takes. Readable by any authenticated member; a partner firm's consultant sees its own firm only.

Responses
StatusDescription
200The partner firms
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "displayName": "string"
    }
  ]
}
GET/partner-access/deleted-firms
The deleted partner firms that reached this organisation

Each partner firm BankConnector has deleted that introduced the caller's organisation, held access to it or asked for access: its name, when it was deleted, and whether it is credited with the introduction. A deleted firm's access and open requests ended with it, and its people were erased. Readable by any authenticated member; a partner firm's consultant sees none.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The deleted partner firms
401Authentication required: the credential is missing, invalid or expired.
403Forbidden: the credential's role, scope or grant does not allow this operation.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "firmId": "string",
      "firmName": "string",
      "deletedAt": "string",
      "introduced": false
    }
  ]
}
POST/partner-access/firms/{firmId}/grant
The customer gives a partner firm access, or changes its level

A direct grant: the customer's own act is the approval, with no request on the firm's side. Replaces any grant the firm already holds here. Requires a signed-in Admin of this organisation; no partner may grant access, whatever its own level. A firm that does not exist is a 404.

Parameters
NameInRequiredDescription
firmId stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body required
PropertyTypeRequiredDescription
companyIdstringno
levelenumyes
Example
{
  "companyId": "string",
  "level": "status"
}
Responses
StatusDescription
200The level the firm now holds
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No such partner
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "firmId": "string",
  "level": "status"
}
POST/partner-access/firms/{firmId}/revoke
The customer withdraws a partner firm's access

Every person of the firm loses access on their next request. A no-op (never an error) when the firm held nothing here. Requires a signed-in Admin of this organisation.

Parameters
NameInRequiredDescription
firmId stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body
PropertyTypeRequiredDescription
companyIdstringno
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Revocation outcome
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "revoked": false
}
GET/partner/firm
The caller's partner firm, and their role in it

A partner login only. Belonging to a firm reaches no customer by itself.

Responses
StatusDescription
200The firm
401Sign in required: there is no valid session.
403The caller is not a partner firm's consultant
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "firm": {
    "id": "string",
    "displayName": "string",
    "partnerType": "uniconta-partner"
  },
  "role": "partner-admin"
}
GET/partner/firm/members
The partner firm's people

Every login of the caller's firm, removed ones included. The firm's administrator only.

Responses
StatusDescription
200The firm's people
401Sign in required: there is no valid session.
403The caller is not this firm's administrator
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "email": "string",
      "name": "string",
      "role": "partner-admin",
      "status": "active",
      "createdAt": "string",
      "addonReleaseEmails": false
    }
  ]
}
POST/partner/firm/members
The firm's administrator invites someone into the firm

Creates a partner login and emails a one-time set-password link (role defaults to consultant). Inviting a removed or not-yet-joined member of the same firm again re-issues the link. An address already registered elsewhere is a 409. The firm's administrator only.

Request body required
PropertyTypeRequiredDescription
emailstringyes
namestringyes
roleenumno
Example
{
  "email": "string",
  "name": "string",
  "role": "partner-admin"
}
Responses
StatusDescription
201Invited
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403The caller is not this firm's administrator
409The address is already registered
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
503No email is configured to deliver the link
Example response (201)
{
  "member": {
    "id": "string",
    "email": "string",
    "name": "string",
    "role": "partner-admin",
    "status": "active",
    "createdAt": "string",
    "addonReleaseEmails": false
  },
  "invited": false,
  "emailDeliveryPending": false,
  "inviteLink": "string"
}
DELETE/partner/firm/members/{userId}
The firm's administrator takes someone out of the firm

Deactivates the login and ends its sessions: every customer the firm reaches stops being reachable for that person at once. Removing the firm's last administrator is a 409. The firm's administrator only.

Parameters
NameInRequiredDescription
userId stringpathyes
Responses
StatusDescription
200Removed
401Sign in required: there is no valid session.
403The caller is not this firm's administrator
404No such person in the firm
409The firm's last administrator
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "member": {
    "id": "string",
    "email": "string",
    "name": "string",
    "role": "partner-admin",
    "status": "active",
    "createdAt": "string",
    "addonReleaseEmails": false
  },
  "removed": false,
  "revokedSessions": 0
}
PATCH/partner/firm/members/{userId}/notifications
The firm's administrator switches a colleague's release emails on or off

Sets addonReleasePublished, the switch the person also sets on their own /partner/me/notifications: whether they are emailed when a new version of the firm's add-on is published. No other switch is changed for someone else. Someone active at the firm always gets these emails, so switching off the last active person who has them on is a 409. A change is recorded on the system audit chain under the administrator. The firm's administrator only.

Parameters
NameInRequiredDescription
userId stringpathyes
Request body required
PropertyTypeRequiredDescription
notificationsobjectyes
Example
{
  "notifications": {
    "addonReleasePublished": false
  }
}
Responses
StatusDescription
200The person, with their release emails as they now stand
400The body names another switch, or a value that is not true or false
401Sign in required: there is no valid session.
403The caller is not this firm's administrator
404No such person in the firm, or the person was removed from it
409The person is the last one at the firm who gets the release emails
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "member": {
    "id": "string",
    "email": "string",
    "name": "string",
    "role": "partner-admin",
    "status": "active",
    "createdAt": "string",
    "addonReleaseEmails": false
  }
}
POST/partner/firm/members/{userId}/two-factor-reset
The firm's administrator asks to reset a consultant's two-factor authentication

Changes nothing on the account: emails a single-use confirmation link to the consultant's own address, and the reset happens only when the consultant confirms it (POST /auth/2fa-reset/confirm). The administrator re-authenticates with their own current password and a current code (or backupCode) from their own authenticator. A firm administrator's own reset is done by BankConnector support. The firm's administrator only.

Parameters
NameInRequiredDescription
userId stringpathyes
Request body required
PropertyTypeRequiredDescription
passwordstringyes
codestringno
backupCodestringno
Example
{
  "password": "string",
  "code": "string",
  "backupCode": "string"
}
Responses
StatusDescription
200The confirmation link was emailed (or `emailDeliveryPending`)
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403The caller is not this firm's administrator, has no second factor, or the person is an administrator
404No such person in the firm
409The person has no active two-factor authentication to reset
413The request body is larger than this operation accepts (`payload_too_large`).
422The administrator's password or code was refused
429Too many attempts, or too many links sent to this person
503No email is configured to deliver the link
Example response (200)
{
  "requested": false,
  "userId": "string",
  "email": "string",
  "name": "string",
  "emailDeliveryPending": false
}
GET/partner/customers
The customers the caller's partner firm referred

Metadata only: legal name, signup date, whether the customer has a billing record, how many payments it has sent, and whether each bank connection is healthy. No payment, counterparty, statement or bank identity. Each row also says where the firm's latest ask for access stands. A partner login only.

Responses
StatusDescription
200The referred customers
401Sign in required: there is no valid session.
403The caller is not a partner firm's consultant
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "legalName": "string",
      "signupDate": "string",
      "subscriptionStatus": "subscribed",
      "paymentCount": 0,
      "bankConnections": [
        {
          "connectionId": "string",
          "healthy": false
        }
      ],
      "access": {
        "level": "status"
      },
      "accessRequest": {
        "status": "string",
        "requestedLevel": "status"
      }
    }
  ]
}
GET/partner/customer-logs
The bank connection state and refused files of the customers that give the caller's firm access

One entry per customer with a live grant to the firm: each bank connection's state (working, failing, being set up or switched off), since when it fails, its newest accepted payment or delivered statement, and the problem in plain words. At Payments access and above, also the payment and statement files the bank or the engine refused in the last 30 days, as the customer's own activity log words them; null below Payments. Revoking a grant removes the customer at once. A partner login only.

Parameters
NameInRequiredDescription
cursor stringquerynoThe previous page's `nextCursor`. A malformed one is 400 `invalid_cursor`.
Responses
StatusDescription
200The customers' logs
400A malformed `cursor` (`invalid_cursor`)
401Sign in required: there is no valid session.
403The caller is not a partner firm's consultant
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "companyId": "string",
      "legalName": "string",
      "accessLevel": "status",
      "connections": [
        {
          "connectionId": "string",
          "bankKey": "string",
          "bankName": "string",
          "environment": "test",
          "state": "working",
          "since": "string",
          "lastSuccessAt": "string",
          "problem": "string"
        }
      ],
      "refusals": [
        {
          "id": "string",
          "at": "string",
          "type": "string",
          "message": "string",
          "documentId": "string"
        }
      ]
    }
  ],
  "nextCursor": "string"
}
GET/partner/addon-releases
The ERP add-on releases the caller's partner firm can download

Newest first: the latest release (latest: true), downloadable however old it is, then each earlier one until availableUntil, a year after it was published. A withdrawn or expired release is not listed. Each carries its version, release notes, publish date, size and SHA-256. A login of a Uniconta partner firm only.

Responses
StatusDescription
200The downloadable releases
401No partner login
403The caller is not a login of a partner firm whose partner type has an add-on
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "product": "uniconta",
      "version": "string",
      "notes": "string",
      "publishedAt": "string",
      "fileKind": "zip",
      "fileName": "string",
      "sizeBytes": 0,
      "sha256": "string",
      "latest": false,
      "availableUntil": "string"
    }
  ]
}
GET/partner/addon-releases/{id}/file
Download one ERP add-on release package

The package exactly as published, as an attachment named BankConnector-Uniconta-<version>.zip (or .dll), with its SHA-256 in X-Content-SHA256. Each download is recorded with the firm and the person. A login of a Uniconta partner firm only.

Parameters
NameInRequiredDescription
id stringpathyes
Responses
StatusDescription
200The release package (attachment)
401No partner login
403The caller is not a login of a partner firm whose partner type has an add-on
404No release the firm can download now: withdrawn, expired or unknown
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
GET/partner/firm/uniconta-pid
The partner firm's Uniconta partner number

The number BankConnector confirmed as the firm's number in Uniconta (null when none), and the numbers the firm proposed itself, newest first, each pending, confirmed or rejected. Any member of the firm.

Responses
StatusDescription
200The firm's number and its proposals
401Sign in required: there is no valid session.
403The caller is not a partner firm's consultant
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "unicontaPid": 0,
  "proposals": [
    {
      "unicontaPid": 0,
      "status": "pending",
      "proposedAt": "string",
      "decidedAt": "string"
    }
  ]
}
POST/partner/firm/uniconta-pid-proposals
The firm's administrator proposes the firm's Uniconta partner number

Changes nothing until BankConnector confirms the number; the Uniconta add-on then recognises the firm's consultants by it. status is the number's state for this firm: pending, confirmed or rejected, and proposing a number again changes nothing. The answer does not depend on whether another partner holds the number. The firm may have three numbers waiting at once. The firm's administrator only.

Request body required
PropertyTypeRequiredDescription
unicontaPidintegeryes
Example
{
  "unicontaPid": 0
}
Responses
StatusDescription
200The proposed number and its state
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403The caller is not this firm's administrator
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429The firm already has three numbers waiting to be checked
Example response (200)
{
  "proposal": {
    "unicontaPid": 0,
    "status": "pending"
  }
}
GET/partner/me/notifications
The caller's own partner email notifications

Which of the firm's customer events the caller is emailed about: a customer signs up through the firm, approves or says no to a request for access, gives access directly or changes its level, or removes it; and whether they hear of a new version of the firm's add-on (addonReleasePublished). Every switch is on until the person turns it off. A partner login only, administrator or consultant.

Responses
StatusDescription
200The caller's switches
401Sign in required: there is no valid session.
403The caller is not a partner firm's consultant
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "notifications": {
    "customerSignedUp": false,
    "accessApproved": false,
    "accessDenied": false,
    "accessGranted": false,
    "accessRevoked": false,
    "addonReleasePublished": false
  }
}
PATCH/partner/me/notifications
Switch the caller's own partner email notifications on or off

Only the switches sent change; the others keep their value. Someone active at the firm always gets the release emails, so the last active person who has addonReleasePublished on cannot switch it off (409). A partner login only.

Request body required
PropertyTypeRequiredDescription
notificationsobjectyes
Example
{
  "notifications": {
    "customerSignedUp": false,
    "accessApproved": false,
    "accessDenied": false,
    "accessGranted": false,
    "accessRevoked": false,
    "addonReleasePublished": false
  }
}
Responses
StatusDescription
200The caller's switches as they now stand
400The body names a switch that does not exist, or a value that is not true or false
401Sign in required: there is no valid session.
403The caller is not a partner firm's consultant
409The caller is the last one at the firm who gets the release emails
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "notifications": {
    "customerSignedUp": false,
    "accessApproved": false,
    "accessDenied": false,
    "accessGranted": false,
    "accessRevoked": false,
    "addonReleasePublished": false
  }
}
PATCH/users/{id}/settings
Update a user's settings blob (partial)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
settingsobjectno
Example
{
  "companyId": "string",
  "settings": {
    "locale": "string",
    "dateFormat": "iso",
    "timezone": "string",
    "notifications": {
      "paymentNeedsApproval": false,
      "paymentApproved": false,
      "paymentRejected": false,
      "statementReceived": false,
      "erpDecisionReceipt": false
    }
  }
}
Responses
StatusDescription
200Updated user
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person.
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "id": "string",
  "companyId": "string",
  "email": "string",
  "name": "string",
  "roles": [
    "admin"
  ],
  "status": "active",
  "settings": {
    "locale": "string",
    "timezone": "string",
    "dateFormat": "iso",
    "notifications": {
      "paymentNeedsApproval": false,
      "paymentApproved": false,
      "paymentRejected": false,
      "statementReceived": false,
      "erpDecisionReceipt": false
    }
  },
  "totpEnabledAt": "string",
  "emailDeliveryFlag": {
    "kind": "hard_bounce",
    "at": "string"
  },
  "createdAt": "string"
}
PATCH/users/{id}/name
Change a user's display name

A signed-in person changes their own name, or an Admin of the same company changes a colleague's; a read-only Viewer may change only their own. The name is trimmed and must be 1 to 200 characters of plain text, with no control characters (a line break is refused, not rewritten). Recorded in the audit journal as user.renamed with the old and the new name. Session callers only; an API key is refused.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
namestringyes
Example
{
  "companyId": "string",
  "name": "string"
}
Responses
StatusDescription
200Updated user
400The name is empty, too long or holds control characters
401Sign in required: there is no valid session.
403Not your own record, and you are not an Admin of this company
404No such user in this company
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "id": "string",
  "companyId": "string",
  "email": "string",
  "name": "string",
  "roles": [
    "admin"
  ],
  "status": "active",
  "settings": {
    "locale": "string",
    "timezone": "string",
    "dateFormat": "iso",
    "notifications": {
      "paymentNeedsApproval": false,
      "paymentApproved": false,
      "paymentRejected": false,
      "statementReceived": false,
      "erpDecisionReceipt": false
    }
  },
  "totpEnabledAt": "string",
  "emailDeliveryFlag": {
    "kind": "hard_bounce",
    "at": "string"
  },
  "createdAt": "string"
}
GET/users/{id}/erp-grants
List a person's ERP add-on sign-ins

The person's live identity grants to ERP clients, their own sign-ins inside an ERP add-on, each consented to by them in the browser. Admin session only.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200The live sign-ins
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "grantId": "string",
      "application": "string",
      "scopes": [
        "string"
      ],
      "createdAt": "string",
      "expiresAt": "string"
    }
  ]
}
POST/users/{id}/erp-grants/{grantId}/revoke
Revoke one ERP add-on sign-in

Ends one of the person's ERP add-on sign-ins; every token it issued stops working on its next request. Admin session only; journalled.

Parameters
NameInRequiredDescription
id stringpathyes
grantId stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Responses
StatusDescription
200Revoked
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
404No live ERP add-on sign-in with that id for this user
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "revoked": false
}
PUT/users/{id}/roles
Replace a user's role set

PUT = full replacement of the role array (there is no partial role patch). Reports approval-quorum impact in both directions: approving is role-gated, so removing the Approver role from someone an approval policy names can block a bank's sends, and granting it can release one. Step-up (ASVS 7.5.3): a change that GRANTS Admin or Approver (a role the user does not hold now) needs the acting admin's current authenticator code (or a backupCode) when they are enrolled in 2FA or their company requires it, and a passed step-up rotates a cookie session. Removing a role, granting Viewer, or re-sending roles the user already holds needs no code. An API key cannot grant Admin or Approver at all (403), nor change the roles of a user who holds Admin.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringyes
rolesstring[]yes
codestringno2FA TOTP code (when step-up applies).
backupCodestringnoA 2FA backup code, in place of `code`.
Example
{
  "companyId": "string",
  "roles": [
    "string"
  ],
  "code": "string",
  "backupCode": "string"
}
Responses
StatusDescription
200Updated user
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Authentication required: the credential is missing, invalid or expired.
403The caller may not make this change: an API key granting Admin or Approver, or changing an Admin's roles; a system admin granting Admin or Approver
404No such user in this company (`not_found`), answered before any code is checked so a single-use code is not spent
413The request body is larger than this operation accepts (`payload_too_large`).
422Step-up refused: `totp_required` (the 2FA code is missing or wrong) or `totp_enrollment_required` (the company requires 2FA and this admin has not set it up)
429Too many wrong 2FA codes (`rate_limited`); see `Retry-After`
Example response (200)
{
  "user": {
    "id": "string",
    "companyId": "string",
    "email": "string",
    "name": "string",
    "roles": [
      "admin"
    ],
    "status": "active",
    "settings": {
      "locale": "string",
      "timezone": "string",
      "dateFormat": "iso",
      "notifications": {
        "paymentNeedsApproval": false,
        "paymentApproved": false,
        "paymentRejected": false,
        "statementReceived": false,
        "erpDecisionReceipt": false
      }
    },
    "totpEnabledAt": "string",
    "emailDeliveryFlag": {
      "kind": "hard_bounce",
      "at": "string"
    },
    "createdAt": "string"
  },
  "sessionsRevoked": 0,
  "banksPaused": [
    "string"
  ],
  "banksResumed": [
    "string"
  ]
}
POST/users/{id}/deactivate
Deactivate a user (keeps data, revokes access)

Keeps personal data for audit, revokes live sessions and reports approval-quorum impact.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringno
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200User deactivated
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "userId": "string",
  "deactivated": false,
  "banksPaused": [
    "string"
  ]
}
POST/users/{id}/reactivate
Reactivate a deactivated user

Restores a DEACTIVATED account to active (or to invited, when it never accepted its invite; no new token is minted, re-send the invite). An ERASED account is never restored, and is refused as a 404 alongside the unknown and not-deactivated cases. Reports approval-quorum impact in its resume direction.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringno
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200User reactivated
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "userId": "string",
  "reactivated": false,
  "status": "string",
  "banksResumed": [
    "string"
  ]
}
POST/users/{id}/clear-email-flag
Clear a user's email delivery problem flag

Clears the "email bounced" or "marked as spam" flag the email provider's webhook left on a colleague's record, once the address works again. Admin session only. Journalled as user.email-flag-cleared. A user with no flag, an unknown user and a user of another company are all a 404. A later bounce or complaint sets the flag again.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringno
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Flag cleared
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "userId": "string",
  "cleared": false
}
POST/users/{id}/sign-out
Sign a user out of every session

Ends every live session a colleague holds, on every device, and every ERP add-on sign-in they hold in this company, and changes nothing else: their password, two-factor and roles stay as they are, and they can sign in again at once. Admin session only. Journalled as auth.logout with scope: admin, and each ended add-on sign-in as grant.identity-revoked. An unknown user and a user of another company are both a 404; your own account is a 409 (use DELETE /me/sessions).

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringno
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Signed out; `revoked` counts the sessions ended, `erpGrantsRevoked` the ERP add-on sign-ins
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "userId": "string",
  "revoked": 0,
  "erpGrantsRevoked": 0
}
POST/users/{id}/reinvite
Re-send a user's invite (command)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringno
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Invite re-sent
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Authentication required: the credential is missing, invalid or expired.
403Admin required: a session without the Admin role is refused (`forbidden`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "id": "string",
  "companyId": "string",
  "email": "string",
  "name": "string",
  "roles": [
    "admin"
  ],
  "status": "active",
  "settings": {
    "locale": "string",
    "timezone": "string",
    "dateFormat": "iso",
    "notifications": {
      "paymentNeedsApproval": false,
      "paymentApproved": false,
      "paymentRejected": false,
      "statementReceived": false,
      "erpDecisionReceipt": false
    }
  },
  "totpEnabledAt": "string",
  "emailDeliveryFlag": {
    "kind": "hard_bounce",
    "at": "string"
  },
  "createdAt": "string",
  "invited": false,
  "emailDeliveryPending": false,
  "inviteLink": "string"
}
POST/users/{id}/reset-password
Trigger a password reset for a user (command)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
companyIdstringno
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Reset issued
400The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too.
401Sign in required: there is no valid session.
403Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`).
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "id": "string",
  "companyId": "string",
  "email": "string",
  "name": "string",
  "roles": [
    "admin"
  ],
  "status": "active",
  "settings": {
    "locale": "string",
    "timezone": "string",
    "dateFormat": "iso",
    "notifications": {
      "paymentNeedsApproval": false,
      "paymentApproved": false,
      "paymentRejected": false,
      "statementReceived": false,
      "erpDecisionReceipt": false
    }
  },
  "totpEnabledAt": "string",
  "emailDeliveryFlag": {
    "kind": "hard_bounce",
    "at": "string"
  },
  "createdAt": "string",
  "passwordReset": false,
  "emailDeliveryPending": false,
  "resetLink": "string"
}

Installs

GET/installs
List the organisation's application installs (Admin)

Every install belonging to the caller's organisation, each with its application's display name and its live (unrevoked, unexpired) grants. Keyset pagination: pass the previous page's nextCursor back as cursor. Installs are created by OAuth consent (/oauth/authorize); no credential secret is ever returned here.

status is whether the install was ended. access is whether the add-on can connect right now: active, stopped or revoked. An install whose token family was revoked after refresh-token reuse was detected, whose grant has expired, or whose application has been suspended fleet-wide reads stopped, and accessReason names which, suspicious_token_reuse, application_suspended, authorisation_revoked, authorisation_expired, credentials_ended or no_authorisation. A revoked install carries admin_revoked when an admin revoked it, and disconnected when its add-on revoked its own refresh token at /oauth/revoke (on disconnecting, or on replacing the connection with a new one).

Each consent run mints a new install with its own credentials, so an add-on authorised twice has two rows. authorisationNumber / authorisationCount say which of the organisation's authorisations of that application a row is; revoking one row leaves the others connected. erpCompanyId is the ERP company the add-on named when it connected (erp_company_id at /oauth/authorize), absent when it named none.

Parameters
NameInRequiredDescription
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
limit integerqueryno
cursor stringqueryno
Responses
StatusDescription
200The organisation's installs.
400A `limit` that is not a number (`invalid_parameter`), or a malformed `cursor` (`invalid_cursor`).
401Sign in required: there is no valid session.
403Admin required, or the grants:manage scope is missing
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "items": [
    {
      "id": "string",
      "applicationId": "string",
      "applicationSlug": "string",
      "applicationName": "string",
      "version": "string",
      "status": "string",
      "installedBy": "string",
      "installedByName": "string",
      "erpCompanyId": "string",
      "revokedAt": "string",
      "createdAt": "string",
      "grants": [
        {
          "id": "string",
          "scopes": [],
          "expiresAt": "string"
        }
      ],
      "access": "active",
      "accessReason": "admin_revoked",
      "authorisationNumber": 0,
      "authorisationCount": 0
    }
  ],
  "nextCursor": "string"
}
POST/installs/{id}/narrow
Remove scopes from a live grant, without revoking it (Admin)

The modify half of reviewing a granted consent (ASVS 10.7.3): an admin who wants an add-on to keep reading statements but stop submitting payments removes payments:submit and the integration keeps running: the alternative being to revoke the install and re-authorise from scratch, with the integration down in between. scopes is the full set the grant should keep, not a list to remove.

Narrowing only. The write refuses any set that is not a strict subset of what the grant already holds, so this endpoint can never add a scope: widening an app's access is what the consent screen at /oauth/authorize exists to authorise. A request that would widen answers 400 and names the offending scopes.

The change takes effect on the add-on's very next request. An access token carries no scopes of its own, so nothing needs revoking for the narrowing to bite.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body required
PropertyTypeRequiredDescription
grantIdstringnoWhich of the install's live grants to narrow. May be omitted when the install has exactly one, which is every install OAuth consent creates.
scopesstring[]noThe scopes to KEEP. A strict subset of what the grant holds. At least one is required; to remove them all, revoke the install instead.
reasonstringnoRecorded on the journal event.
Example
{
  "grantId": "string",
  "scopes": [
    "string"
  ],
  "reason": "string"
}
Responses
StatusDescription
200The grant's remaining scopes, and what was removed.
400No scope given, a non-delegable scope, a set that would WIDEN the grant, or the set it already holds.
401Sign in required: there is no valid session.
403Admin required, or the grants:manage scope is missing
404Unknown or revoked install, or unknown/revoked/expired grant.
409This grant has live delegated grants beneath it, revoke those first.
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "installId": "string",
  "grant": {
    "id": "string",
    "scopes": [
      "string"
    ]
  },
  "removed": [
    "string"
  ]
}
POST/installs/{id}/revoke
Revoke an install, a person's or an application's installs, or the whole organisation's (Admin)

Four revocation shapes, chosen by scope and all fenced to the caller's own organisation: install (the default, just this one), installer (every install of this install's application approved by the same person, to unlink one person), application (every install of this install's application, whoever approved it, to disconnect the app) and organisation (every install of every application, the break-glass). Installs of other applications survive installer and application. Suspending an application across every customer is POST /system/applications/{slug}/suspend, a System-plane route, because a customer's admin must never suspend an app for other customers. With install, an already-revoked install answers 404 rather than revoking twice.

Parameters
NameInRequiredDescription
id stringpathyes
companyId stringquerynoThe organisation this request acts on. Required with an API key. A signed-in company user, an application install or a delegated user falls back to its own company when this is omitted; a workspace administrator falls back to the company selected with `POST /auth/company-context`.
Request body required
PropertyTypeRequiredDescription
scopeenumnoWhich revocation shape to apply. Defaults to this install alone. `installer`: every install of this install's application the same person approved. `application`: every install of this install's application. `organisation`: every install in the organisation.
reasonstringnoRecorded on the journal event.
Example
{
  "scope": "install",
  "reason": "string"
}
Responses
StatusDescription
200How many installs were revoked, and under which shape.
400Validation failed.
401Sign in required: there is no valid session.
403Admin required, or the grants:manage scope is missing
404Unknown or already-revoked install (scope=install), or an install unknown to this organisation (scope=application).
409scope=installer, but this install has no recorded installer to revoke by.
413The request body is larger than this operation accepts (`payload_too_large`).
422The body is JSON but fails the route's schema, or names a field the route does not read (`validation_failed`, one entry per problem in `details.issues`). Pin `BankConnector-Version: 2026-10-20` to get 422; earlier pins answer 400.
429Too many requests from this network (`rate_limited`); wait `Retry-After` seconds.
Example response (200)
{
  "installId": "string",
  "shape": "string",
  "revoked": 0
}