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)
/connectivity/profilesRead-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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 enum | query | no | `badge` projects each row down to identity + channel badge. Omit it for the full connection declaration. Any other value is a 400 `invalid_parameter`. |
| Status | Description |
|---|---|
| 200 | Connectivity profiles |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
]
}/connections| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Connection list |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
]
}
}
]
}/connectionsCreates 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."
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
bankKey | string | yes | |
environment | string | no | |
countries | string[] | no |
{
"companyId": "string",
"bankKey": "string",
"environment": "string",
"countries": [
"string"
]
}| Status | Description |
|---|---|
| 201 | Connection created |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
]
}/connections/{id}| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Connection + readiness |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 404 | Not found |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
}/connections/{id}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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
confirm string | query | no | The connection's own `bankKey`. Required when the channel is production or live; ignored otherwise. |
companyId string | query | no | The 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. |
| Status | Description |
|---|---|
| 200 | Channel deleted: the body is the receipt (what was destroyed, and what survived) |
| 400 | Confirmation required: re-send with ?confirm=<bankKey> |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | Not found (unknown connection, or one that was already deleted) |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"deleted": false,
"bankKey": "string",
"environment": "test",
"secretsDestroyed": 0,
"inboundAttemptsCleared": 0,
"openEbicsTransactions": 0,
"ebicsEnrolmentsCleared": 0,
"ebicsKeysetsDestroyed": 0,
"bankUnselected": false
}/connections/{id}/healthThe 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Channel health |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 404 | Not found |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
}/connections/{id}/intraday-reportAsks 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The reports this request ingested, or, inside the 15 minutes after the last fetch, that fetch's reports again |
| 400 | The bank endpoint is one the outbound address policy refuses (`validation_failed`; 422 on `BankConnector-Version: 2026-10-20`) |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 404 | No such connection for this company (`connection_not_found`) |
| 409 | The connection is being polled right now; try again in a minute |
| 422 | No intraday report to fetch on this connection: it is not active, its bank offers none, or it is a test connection |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
| 502 | The bank could not be reached |
{
"connectionId": "string",
"ingested": [
{
"documentId": "string",
"type": "string",
"name": "string"
}
],
"skipped": 0,
"complete": false,
"fetchedAt": "string",
"reused": false,
"nextFetchAt": "string"
}/connections/{id}/test-filesThe 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The test files, grouped by country |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 404 | Not found |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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
}/connections/{id}/test-files/acceptanceRecords 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
bankKey | string | yes | The covered bankKey the file belongs to. The country, in the connection's own coverage model. |
scenario | string | yes | The test scenario id, as `GET /connections/{id}/test-files` reports it. |
action | enum | yes | |
note | string | no | Optional free text kept with the record, how the bank confirmed, or why an acceptance was withdrawn. |
{
"companyId": "string",
"bankKey": "string",
"scenario": "string",
"action": "accept",
"note": "string"
}| Status | Description |
|---|---|
| 200 | Recorded: the refreshed test-file view |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | Not found |
| 409 | Already accepted, or nothing to withdraw |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | Not a test file on this connection |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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
}/connections/{id}/test-files/sendSends 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
bankKey | string | yes | The covered bankKey the file belongs to. The country, in the connection's own coverage model. |
scenario | string | yes | The test scenario id, as `GET /connections/{id}/test-files` reports it. |
account | object | yes | The 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. |
testServerConfirmed | boolean | yes | Confirms this connection points at the bank's test server, not production. Required; `false` or absent is refused with 422 test_server_not_confirmed. |
{
"companyId": "string",
"bankKey": "string",
"scenario": "string",
"account": {
"name": "string",
"iban": "string",
"other": {
"id": "string",
"scheme": "string"
},
"currency": "string",
"country": "string"
},
"testServerConfirmed": false
}| Status | Description |
|---|---|
| 201 | Accepted: the payment pipeline's own outcome |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | The connection is production. The test round is sandbox-only |
| 404 | Not found |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | Not a test file on this connection, or the test server was not confirmed |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
]
}
}/connections/{id}/test-files/fileThe 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
bankKey | string | yes | The covered bankKey the file belongs to. The country, in the connection's own coverage model. |
scenario | string | yes | The test scenario id, as `GET /connections/{id}/test-files` reports it. |
account | object | yes | The 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. |
testServerConfirmed | boolean | yes | Confirms this connection points at the bank's test server, not production. Required; `false` or absent is refused with 422 test_server_not_confirmed. |
{
"companyId": "string",
"bankKey": "string",
"scenario": "string",
"account": {
"name": "string",
"iban": "string",
"other": {
"id": "string",
"scheme": "string"
},
"currency": "string",
"country": "string"
},
"testServerConfirmed": false
}| Status | Description |
|---|---|
| 200 | The generated pain.001, its filename and the pain version |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | The connection is production. The test round is sandbox-only |
| 404 | Not found |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | Not a test file on this connection, or the test server was not confirmed |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"filename": "string",
"xml": "string",
"painVersion": "string"
}/connections/{id}/signing-certStores 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
cert | string | yes | The bank's published signing certificate. PEM (-----BEGIN CERTIFICATE-----) or base64-DER. |
{
"companyId": "string",
"cert": "string"
}| Status | Description |
|---|---|
| 200 | Pinned |
| 400 | Not a PEM certificate (`validation_failed`) |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"connectionId": "string",
"certSubject": "string",
"certExpiry": "string"
}/connections/{id}/generate-pgp| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | PGP key pair generated |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No such connection for this company (`connection_not_found`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/generate-abn-xmldsig-key| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Signing key generated |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No such connection for this company (`connection_not_found`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/bank-key| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
armoredKey | string | yes | ASCII-armored PGP public key block. |
{
"companyId": "string",
"armoredKey": "string"
}| Status | Description |
|---|---|
| 200 | Bank key saved |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/server-info| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
host | string | no | |
port | number | no | |
uploadPath | string | no | |
downloadPath | string | no | |
downloadHost | string | no | |
downloadHostFingerprint | string | no | |
filename | string | no | |
hostFingerprint | string | no | The 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. |
answers | object | no | Answers 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`. |
{
"companyId": "string",
"host": "string",
"port": 0,
"uploadPath": "string",
"downloadPath": "string",
"downloadHost": "string",
"downloadHostFingerprint": "string",
"filename": "string",
"hostFingerprint": "string",
"answers": {}
}| Status | Description |
|---|---|
| 200 | Server info saved |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/sftp-userSets 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
username | string | no | SFTP username assigned by the bank. The SSH key is generated with or without it. |
{
"companyId": "string",
"username": "string"
}| Status | Description |
|---|---|
| 200 | Username set + SSH key generated |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No such connection for this company (`connection_not_found`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/sftp-host-keysFor 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
hostFingerprint | string | no | The 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. |
downloadHostFingerprint | string | no | Split-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. |
{
"companyId": "string",
"hostFingerprint": "string",
"downloadHostFingerprint": "string"
}| Status | Description |
|---|---|
| 200 | Host key pinned |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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 |
{
"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"
}/connections/{id}/sftp-bank-keyFor 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
armoredKey | string | yes | The bank's new ASCII-armored PGP public key block. |
{
"companyId": "string",
"armoredKey": "string"
}| Status | Description |
|---|---|
| 200 | Bank key replaced |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/sftp-key-prepareGenerates 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
key | enum | yes | `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. |
{
"companyId": "string",
"key": "pgp"
}| Status | Description |
|---|---|
| 200 | New key pair prepared |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/sftp-key-switchPuts 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
key | enum | yes | `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. |
{
"companyId": "string",
"key": "pgp"
}| Status | Description |
|---|---|
| 200 | Switched to the new key pair |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/sftp-key-discardThrows 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
key | enum | yes | `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. |
{
"companyId": "string",
"key": "pgp"
}| Status | Description |
|---|---|
| 200 | Prepared key pair discarded |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/approversAssigns 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
userIds | string[] | yes | User IDs of company members with the Approver role. Must already exist in the company. Max 200. |
{
"companyId": "string",
"userIds": [
"string"
]
}| Status | Description |
|---|---|
| 200 | Approvers assigned |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No such connection for this company (`connection_not_found`). |
| 409 | Refused by approval governance with the code `POST /approvals/bank-rosters` gives it: `second_admin_required`, `policy_cosign_required`, `policy_change_in_flight` |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | One 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 |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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": []
}
]
}
}
}/connections/{id}/activateSwitches 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Connection activated |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/intro-email-sent| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
introEmailTo | string | no |
{
"companyId": "string",
"introEmailTo": "string"
}| Status | Description |
|---|---|
| 200 | Updated |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No such connection for this company (`connection_not_found`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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
}/connections/{id}/ws-environmentRequires 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
environment | string | no |
{
"companyId": "string",
"environment": "string"
}| Status | Description |
|---|---|
| 200 | Environment updated |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required, or the toggle is disabled on this server (development-only) |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/covered-banksFor a shared (group) connection. The store clamps the set to the bank's group and always includes the connection's own bank.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
coveredBankKeys | string[] | no | Bank keys this connection serves (clamped to the bank's group). |
{
"companyId": "string",
"coveredBankKeys": [
"string"
]
}| Status | Description |
|---|---|
| 200 | Covered banks updated |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/intro-email| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Rendered email (subject + body) |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 404 | Not found |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"email": {
"to": "string",
"subject": "string",
"body": "string"
}
}/connections/{id}/capability-sheetThe 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | PDF as base64, plus the fields the sheet could not state |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 404 | Connection not found |
| 409 | The bank agreement pins a pain.001 version this bank does not support |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"pdfBase64": "string",
"filename": "string",
"unknowns": [
"string"
],
"pages": 0
}/banks/{bankKey}/setup-infoReturns 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.
| Name | In | Required | Description |
|---|---|---|---|
bankKey BankKey | path | yes | |
companyId string | query | no | The 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 enum | query | no | Whether 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 enum | query | no | The 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. |
| Status | Description |
|---|---|
| 200 | Setup descriptor |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 404 | Unknown bank |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
}/banks/{bankKey}/sftp-namingFor 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.
| Name | In | Required | Description |
|---|---|---|---|
bankKey BankKey | path | yes | |
companyId string | query | no | The 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 string | query | no | SFTP account code |
orgNo string | query | no | 9-digit organisation number |
custId string | query | no | Customer identifier (CUSTID) |
| Status | Description |
|---|---|
| 200 | The test and production logins, folders and file names |
| 401 | Authentication 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. |
| 404 | Unknown bank, or a bank whose server, logins and file names are not derived |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
}/banks/{bankKey}/guide-feedbackSends 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.
| Name | In | Required | Description |
|---|---|---|---|
bankKey BankKey | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
message | string | yes | What was confusing, or what the bank did differently. |
{
"companyId": "string",
"message": "string"
}| Status | Description |
|---|---|
| 200 | Feedback sent |
| 400 | Empty or over-long message |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 404 | Unknown bank |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
| 502 | The feedback could not be mailed, retry |
{
"sent": false
}/banks/{bankKey}/guide-access-requestAsks 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.
| Name | In | Required | Description |
|---|---|---|---|
bankKey BankKey | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
note | string | no | Anything BankConnector should know, such as when the organisation plans to go live. |
{
"companyId": "string",
"note": "string"
}| Status | Description |
|---|---|
| 200 | A request is already pending; it is answered as it stands |
| 201 | Request made |
| 400 | Over-long note |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 404 | Unknown bank |
| 409 | The bank's guide is open to everyone, or the organisation already holds it |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"request": {
"id": "string",
"bankKey": "string",
"status": "pending",
"note": "string",
"requestedAt": "string",
"decidedAt": "string",
"message": "string"
}
}/banks/{bankKey}/setup-telemetrySetup-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.
| Name | In | Required | Description |
|---|---|---|---|
bankKey BankKey | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
event | enum | yes | |
channel | enum | yes | |
environment | enum | yes | |
turnId | string | yes | |
ms | integer | no |
{
"companyId": "string",
"event": "card-active",
"channel": "sftp",
"environment": "test",
"turnId": "string",
"ms": 0
}| Status | Description |
|---|---|
| 202 | Measurement accepted (recording is fire-and-forget) |
| 400 | Unknown event, malformed turn id, or a duration the event cannot carry |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 404 | Unknown bank |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"accepted": false
}/banks/{bankKey}/settings| Name | In | Required | Description |
|---|---|---|---|
bankKey BankKey | path | yes | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Bank settings (null if none saved) |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
}/banks/{bankKey}/settingsPayment-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.
| Name | In | Required | Description |
|---|---|---|---|
bankKey BankKey | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
agreementId | string | null | no | |
debtorAgreementId | string | null | no | |
chargeBearer | string | null | no | |
executionDateOffsetDays | integer | null | no | |
approvalPolicyId | string | null | no | |
painVersion | string | null | no | |
batchBooking | boolean | null | no | |
authorisationCode | string | null | no | |
authorisationProprietary | string | null | no | |
noApproverCodesEnabled | boolean | null | no | |
noApproverAuthVendor | string | null | no | |
noApproverAuthMethod | string | null | no | |
deriveHybridAddress | boolean | null | no | |
fillDebtorAddressFromRegisteredAddress | boolean | null | no | |
memberBankCode | string | null | no | |
selected | boolean | no | |
setupStep | string | null | no |
{
"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"
}| Status | Description |
|---|---|
| 200 | Settings saved |
| 202 | Settings saved, but the approval-policy re-bind needs a second Admin's co-sign |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required for payment-affecting fields |
| 404 | Unknown bank, or `approvalPolicyId` names no approval policy in this company |
| 409 | The 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 |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
}/bank-settings| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | All saved bank settings for this company |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
}
]
}/connections/{id}/registry-bank-keyChooses 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
use | boolean | yes | |
fingerprintPin | string | no |
{
"companyId": "string",
"use": false,
"fingerprintPin": "string"
}| Status | Description |
|---|---|
| 200 | Updated 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 |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/deactivateTakes 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Connection deactivated; updated connection and readiness |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/test-channelSFTP setup: records whether the bank runs a test channel apart from production. supported is required and must be a boolean. Admin only.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
supported | boolean | yes |
{
"companyId": "string",
"supported": false
}| Status | Description |
|---|---|
| 200 | Updated connection and readiness |
| 400 | `missing_fields` when `supported` is not a boolean |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No such connection for this company (`connection_not_found`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/testing-skippedSFTP 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
skipped | boolean | yes |
{
"companyId": "string",
"skipped": false
}| Status | Description |
|---|---|
| 200 | Updated connection and readiness |
| 400 | `missing_fields` when `skipped` is not a boolean |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No such connection for this company (`connection_not_found`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/demo-scenarioSets 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
demoOutcome | enum | no | |
demoDelaySeconds | integer | no | |
demoAuto | boolean | no | |
demoRejectReason | string | no |
{
"companyId": "string",
"demoOutcome": "accepted",
"demoDelaySeconds": 0,
"demoAuto": false,
"demoRejectReason": "string"
}| Status | Description |
|---|---|
| 200 | Updated connection and readiness |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required, or `demo_bank_disabled_in_production` on a production server |
| 404 | `connection_not_found`: no such connection |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/resume-sendsLifts 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | The connection, with sends no longer paused |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin 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 |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
]
}
}
}/connections/{id}/sftp-passwordStores 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
password | string | yes |
{
"companyId": "string",
"password": "string"
}| Status | Description |
|---|---|
| 200 | Password stored |
| 400 | `password_required` when `password` is empty |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"connectionId": "string",
"updated": false
}/connections/{id}/ws-bank-signing-certStores 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
cert | string | yes |
{
"companyId": "string",
"cert": "string"
}| Status | Description |
|---|---|
| 200 | Pinned |
| 400 | `cert_required` when `cert` is empty, `invalid_certificate` when it does not parse |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"connectionId": "string",
"certSubject": "string",
"certExpiry": "string"
}/connections/{id}/asic-signing-materialStores 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
cert | string | yes | |
key | string | yes |
{
"companyId": "string",
"cert": "string",
"key": "string"
}| Status | Description |
|---|---|
| 200 | Signing material stored |
| 400 | `material_required` when `cert` or `key` is missing, or a refusal that says what to fix |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No such connection for this company (`connection_not_found`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"connectionId": "string",
"updated": false
}/connections/{id}/abn-xml-signing-materialStores 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
key | string | yes | |
publicKey | string | yes | |
key2 | string | no | |
publicKey2 | string | no |
{
"companyId": "string",
"key": "string",
"publicKey": "string",
"key2": "string",
"publicKey2": "string"
}| Status | Description |
|---|---|
| 200 | Signing material stored |
| 400 | `material_required` when `key` or `publicKey` is missing, or a refusal that says what to fix |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No such connection for this company (`connection_not_found`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"connectionId": "string",
"updated": false
}/connections/{id}/detect-foldersRead-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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | One probe result per candidate folder, and the candidate list |
| 400 | `not_an_sftp_connection`: folder discovery is for SFTP connections |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin 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 |
| 413 | The 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 |
| 429 | Too 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 |
{
"probes": [
{
"path": "string",
"exists": false,
"fileCount": 0,
"newestModifiedAt": "string",
"error": "string",
"errorCode": 0
}
],
"candidates": [
"string"
]
}/connections/{id}/folder-healthRead-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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | The probe result for the download folder (`health`) |
| 400 | `not_an_sftp_connection`: the check is for SFTP connections |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin 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 |
| 413 | The 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 |
| 429 | Too 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 |
{
"health": {
"path": "string",
"exists": false,
"fileCount": 0,
"newestModifiedAt": "string",
"error": "string",
"errorCode": 0
}
}/connections/{id}/test-connectionSigns 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
host | string | no | |
port | number | no | |
username | string | no | |
uploadPath | string | no | |
downloadPath | string | no |
{
"companyId": "string",
"host": "string",
"port": 0,
"username": "string",
"uploadPath": "string",
"downloadPath": "string"
}| Status | Description |
|---|---|
| 200 | The overall result and one entry per check |
| 400 | `not_an_sftp_connection`: the check is for SFTP connections |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin 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 |
| 413 | The 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 |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"success": false,
"host": "string",
"port": 0,
"username": "string",
"checks": [
{
"check": "sign-in",
"status": "passed",
"reason": "string",
"path": "string",
"fileCount": 0
}
]
}/connections/{id}/ws-certificateOne 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
{
"companyId": "string",
"action": "string",
"family": "danske-ws"
}| Status | Description |
|---|---|
| 200 | Activated or renewed: the connection and its readiness. OP's activation also carries OP's service certificates. |
| 400 | The 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. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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. |
{
"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"
}
]
}/connections/{id}/ebics-params| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
url | string | no | EBICS server URL. |
hostId | string | no | Bank-assigned Host ID. |
partnerId | string | no | Customer ID (PartnerID) from the bank. |
userId | string | no | Subscriber ID (UserID) from the bank. |
protocolVersion | enum | no | |
signatureVersion | enum | no | The 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. |
subscriberMode | enum | no | Deprecated: 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. |
veuOnly | boolean | no | Per-user only: this agreement routes every order through VEU (refuses multi-signature uploads), delivery uploads one ES and adds the rest via HVE. |
uploaderUserId | string | no | Per-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. |
signatureProfile | enum | no | Deprecated: 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. |
keyManagement | enum | no | Which 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. |
authorisationMode | enum | no | WHERE 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. |
{
"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"
}| Status | Description |
|---|---|
| 200 | EBICS params saved |
| 400 | `validation_failed` when the change asks for an arrangement the bank does not offer; the message says why |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/ebics-generate-keys| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
subscriberMode | enum | no |
{
"companyId": "string",
"subscriberMode": "technical"
}| Status | Description |
|---|---|
| 200 | Keys generated |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/ebics-fetch-htdRuns 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Discovery result (fetched flag, message, and the parsed agreement data when available) |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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. |
{
"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": []
}
]
}
}
}/connections/{id}/ebics-renewSends 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
userId | string | no | Per-user mode: the approver whose subscriber to rotate. |
{
"companyId": "string",
"userId": "string"
}| Status | Description |
|---|---|
| 200 | Renewal outcome (renewed | ambiguous | resolved-kept-old | resolved-promoted | unresolved) |
| 400 | `validation_failed`: a renewal on a per-user agreement names no approver |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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. |
{
"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"
}
}/connections/{id}/ebics-veu-pendingRead-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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Pending orders (veuPending array on the connection response) |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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. |
{
"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
}
]
}/connections/{id}/ebics-suspendSends 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
userIds | string[] | no | Per-user mode: the approvers to suspend. Nobody else is suspended. |
userId | string | no | Per-user mode: one approver to suspend (added to `userIds`). |
{
"companyId": "string",
"userIds": [
"string"
],
"userId": "string"
}| Status | Description |
|---|---|
| 200 | Suspend 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 |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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. |
{
"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"
}
]
}
}/connections/{id}/ebics-veu-completeRe-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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
documentId | string | no | The sent payment (its frozen pain.001 is signed). |
orderId | string | no | The bank order number to select the pending order. |
orderDigest | string | no | The pending order's dataDigest, to resolve the payment. |
{
"companyId": "string",
"documentId": "string",
"orderId": "string",
"orderDigest": "string"
}| Status | Description |
|---|---|
| 200 | Co-sign results (per approver) + executionReady |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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. |
{
"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
}
}/connections/{id}/ebics-letterReturns 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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 string | query | no | An 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 enum | query | no | `ini` or `hia` returns that one letter; omit it for both. Any other value is ignored. |
| Status | Description |
|---|---|
| 200 | PDF as base64 |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 404 | 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`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"pdfBase64": "string",
"filename": "string"
}/connections/{id}/ebics-generate-user-keysPer-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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
userId | string | yes | |
ebicsUserId | string | yes |
{
"companyId": "string",
"userId": "string",
"ebicsUserId": "string"
}| Status | Description |
|---|---|
| 200 | Updated 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 |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/ebics-subscriber-statePer-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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
userId | string | yes | |
state | string | yes |
{
"companyId": "string",
"userId": "string",
"state": "string"
}| Status | Description |
|---|---|
| 200 | Updated connection and readiness |
| 400 | `missing_fields` when `userId` is missing or `state` is not `ini-hia-sent` or `active` |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/ebics-letters-postedMoves 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Updated connection and readiness |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/ebics-fingerprints-confirmedRecords 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Updated connection and readiness |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/ebics-authorisation-confirmedSettles 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
authorisationMode | enum | no | |
reapproveDocumentIds | string[] | no |
{
"companyId": "string",
"authorisationMode": "outside-ebics",
"reapproveDocumentIds": [
"string"
]
}| Status | Description |
|---|---|
| 200 | Updated 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 |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/connections/{id}/ebics-hevA 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Connection and readiness, with the bank's answer under `hev` |
| 400 | `validation_failed`: the connection's EBICS address is refused (for example, not https) |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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. |
{
"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"
}
]
}
}/connections/{id}/ebics-hev-probeThe 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
force | boolean | no | Ask the bank again even when an answer for the same URL and Host ID is under ten minutes old. |
{
"companyId": "string",
"force": false
}| Status | Description |
|---|---|
| 200 | Connection and readiness, with the result under `hevProbe` |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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
}
}/connections/{id}/ebics-send-iniLive 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
userId | string | no |
{
"companyId": "string",
"userId": "string"
}| Status | Description |
|---|---|
| 200 | Connection and readiness, with the bank's answers under `ini`, `hia`, `keyHashes` and `subscribers` |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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. |
{
"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"
}/connections/{id}/ebics-fetch-hpbLive 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
userId | string | no |
{
"companyId": "string",
"userId": "string"
}| Status | Description |
|---|---|
| 200 | Connection and readiness, with the outcome under `hpb` |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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. |
{
"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"
]
}
}/connections/{id}/ebics-fetch-hacLive 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Connection and readiness, with the acknowledgements under `hac` |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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. |
{
"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"
}
]
}
}/connections/{id}/ebics-refetch-hpbLive 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
acceptBankKeys | object | no |
{
"companyId": "string",
"acceptBankKeys": {
"authentication": "string",
"encryption": "string"
}
}| Status | Description |
|---|---|
| 200 | Connection and readiness, with the outcome under `refetch` |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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. |
{
"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"
}
}/connections/{id}/ebics-reinitialiseLive 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
userId | string | no |
{
"companyId": "string",
"userId": "string"
}| Status | Description |
|---|---|
| 200 | Connection 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 |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | 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`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too 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. |
{
"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"
}
}/connections/{id}/ebics-subscribersEach 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The enrolled subscribers |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"subscribers": [
{
"userId": "string",
"ebicsUserId": "string",
"state": "keys-generated",
"signatureVersion": "A005",
"modulusLength": 0
}
]
}Approvals
Maker-checker approval policies + the pending-approval queue (session, Admin/Approver)
/approvals/pendingFor 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 enum | query | no | `pending` (the default) is the queue described above; `approved` or `rejected` is the company's decided trail. |
cursor string | query | no | The previous page's `nextCursor`: the page continues after that request. |
after string | query | no | Deprecated alias of `cursor`; `cursor` wins when both are sent. |
limit integer | query | no | Page size, at most 500. |
| Status | Description |
|---|---|
| 200 | Pending approval requests |
| 400 | A `status` or `limit` that is not valid (`invalid_parameter`), or a malformed `cursor` (`invalid_cursor`). |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/approvals/oversightThe 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 string | query | no | The previous page's `nextCursor`: the page continues after that request. |
after string | query | no | Deprecated alias of `cursor`; `cursor` wins when both are sent. |
limit integer | query | no | Page size, at most 500. |
| Status | Description |
|---|---|
| 200 | Every pending approval request in the company. The standard { items, nextCursor } envelope |
| 400 | A `limit` that is not valid (`invalid_parameter`), or a malformed `cursor` (`invalid_cursor`). |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/approvals/{id}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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The request |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 404 | No such request in this organisation (or not one that names this ERP sign-in) |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
}/approvals/{id}/approveAn 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
reason | string | no | |
code | string | no | 2FA TOTP code (if step-up required). |
backupCode | string | no | |
contentDigest | string | no | ERP add-on only (required there): the `contentDigest` GET /approvals/{id} returned. A mismatch is 409 `content_changed`. |
{
"companyId": "string",
"reason": "string",
"code": "string",
"backupCode": "string",
"contentDigest": "string"
}| Status | Description |
|---|---|
| 200 | Approval recorded (and payment dispatched if fully approved) |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`), and so is a signed-in user without the Approver role. |
| 404 | No approval request with this id (`not_found`) |
| 409 | The 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) |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | Step-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). |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
| 500 | The decision could not be recorded (`internal_error`) |
{
"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"
}/approvals/{id}/rejectA 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
reason | string | no | |
code | string | no | |
backupCode | string | no | |
contentDigest | string | no |
{
"companyId": "string",
"reason": "string",
"code": "string",
"backupCode": "string",
"contentDigest": "string"
}| Status | Description |
|---|---|
| 200 | Rejection recorded |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`), and so is a signed-in user without the Approver role. |
| 404 | No approval request with this id (`not_found`) |
| 409 | The 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` |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
| 500 | The decision could not be recorded (`internal_error`) |
{
"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"
}/approvals/policies| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Policies: the standard { items } envelope, one row per policy |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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
}
]
}/approvals/policiesDefines required approver count + amount thresholds. Admin only.
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
id | string | no | |
name | string | no | |
template | string | no | |
approvers | string[] | no | |
isDefault | boolean | no | |
enabled | boolean | no | |
requiredApprovals | number | no | |
allowSelfApproval | boolean | no | |
approverLimits | object | no | |
perTransactionLimit | string | null | no | |
perJournalLimit | string | null | no | |
perTransactionMax | string | null | no | |
requireOneFromEachGroup | boolean | no | |
orderedApproval | boolean | no | |
groups | object[] | no | |
locked | boolean | no | |
lockedAt | string | no | |
lockedBy | string | no |
{
"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"
}| Status | Description |
|---|---|
| 201 | Policy created |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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
}/approvals/policies/{id}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).
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
id | string | no | |
name | string | no | |
template | string | no | |
approvers | string[] | no | |
isDefault | boolean | no | |
enabled | boolean | no | |
requiredApprovals | number | no | |
allowSelfApproval | boolean | no | |
approverLimits | object | no | |
perTransactionLimit | string | null | no | |
perJournalLimit | string | null | no | |
perTransactionMax | string | null | no | |
requireOneFromEachGroup | boolean | no | |
orderedApproval | boolean | no | |
groups | object[] | no | |
locked | boolean | no | |
lockedAt | string | no | |
lockedBy | string | no |
{
"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"
}| Status | Description |
|---|---|
| 200 | Saved and IN FORCE now, or nothing to change (`unchanged: true`) |
| 202 | Accepted: not in force; `change` is the request a second Admin must co-sign |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 409 | A change to this policy is already awaiting co-sign / conflict |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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
}/approvals/policies/{id}/lockLocks 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}).
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
id | string | no | |
name | string | no | |
template | string | no | |
approvers | string[] | no | |
isDefault | boolean | no | |
enabled | boolean | no | |
requiredApprovals | number | no | |
allowSelfApproval | boolean | no | |
approverLimits | object | no | |
perTransactionLimit | string | null | no | |
perJournalLimit | string | null | no | |
perTransactionMax | string | null | no | |
requireOneFromEachGroup | boolean | no | |
orderedApproval | boolean | no | |
groups | object[] | no | |
locked | boolean | no | |
lockedAt | string | no | |
lockedBy | string | no |
{
"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"
}| Status | Description |
|---|---|
| 200 | Policy activated |
| 202 | Accepted: not active; `change` is the request a second Admin must co-sign |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 409 | Quorum not met / conflict |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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
}/approvals/bank-rostersOne 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 string | query | yes | Comma-separated covered bank keys (repeatable). |
| Status | Description |
|---|---|
| 200 | One roster row per covered bank |
| 400 | No bank keys named |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"bankKey": "string",
"policyId": "string",
"policyName": "string",
"builtIn": false,
"bound": false,
"approverUserIds": [
"string"
],
"requiredApprovals": 0,
"sharedWith": [
"string"
]
}
]
}/approvals/bank-rostersAll 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.
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
targets | object[] | yes |
{
"companyId": "string",
"targets": [
{
"bankKey": "string",
"approverUserIds": [
"string"
]
}
]
}| Status | Description |
|---|---|
| 200 | In force now |
| 202 | Accepted: not in force; awaiting a second Admin's co-sign |
| 400 | Malformed roster set |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 409 | Refused: the change would weaken approval (e.g. only one Admin), or a change is already awaiting co-sign |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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
}/approvals/changesThe dual-co-sign change requests for the company. ?status=pending (default) | activated | cancelled.
| Name | In | Required | Description |
|---|---|---|---|
status enum | query | no | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Change requests: the standard { items } envelope |
| 400 | A `status` that is not valid (`invalid_parameter`). |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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": [
{}
]
}
}
]
}/approvals/changes/{changeId}/{action}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).
| Name | In | Required | Description |
|---|---|---|---|
changeId string | path | yes | |
action enum | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Change updated: one shape per outcome; `change` is always present |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 409 | Same-admin co-sign / conflict |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
]
}/approvals/policyThe 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The active policy (`policy`) |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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
}
}/approvals/policies/{id}/defaultSets 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).
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
id | string | no | |
name | string | no | |
template | string | no | |
approvers | string[] | no | |
isDefault | boolean | no | |
enabled | boolean | no | |
requiredApprovals | number | no | |
allowSelfApproval | boolean | no | |
approverLimits | object | no | |
perTransactionLimit | string | null | no | |
perJournalLimit | string | null | no | |
perTransactionMax | string | null | no | |
requireOneFromEachGroup | boolean | no | |
orderedApproval | boolean | no | |
groups | object[] | no | |
locked | boolean | no | |
lockedAt | string | no | |
lockedBy | string | no |
{
"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"
}| Status | Description |
|---|---|
| 200 | The policy is the default now (`pending: false`) |
| 202 | Accepted, not in force: `change` is the request a second Admin must co-sign |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin 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 |
| 409 | A change to this policy is already awaiting co-sign, or the policy cannot be the default |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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.
/oauth/userinfoAn 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.
| Status | Description |
|---|---|
| 200 | The token's person or install. |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Not an OAuth access token, or (a person's sign-in) the organisation does not allow approving in the ERP (`erp_approval_unavailable`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
}/oauth/tokenRFC 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).
| Status | Description |
|---|---|
| 200 | The 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. |
| 400 | RFC 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. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 429 | Over the per-IP or per-client throttle. `Retry-After` is set. |
{
"access_token": "string",
"token_type": "string",
"expires_in": 0,
"refresh_token": "string",
"scope": "string"
}/oauth/authorizeThe 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.
| Name | In | Required | Description |
|---|---|---|---|
response_type enum | query | yes | Always `code`. |
client_id string | query | yes | The application's registered client id. |
redirect_uri string | query | yes | A 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 string | query | yes | The scopes requested, space-delimited. |
state string | query | no | Returned unchanged on the redirect. |
code_challenge string | query | yes | The PKCE code challenge. |
code_challenge_method enum | query | yes | Always `S256`. |
erp_company_id string | query | no | Optional, 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. |
| Status | Description |
|---|---|
| 200 | The validated request, or a redirectable refusal. |
| 400 | Unknown client, or a redirect_uri the client did not register. |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
]
}/oauth/authorize/decisionThe 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.
| Property | Type | Required | Description |
|---|---|---|---|
clientId | string | yes | |
redirectUri | string | yes | |
scope | string | yes | |
state | string | no | |
codeChallenge | string | yes | |
codeChallengeMethod | string | yes | |
erpCompanyId | string | no | |
approve | boolean | yes | |
twofaCode | string | no | |
backupCode | string | no |
{
"clientId": "string",
"redirectUri": "string",
"scope": "string",
"state": "string",
"codeChallenge": "string",
"codeChallengeMethod": "string",
"erpCompanyId": "string",
"approve": false,
"twofaCode": "string",
"backupCode": "string"
}| Status | Description |
|---|---|
| 200 | Where to send the browser next. |
| 400 | Validation failed (unknown client, unmatched redirect, bad PKCE parameters). |
| 401 | Sign in required: there is no valid session. |
| 403 | Not an Admin session, or no company context selected. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"redirectTo": "string"
}/oauth/authorize/identity-decisionThe 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.
| Property | Type | Required | Description |
|---|---|---|---|
clientId | string | yes | |
redirectUri | string | yes | |
scope | string | yes | |
state | string | no | |
codeChallenge | string | yes | |
codeChallengeMethod | string | yes | |
erpCompanyId | string | no | |
approve | boolean | yes | |
twofaCode | string | no | |
backupCode | string | no |
{
"clientId": "string",
"redirectUri": "string",
"scope": "string",
"state": "string",
"codeChallenge": "string",
"codeChallengeMethod": "string",
"erpCompanyId": "string",
"approve": false,
"twofaCode": "string",
"backupCode": "string"
}| Status | Description |
|---|---|
| 200 | Where to send the browser next. |
| 400 | Validation failed, or the request is for an application install (with or without identity scopes beside it). |
| 401 | Sign in required: there is no valid session. |
| 403 | Not 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. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | Two-factor authentication is not set up, or the code is missing or wrong. |
| 429 | Too many wrong codes, locked out for a while. |
{
"redirectTo": "string"
}/oauth/revokePublic, 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.
| Status | Description |
|---|---|
| 200 | The token has been revoked, or was already invalid. RFC 7009 does not distinguish. |
| 400 | Malformed request: `token` or `client_id` missing. |
| 401 | `invalid_client`: a confidential client's secret is missing or wrong. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
/.well-known/oauth-authorization-serverThe 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).
| Status | Description |
|---|---|
| 200 | The metadata document. |
| 503 | This server has no configured public origin, so it cannot name itself. |
{
"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.
/auth/loginPUBLIC. 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.
| Property | Type | Required | Description |
|---|---|---|---|
email | string | yes | |
password | string | yes |
{
"email": "string",
"password": "string"
}| Status | Description |
|---|---|
| 200 | Logged in (session cookie set) or a 2FA step-up challenge |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Invalid credentials |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}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()/2fa/setupGenerates 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.
| Status | Description |
|---|---|
| 200 | Pending secret + otpauth URI |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 409 | Already enrolled (`conflict`). Disable 2FA first, then set it up again. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"secret": "string",
"otpauthUri": "string",
"issuer": "string"
}/2fa/confirmRe-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.
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no | |
code | string | yes | 6-digit TOTP code |
backupCode | string | no | |
password | string | yes | The caller's current password (re-authentication). |
{
"companyId": "string",
"code": "string",
"backupCode": "string",
"password": "string"
}| Status | Description |
|---|---|
| 200 | Enabled + one-time backup codes |
| 400 | `setup_required`: no pending secret, call POST /2fa/setup first; or a body that is not JSON (`validation_failed`) |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 409 | Already enabled |
| 413 | The 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 |
| 429 | Too 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. |
{
"enabled": false,
"backupCodes": [
"string"
],
"csrfToken": "string"
}/2fa/disableTurns 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).
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no | |
code | string | no | |
backupCode | string | no | |
password | string | yes | The caller's current password (re-authentication). |
{
"companyId": "string",
"code": "string",
"backupCode": "string",
"password": "string"
}| Status | Description |
|---|---|
| 200 | Disabled |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Company requires 2FA |
| 409 | Not enabled |
| 413 | The 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 |
| 429 | Too 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. |
{
"enabled": false
}/company/require-2faAdmin-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).
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no | |
enabled | boolean | yes |
{
"companyId": "string",
"enabled": false
}| Status | Description |
|---|---|
| 200 | Updated company policy |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"require2fa": false
}/company/registration-numberSystem-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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | yes | The 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. |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no | |
registrationNumber | string | null | yes |
{
"companyId": "string",
"registrationNumber": "string"
}| Status | Description |
|---|---|
| 200 | The company's registration number after the write |
| 400 | Nothing to update, a value longer than the bound, or companyId missing |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | System admin required |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"registrationNumber": "string"
}/company/registration-numberAn 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
registrationNumber | string | yes | The corrected number: CVR, organisasjonsnummer, organisationsnummer or equivalent. |
{
"registrationNumber": "string"
}| Status | Description |
|---|---|
| 200 | The company's registration number after the write |
| 400 | The body is not valid |
| 401 | Sign in required: there is no valid session. |
| 403 | Not 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 |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | No number, or a Danish, Norwegian or Swedish number whose check digit is wrong (`details.field: registrationNumber`) |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"registrationNumber": "string"
}/auth/me| Status | Description |
|---|---|
| 200 | The signed-in user + roles + company |
| 401 | No session, or the session's company no longer exists |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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",
"features": [
"string"
]
},
"session": {
"idleMinutes": 0,
"maxMinutes": 0,
"maxRemainingSeconds": 0
}
}/me/organisationsThe 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.
| Name | In | Required | Description |
|---|---|---|---|
limit integer | query | no | Page size. |
cursor string | query | no | The previous page's `nextCursor`, opaque. A malformed one is 400 `invalid_cursor`; any other answers only organisations the caller holds a live grant on. |
| Status | Description |
|---|---|
| 200 | The organisations this identity administers, newest first. |
| 400 | A `limit` that is not a number (`invalid_parameter`), or a malformed `cursor` (`invalid_cursor`). |
| 401 | Sign in required: there is no valid session. |
| 403 | Not an identity that can hold a grant (an API key, an install, or dev open mode). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"id": "string",
"name": "string",
"createdAt": "string",
"accessLevel": "admin",
"expiresAt": "string",
"userCount": 0,
"bankConnectionCount": 0
}
],
"nextCursor": "string"
}/auth/2fa/setupPUBLIC, 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.
| Property | Type | Required | Description |
|---|---|---|---|
twofaToken | string | no | The challenge token from POST /auth/login. |
{
"twofaToken": "string"
}| Status | Description |
|---|---|
| 200 | Pending secret + otpauth URI |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | The sign-in challenge expired. Sign in again. |
| 409 | Already enrolled, or the token is a step-up challenge rather than an enrollment one. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many attempts from this IP (Retry-After) |
{
"secret": "string",
"otpauthUri": "string",
"issuer": "string"
}/me/sessionsEvery 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.
| Status | Description |
|---|---|
| 200 | The caller's own sessions. |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"id": "string",
"current": false,
"createdAt": 0,
"expiresAt": 0,
"deviceLabel": "string",
"lastSeenAt": 0
}
],
"nextCursor": "string",
"total": 0
}/me/sessionsRevokes 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).
| Property | Type | Required | Description |
|---|---|---|---|
password | string | no | The caller's current password, when no second factor applies to them. |
code | string | no | A current 2FA TOTP code, when the caller has 2FA. |
backupCode | string | no | A 2FA backup code, in place of `code`. |
{
"password": "string",
"code": "string",
"backupCode": "string"
}| Status | Description |
|---|---|
| 200 | How many other sessions were revoked. |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | Re-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 |
| 429 | Too many requests from this network, or too many wrong codes or passwords (`rate_limited`); wait `Retry-After` seconds. |
{
"revoked": 0
}/me/sessions/{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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | The session's opaque id, as listed by GET /me/sessions. |
| Property | Type | Required | Description |
|---|---|---|---|
password | string | no | The caller's current password, when no second factor applies to them. |
code | string | no | A current 2FA TOTP code, when the caller has 2FA. |
backupCode | string | no | A 2FA backup code, in place of `code`. |
{
"password": "string",
"code": "string",
"backupCode": "string"
}| Status | Description |
|---|---|
| 200 | Revoked. |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 404 | No such active session. It may already have ended. Answered before any code or password is checked. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | Re-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 |
| 429 | Too many requests from this network, or too many wrong codes or passwords (`rate_limited`); wait `Retry-After` seconds. |
{
"revoked": false,
"current": false
}/me/erp-grantsThe 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.
| Status | Description |
|---|---|
| 200 | The caller's live sign-ins |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"grantId": "string",
"application": "string",
"scopes": [
"string"
],
"createdAt": "string",
"expiresAt": "string"
}
]
}/me/erp-grants/{grantId}/revokeEnds 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.
| Name | In | Required | Description |
|---|---|---|---|
grantId string | path | yes | The sign-in's id, as listed by GET /me/erp-grants. |
| Status | Description |
|---|---|
| 200 | Ended |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 404 | No live ERP add-on sign-in with that id is the caller's |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"revoked": false
}/me/passwordRequires 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).
| Property | Type | Required | Description |
|---|---|---|---|
currentPassword | string | yes | |
newPassword | string | yes | |
twofaCode | string | no | Required when the caller has 2FA enabled. |
backupCode | string | no | A one-time backup code, in place of twofaCode. |
{
"currentPassword": "string",
"newPassword": "string",
"twofaCode": "string",
"backupCode": "string"
}| Status | Description |
|---|---|
| 200 | Password changed. |
| 400 | Missing fields, or the new password fails the strength/breached-password policy. |
| 401 | Sign in first, or the current password is incorrect. |
| 403 | A system-admin session: the system console manages its own credentials. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | A valid two-factor code is required. |
| 429 | Too many attempts from this IP (Retry-After) |
{
"ok": false,
"revokedOtherSessions": 0,
"csrfToken": "string"
}/me/marketing-consentWhether the caller has opted in to marketing email, when, and through which form (the signup box or this setting). Session only; a system-admin or workspace-admin session is refused (403).
| Status | Description |
|---|---|
| 200 | The stored consent. |
| 401 | Sign in required: there is no valid session. |
| 403 | A system-admin or workspace-admin session. |
| 404 | The caller's account is not in this organisation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"subscribed": false,
"consentedAt": "string",
"source": "signup",
"withdrawnAt": "string"
}/me/marketing-consentRecords the caller's own choice (source: settings). Opting in keeps the original consent's time and form when one is already on record; opting out clears it at once and records when. When the Brevo integration is configured, the choice is queued for sync to the marketing list in the same transaction. Session only; a system-admin or workspace-admin session is refused (403).
| Property | Type | Required | Description |
|---|---|---|---|
subscribed | boolean | yes | true = opt in, false = opt out. |
{
"subscribed": false
}| Status | Description |
|---|---|
| 200 | The consent as stored after the change. |
| 400 | The body is not valid, or `subscribed` is missing. |
| 401 | Sign in required: there is no valid session. |
| 403 | A system-admin or workspace-admin session. |
| 404 | The caller's account is not in this organisation. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"subscribed": false,
"consentedAt": "string",
"source": "signup",
"withdrawnAt": "string"
}/auth/logout| Status | Description |
|---|---|
| 200 | Logged out |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"ok": false
}/auth/areaFor 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.
| Property | Type | Required | Description |
|---|---|---|---|
area | enum | yes |
{
"area": "partner"
}| Status | Description |
|---|---|
| 200 | The session sits in the place asked for |
| 400 | `area` is missing or not one of the two |
| 401 | Sign in required: there is no valid session. |
| 403 | Not a person who is both a partner and a member of their own organisation |
| 409 | The session is already there |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"ok": false,
"area": "partner",
"csrfToken": "string"
}/auth/password-resetPUBLIC: 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.
| Status | Description |
|---|---|
| 200 | Reset-link availability |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"available": false
}/auth/password-resetPUBLIC. 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.
| Property | Type | Required | Description |
|---|---|---|---|
email | string | yes | The address to send the reset link to, if an account exists. |
{
"email": "string"
}| Status | Description |
|---|---|
| 202 | Accepted: the neutral answer, identical for every address |
| 400 | Malformed body, or not an email address |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
| 503 | Password reset is unavailable on this instance (no email transport) |
{
"message": "string"
}/auth/password-reset/confirmPUBLIC. 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.
| Property | Type | Required | Description |
|---|---|---|---|
token | string | yes | The one-time token from the reset email link. |
password | string | yes | The new password. |
{
"token": "string",
"password": "string"
}| Status | Description |
|---|---|
| 200 | Password reset |
| 400 | Invalid, expired or already-used link, or a password the policy refuses |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many attempts: IP rate-limited |
{
"ok": false,
"email": "string"
}/auth/2fa-reset/confirmPUBLIC. 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.
| Property | Type | Required | Description |
|---|---|---|---|
token | string | yes | The one-time token from the confirmation email's link. |
{
"token": "string"
}| Status | Description |
|---|---|
| 200 | Two-factor authentication reset |
| 400 | Missing token, or an invalid, expired, already-used or superseded link |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many attempts: IP rate-limited |
{
"reset": false,
"email": "string"
}/auth/signupPUBLIC: 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.
| Status | Description |
|---|---|
| 200 | Signup availability |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"available": false
}/auth/2faPUBLIC. 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.
| Property | Type | Required | Description |
|---|---|---|---|
twofaToken | string | yes | The `twofaToken` or `stepUpToken` returned by POST /auth/login. |
code | string | no | TOTP code: the proof a `twofaToken` demands. |
backupCode | string | no | |
solution | string | no | Proof-of-work solution: the proof a `stepUpToken` demands. Any string for which sha256("<stepUpToken>.<solution>") begins with the response's `proofOfWork.bits` zero bits. |
{
"twofaToken": "string",
"code": "string",
"backupCode": "string",
"solution": "string"
}| Status | Description |
|---|---|
| 200 | Session granted (session cookie set) |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | The 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. |
| 413 | The 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). |
| 429 | Too many failed attempts for this user or from this network (`rate_limited`). Try again later. |
{
"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"
]
}/approver-identityWhether 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.
| Status | Description |
|---|---|
| 200 | The caller's own approver-identity enrolment (masked). |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"enrolled": false,
"ssnFirst6": "string",
"districtUserId": "string",
"enrolledAt": "string",
"banksRequiringId": [
"string"
],
"banksAcceptingDistrictUserId": [
"string"
]
}/approver-identityAccepts 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).
| Property | Type | Required | Description |
|---|---|---|---|
ssn | string | null | no | The Norwegian national ID (fødselsnummer), cleartext, once. `null` removes it. |
districtUserId | string | null | no | The 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. |
{
"ssn": "string",
"districtUserId": "string"
}| Status | Description |
|---|---|
| 200 | The caller's own approver-identity enrolment (masked). |
| 400 | Neither 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`). |
| 401 | Sign in required: there is no valid session. |
| 403 | Attempted to write an identity that is not the caller's own. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | From `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`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"enrolled": false,
"ssnFirst6": "string",
"districtUserId": "string",
"enrolledAt": "string",
"banksRequiringId": [
"string"
],
"banksAcceptingDistrictUserId": [
"string"
]
}/approver-identityDeletes the caller's own enrolled identity. Idempotent: always answers enrolled: false.
| Status | Description |
|---|---|
| 200 | The caller's own approver-identity enrolment (masked). |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"enrolled": false,
"ssnFirst6": "string",
"districtUserId": "string",
"enrolledAt": "string",
"banksRequiringId": [
"string"
],
"banksAcceptingDistrictUserId": [
"string"
]
}User Management
Create, invite, and manage users within a company.
/usersReturns all users in the company (name, email, roles, status). Readable by any authenticated company member.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Company users |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
]
}
]
}/usersCompany 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.
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
email | string | yes | |
name | string | yes | |
roles | string[] | yes | |
code | string | no | The acting admin's 2FA TOTP code (when step-up applies; an `admin` or `approver` role). |
backupCode | string | no | A 2FA backup code, in place of `code`. |
{
"companyId": "string",
"email": "approver@acme.com",
"name": "Bob Approver",
"roles": [
"approver"
],
"code": "string",
"backupCode": "string"
}| Status | Description |
|---|---|
| 201 | User invited |
| 400 | Invalid request (`bad_request`), or no valid roles (`invalid_roles`) |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Company admin required; or an API key or a system admin creating an `admin` or `approver` |
| 409 | The email address is already registered (`conflict`) |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | Step-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) |
| 429 | Too many wrong 2FA codes (`rate_limited`); see `Retry-After` |
| 503 | An invite with no email transport to deliver it (`invites_unavailable`), refused before the code is checked so a single-use code is not spent |
{
"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"
}/users/{id}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
adminrole receive the whole record:settings,companyIdandcreatedAtincluded. - Any other signed-in company member receives the narrower roster projection (
id,email,name,roles,status,totpEnabledAt). The same six fieldsGET /userspublishes. 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The 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. |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 404 | Unknown user in this company |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/auth/set-passwordPUBLIC. 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.
| Property | Type | Required | Description |
|---|---|---|---|
token | string | yes | The one-time invite token from the email link. |
password | string | yes | The user's chosen password. |
{
"token": "string",
"password": "string"
}| Status | Description |
|---|---|
| 200 | Password set |
| 400 | Invalid or expired token |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many attempts: IP rate-limited |
{
"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
/dashboard/kpisCounts 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 string | query | yes | The calendar day to window on, as YYYY-MM-DD. A value carrying a time is rejected. |
timezone string | query | no | IANA zone the day is resolved in, e.g. Europe/Copenhagen. Defaults to UTC. |
| Status | Description |
|---|---|
| 200 | KPI aggregate for the requested day |
| 400 | Missing or malformed `day`, or an unknown `timezone` |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"day": "string",
"timezone": "string",
"yesterdayCount": 0,
"pendingCount": 0,
"execCount": 0,
"execCountByCurrency": {},
"rejectedOpenCount": 0,
"todayByStatus": [
{
"status": "string",
"currency": "string",
"count": 0,
"bankKeys": [
"string"
]
}
],
"execMoney": {},
"awaitMoney": {}
}/client-errorsThe 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.
| Property | Type | Required | Description |
|---|---|---|---|
island | string | no | Screen label, e.g. "approvals-queue". |
route | string | no | Route in view. Query string is dropped by client and server. |
message | string | no | |
stack | string | no | |
componentStack | string | no | Component stack. |
userAgent | string | no |
{
"island": "string",
"route": "string",
"message": "string",
"stack": "string",
"componentStack": "string",
"userAgent": "string"
}| Status | Description |
|---|---|
| 202 | Accepted. `recorded` distinguishes stored from dropped (capture off, no session, empty). |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"ok": false,
"recorded": false,
"capture": false
}/client-absenceErrors 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.
| Property | Type | Required | Description |
|---|---|---|---|
kind | string | no | Which 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. |
route | string | no | A route template of the browser app, e.g. `/app/approvals` or `/app/policy/edit/$id`: never a concrete URL, never a query string. |
{
"kind": "string",
"route": "string"
}| Status | Description |
|---|---|
| 202 | Accepted. `recorded` distinguishes counted from dropped (unknown route/kind, oversized, throttled). |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"ok": false,
"recorded": false
}/setup-lessonsAvailable 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.
| Property | Type | Required | Description |
|---|---|---|---|
wizard | enum | yes | Which setup wizard filed it. |
step | string | no | The wizard's own step key in view when filed, if any. |
bankKey | string | no | The bank being set up, when the wizard had resolved one. |
note | string | yes | The free-typed lesson: what the bank asked for. |
{
"wizard": "sftp",
"step": "string",
"bankKey": "string",
"note": "string"
}| Status | Description |
|---|---|
| 201 | Recorded. |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"ok": false,
"id": "string",
"createdAt": "string"
}/bank-coverage-requests| Name | In | Required | Description |
|---|---|---|---|
status enum | query | no | Narrow the list to one lifecycle state. The tenant scope is unaffected. |
limit integer | query | no | |
cursor string | query | no |
| Status | Description |
|---|---|
| 200 | All bank coverage requests |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/bank-coverage-requestsAny 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.
| Property | Type | Required | Description |
|---|---|---|---|
query | string | yes | BIC code or bank name. |
email | object | no |
{
"query": "string",
"email": "string"
}| Status | Description |
|---|---|
| 201 | Request recorded |
| 400 | Empty query |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"ok": false,
"request": {
"id": "string",
"query": "string",
"createdAt": "string"
}
}/bank-coverage-requests/demandThe 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.
| Name | In | Required | Description |
|---|---|---|---|
limit integer | query | no |
| Status | Description |
|---|---|
| 200 | Demand per bank, most-wanted first |
| 401 | Sign in required: there is no valid session. |
| 403 | System operator only |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}
]
}/bank-coverage-requests/{id}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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
status | enum | yes | |
note | string | no | Internal operator note. Never sent to the requester. |
bankKey | string | no | Registry bank key, `<slug>-<cc>`. |
notify | boolean | no | Tell the requester their bank shipped. |
{
"status": "open",
"note": "string",
"bankKey": "string",
"notify": false
}| Status | Description |
|---|---|
| 200 | Updated request; `notified` says whether a message actually went out |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | System operator only |
| 404 | No such request, or an unknown bankKey |
| 409 | Refused: not notifiable in this state, or already notified |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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
/billing/packagesEvery 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.
| Status | Description |
|---|---|
| 200 | List of packages |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"stripePriceId": "string",
"displayName": "string",
"marketingCopy": "string",
"featureBullets": [
"string"
],
"sortOrder": 0,
"mostPopular": false,
"price": {
"amount": "string",
"currency": "string",
"interval": "string"
},
"includedPayments": 0,
"overageRatePerPayment": "string"
}
]
}/billing/checkoutCreates 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.
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
stripePriceId | string | yes | The chosen package's flat recurring Price id. |
continueWithoutVatNumber | boolean | no | The 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. |
{
"companyId": "string",
"stripePriceId": "string",
"continueWithoutVatNumber": false
}| Status | Description |
|---|---|
| 200 | Hosted Checkout URL |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | Unknown or unavailable package |
| 409 | The 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. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
| 503 | Billing 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. |
{
"url": "string"
}/billing/subscriptionReads 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Subscription state |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
| 503 | Stripe could not be reached |
{
"subscribed": false,
"status": "string",
"hasBillingAccount": false,
"taxLocationRequired": false,
"nextInvoice": {
"date": "string",
"amount": "string",
"currency": "string"
},
"freePlan": false,
"freePlanSource": "bankconnector"
}/billing/usageThe 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Usage in the current billing period |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
| 503 | Stripe could not be reached |
{
"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"
}
]
}
}/billing/change-packageMoves 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.
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
stripePriceId | string | yes | The chosen package's flat recurring Price id. |
{
"companyId": "string",
"stripePriceId": "string"
}| Status | Description |
|---|---|
| 200 | The package the subscription is on now, and how the change is charged |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | Unknown or unavailable package |
| 409 | The 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. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
| 503 | Billing 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. |
{
"changed": false,
"packageName": "string",
"charge": "free_first_period"
}/billing/portalCreates 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.
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Hosted Customer Portal URL |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 409 | No billing account yet. Start Checkout first |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
| 503 | Billing 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. |
{
"url": "string"
}Workspace Admin
/auth/company-contextWorkspace (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.
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Context set |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Not a workspace admin: a company session, an API key or an install is refused (`forbidden`). |
| 404 | Unknown company in your platform |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"ok": false,
"csrfToken": "string"
}/auth/company-context| Status | Description |
|---|---|
| 200 | Context cleared |
| 401 | Sign in required: there is no valid session. |
| 403 | Not a workspace admin: a company session, an API key or an install is refused (`forbidden`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"ok": false
}Tenancy
/company/approval-settingsReadable 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).
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Approval settings |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"approvalSettings": {
"forbidSelfApproval": false,
"updatedAt": "string",
"updatedBy": "string"
}
}/company/approval-settingsSanitised 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Updated settings |
| 400 | Nothing to update |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"approvalSettings": {
"forbidSelfApproval": false,
"updatedAt": "string",
"updatedBy": "string"
}
}/company/currencyReadable by any authenticated member. currency is the Admin's choice, else the currency of the registered address's country, else EUR; source says which.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The company currency |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"currency": {
"currency": "string",
"source": "chosen",
"updatedAt": "string",
"updatedBy": "string"
}
}/company/currencyRequires 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
currency | string | null | yes |
{
"currency": "string"
}| Status | Description |
|---|---|
| 200 | The setting as stored |
| 400 | The body is not `{ currency: string | null }` with an active ISO 4217 code |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"currency": {
"currency": "string",
"source": "chosen",
"updatedAt": "string",
"updatedBy": "string"
}
}/company/productReadable 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The organisation's product |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"product": "erp-addon",
"erp": "string",
"packageChosen": false
}/company/productRequires 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).
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
product | enum | yes | |
erp | string | null | no |
{
"product": "erp-addon",
"erp": "string"
}| Status | Description |
|---|---|
| 200 | The product as stored |
| 400 | The body is not `{ product, erp? }` |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 409 | The organisation has chosen a package, or is on Embedded |
| 413 | The 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 |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"product": "erp-addon",
"erp": "string",
"packageChosen": false
}/company/erp-approvalReadable 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The ERP-approval setting |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"erpApproval": {
"enabled": false,
"updatedAt": "string",
"updatedBy": "string",
"require2fa": false,
"policiesNamingNobody": [
{
"id": "string",
"name": "string"
}
]
}
}/company/erp-approvalRequires 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
enabled | boolean | yes |
{
"enabled": false
}| Status | Description |
|---|---|
| 200 | The setting as stored |
| 400 | The body is not `{ enabled: boolean }` |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 409 | A precondition is missing |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"erpApproval": {
"enabled": false,
"updatedAt": "string",
"updatedBy": "string",
"require2fa": false,
"policiesNamingNobody": [
{
"id": "string",
"name": "string"
}
]
}
}/company/payee-verificationReadable 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The payee-verification setting |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"payeeVerification": {
"batches": "opt-in",
"updatedAt": "string",
"updatedBy": "string"
}
}/company/payee-verificationRequires 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
batches | enum | yes |
{
"batches": "opt-in"
}| Status | Description |
|---|---|
| 200 | The setting as stored |
| 400 | The body is not `{ batches: "opt-in" | "opt-out" }` |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"payeeVerification": {
"batches": "opt-in",
"updatedAt": "string",
"updatedBy": "string"
}
}/company/legal-identityWho we invoice, and where. Requires a signed-in Admin of this organisation. An organisation that has never set it answers { legalIdentity: {} }.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Legal identity |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"legalIdentity": {
"legalName": "string",
"vatNumber": "string",
"registeredAddress": {
"streetName": "string",
"buildingNumber": "string",
"postCode": "string",
"townName": "string",
"countrySubDivision": "string",
"addressLines": [
"string"
],
"country": "string"
},
"billingContactEmail": "string",
"updatedAt": "string",
"updatedBy": "string"
},
"automaticTax": {
"state": "restored"
},
"vatNumberNotConfirmed": false,
"registrationNumberEditable": false,
"vatNumberEditable": false,
"registerLookup": {
"outcome": "active",
"country": "string",
"number": "string",
"register": "string",
"lookedUpAt": "string",
"company": {
"name": "string",
"address": {
"streetName": "string",
"buildingNumber": "string",
"postCode": "string",
"townName": "string"
},
"legalForm": "string",
"inactiveReasons": [
"deleted"
],
"vatRegistered": false
},
"consultationNumber": "string"
}
}/company/legal-identitySanitised partial patch of legalName / vatNumber / registeredAddress / billingContactEmail. Unknown fields are stripped; an empty effective patch is a 400, and so is a billingContactEmail that is not an email address, and so is a registeredAddress without a two-letter country (or registeredAddress: null): the country is where the organisation is taxed and decides whether Checkout requires a VAT number. null clears a field. Requires a signed-in Admin of this organisation. An Admin may change legalName at any time; once one is stored, clearing it is a 400, and delegated partner access may set it while it is empty but not change it (403 partner_grant_cannot_rename). Each save is recorded on the organisation's activity feed with the name before and after. vatNumber is locked from the moment it is known: once stored, or, before that, where the organisation's registration number already is its VAT number (a Danish CVR number, as DK + CVR). Restating the known number in any spelling passes, and any save records a known number not yet stored; a different number or a clear is refused legal_identity_locked (409). A change is pushed onto the organisation's Stripe Customer where one exists; a Stripe that will not take it does Not fail the save, and the outcome is recorded on the organisation's activity feed. Where Stripe had switched VAT off on the organisation's subscription because it could not place the address, a save that lands on the Customer asks Stripe to turn it back on and answers the result as automaticTax. A VAT number the EU VAT register does not recognise is saved, left off the Stripe Customer so the invoices carry Danish VAT, and the answer carries vatNumberNotConfirmed: true.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Updated legal identity |
| 400 | Nothing to update, a malformed `billingContactEmail`, a `registeredAddress` without a country, or a stored `legalName` cleared |
| 401 | Sign in required: there is no valid session. |
| 403 | Not an Admin of this organisation, or `partner_grant_cannot_rename`: delegated partner access does not include changing a stored `legalName` |
| 409 | vatNumber already known as a different value. Contact support to change it |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"legalIdentity": {
"legalName": "string",
"vatNumber": "string",
"registeredAddress": {
"streetName": "string",
"buildingNumber": "string",
"postCode": "string",
"townName": "string",
"countrySubDivision": "string",
"addressLines": [
"string"
],
"country": "string"
},
"billingContactEmail": "string",
"updatedAt": "string",
"updatedBy": "string"
},
"automaticTax": {
"state": "restored"
},
"vatNumberNotConfirmed": false,
"registrationNumberEditable": false,
"vatNumberEditable": false,
"registerLookup": {
"outcome": "active",
"country": "string",
"number": "string",
"register": "string",
"lookedUpAt": "string",
"company": {
"name": "string",
"address": {
"streetName": "string",
"buildingNumber": "string",
"postCode": "string",
"townName": "string"
},
"legalForm": "string",
"inactiveReasons": [
"deleted"
],
"vatRegistered": false
},
"consultationNumber": "string"
}
}/company/nameSets 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
name | string | yes | The organisation's display name, as it appears in lists, invoices and the activity log. |
{
"name": "string"
}| Status | Description |
|---|---|
| 200 | The organisation's name after the write |
| 400 | `name` missing, empty, or longer than 70 characters |
| 401 | Sign in required: there is no valid session. |
| 403 | Not an Admin of this organisation, or `partner_grant_cannot_rename`: delegated partner access does not include renaming it |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"name": "string"
}/company/alert-settingsWhere 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Alert settings |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"alertSettings": {
"email": "string",
"pendingEmail": "string",
"certExpiring": false,
"batchRejected": false,
"channelDown": false,
"statementMissing": false,
"updatedAt": "string",
"updatedBy": "string"
}
}/company/alert-settingsPartial 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
email | string | null | no | The inbox alerts are sent to. `null` clears it, and then nothing is sent. |
certExpiring | boolean | no | Alert when a certificate or key is about to expire, or has. |
batchRejected | boolean | no | Alert when the bank rejects a batch. |
channelDown | boolean | no | Alert when a bank channel stops responding. |
statementMissing | boolean | no | Alert when an expected end-of-day statement has not arrived by 10:00 on a bank day. Off by default. |
{
"email": "string",
"certExpiring": false,
"batchRejected": false,
"channelDown": false,
"statementMissing": false
}| Status | Description |
|---|---|
| 200 | Updated alert settings |
| 400 | Invalid body, or nothing to update |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"alertSettings": {
"email": "string",
"pendingEmail": "string",
"certExpiring": false,
"batchRejected": false,
"channelDown": false,
"statementMissing": false,
"updatedAt": "string",
"updatedBy": "string"
}
}/company/alert-settings/resend-confirmationMints 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | A fresh link was sent |
| 400 | Nothing is pending |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many resend requests for this organisation |
{
"ok": false,
"pendingEmail": "string"
}/alert-inbox/confirmThe 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.
| Status | Description |
|---|---|
| 200 | HTML page |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
/alert-inbox/confirmPUBLIC: 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.
| Property | Type | Required | Description |
|---|---|---|---|
token | string | no |
{
"token": "string"
}| Status | Description |
|---|---|
| 200 | Confirmed |
| 400 | Unknown, already-redeemed or expired token |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"ok": false,
"email": "string"
}/company/api-keysRequires 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 integer | query | no | |
cursor string | query | no |
| Status | Description |
|---|---|
| 200 | API keys (no secret) |
| 400 | A `limit` that is not a number (`invalid_parameter`), or a malformed `cursor` (`invalid_cursor`). |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"id": "string",
"label": "string",
"createdAt": "string",
"lastUsedAt": "string"
}
],
"nextCursor": "string"
}/company/api-keysRequires 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
label | string | yes | Human name, e.g. "Production ERP". |
code | string | no | 2FA TOTP code (when step-up applies). |
backupCode | string | no | A 2FA backup code, in place of `code`. |
{
"label": "string",
"code": "string",
"backupCode": "string"
}| Status | Description |
|---|---|
| 201 | Key created: raw key shown once |
| 400 | A 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`) |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | Step-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) |
| 429 | Too many wrong 2FA codes (`rate_limited`); see `Retry-After` |
{
"id": "string",
"key": "string",
"label": "string",
"createdAt": "string"
}/company/api-keys/{keyId}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.
| Name | In | Required | Description |
|---|---|---|---|
keyId string | path | yes | |
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
code | string | no | 2FA TOTP code (when step-up applies). |
backupCode | string | no | A 2FA backup code, in place of `code`. |
{
"code": "string",
"backupCode": "string"
}| Status | Description |
|---|---|
| 200 | Revoked |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | Unknown or already-revoked key for this organisation, refused before the code is checked so a single-use code is not spent |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | Step-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) |
| 429 | Too many wrong 2FA codes (`rate_limited`); see `Retry-After` |
{
"id": "string",
"revoked": false
}/partner-access/requestsEvery 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Incoming requests |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"id": "string",
"orgId": "string",
"firmId": "string",
"firmName": "string",
"requestedBy": "string",
"requestedByName": "string",
"requestedLevel": "status",
"status": "pending",
"createdAt": "string",
"decidedAt": "string",
"decidedBy": "string"
}
]
}/partner-access/requestsA 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.
| Property | Type | Required | Description |
|---|---|---|---|
orgId | string | yes | |
level | enum | yes |
{
"orgId": "string",
"level": "status"
}| Status | Description |
|---|---|
| 201 | Request recorded |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not a partner firm's consultant |
| 404 | No such organisation |
| 409 | A pending request for this (organisation, level) already exists |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"request": {
"id": "string",
"orgId": "string",
"firmId": "string",
"firmName": "string",
"requestedBy": "string",
"requestedByName": "string",
"requestedLevel": "status",
"status": "pending",
"createdAt": "string",
"decidedAt": "string",
"decidedBy": "string"
}
}/partner-access/my-requestsEvery 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.
| Status | Description |
|---|---|
| 200 | The firm's requests |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not a partner firm's consultant |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"id": "string",
"orgId": "string",
"firmId": "string",
"firmName": "string",
"requestedBy": "string",
"requestedByName": "string",
"requestedLevel": "status",
"status": "pending",
"createdAt": "string",
"decidedAt": "string",
"decidedBy": "string"
}
]
}/partner-access/requests/{id}/approveMints 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no | |
level | enum | no |
{
"companyId": "string",
"level": "status"
}| Status | Description |
|---|---|
| 200 | Approved |
| 400 | Before `BankConnector-Version: 2026-10-20`: a level higher than the one asked for (`validation_failed`). |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No such request in this organisation |
| 409 | Already decided, or expired |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | From `BankConnector-Version: 2026-10-20`: a level higher than the one asked for (`validation_failed`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"request": {
"id": "string",
"orgId": "string",
"firmId": "string",
"firmName": "string",
"requestedBy": "string",
"requestedByName": "string",
"requestedLevel": "status",
"status": "pending",
"createdAt": "string",
"decidedAt": "string",
"decidedBy": "string"
}
}/partner-access/requests/{id}/denyMints nothing. Requires a signed-in Admin of this organisation. Same 404/409 shape as approve.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Denied |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No such request in this organisation |
| 409 | Already decided, or expired |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"request": {
"id": "string",
"orgId": "string",
"firmId": "string",
"firmName": "string",
"requestedBy": "string",
"requestedByName": "string",
"requestedLevel": "status",
"status": "pending",
"createdAt": "string",
"decidedAt": "string",
"decidedBy": "string"
}
}/partner-access/grants/{userId}/revokeRevokes 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.
| Name | In | Required | Description |
|---|---|---|---|
userId string | path | yes | |
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Revocation outcome |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"revoked": false
}/partner-access/firmsEach 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The firms with access |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"firmId": "string",
"firmName": "string",
"level": "status",
"grantedAt": "string",
"grantedBy": "string",
"consultants": [
{
"userId": "string",
"name": "string",
"email": "string",
"role": "partner-admin"
}
]
}
]
}/partner-access/firm-choicesEvery 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.
| Status | Description |
|---|---|
| 200 | The partner firms |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"id": "string",
"displayName": "string"
}
]
}/partner-access/deleted-firmsEach 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The deleted partner firms |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Forbidden: the credential's role, scope or grant does not allow this operation. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"firmId": "string",
"firmName": "string",
"deletedAt": "string",
"introduced": false
}
]
}/partner-access/firms/{firmId}/grantA 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.
| Name | In | Required | Description |
|---|---|---|---|
firmId string | path | yes | |
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no | |
level | enum | yes |
{
"companyId": "string",
"level": "status"
}| Status | Description |
|---|---|
| 200 | The level the firm now holds |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No such partner |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"firmId": "string",
"level": "status"
}/partner-access/firms/{firmId}/revokeEvery 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.
| Name | In | Required | Description |
|---|---|---|---|
firmId string | path | yes | |
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Revocation outcome |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"revoked": false
}/partner/firmA partner login only. Belonging to a firm reaches no customer by itself.
| Status | Description |
|---|---|
| 200 | The firm |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not a partner firm's consultant |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"firm": {
"id": "string",
"displayName": "string",
"partnerType": "uniconta-partner"
},
"role": "partner-admin"
}/partner/firm/membersEvery login of the caller's firm, removed ones included. The firm's administrator only.
| Status | Description |
|---|---|
| 200 | The firm's people |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not this firm's administrator |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"id": "string",
"email": "string",
"name": "string",
"role": "partner-admin",
"status": "active",
"createdAt": "string",
"addonReleaseEmails": false
}
]
}/partner/firm/membersCreates 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.
| Property | Type | Required | Description |
|---|---|---|---|
email | string | yes | |
name | string | yes | |
role | enum | no |
{
"email": "string",
"name": "string",
"role": "partner-admin"
}| Status | Description |
|---|---|
| 201 | Invited |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not this firm's administrator |
| 409 | The address is already registered |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
| 503 | No email is configured to deliver the link |
{
"member": {
"id": "string",
"email": "string",
"name": "string",
"role": "partner-admin",
"status": "active",
"createdAt": "string",
"addonReleaseEmails": false
},
"invited": false,
"emailDeliveryPending": false,
"inviteLink": "string"
}/partner/firm/members/{userId}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.
| Name | In | Required | Description |
|---|---|---|---|
userId string | path | yes |
| Status | Description |
|---|---|
| 200 | Removed |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not this firm's administrator |
| 404 | No such person in the firm |
| 409 | The firm's last administrator |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"member": {
"id": "string",
"email": "string",
"name": "string",
"role": "partner-admin",
"status": "active",
"createdAt": "string",
"addonReleaseEmails": false
},
"removed": false,
"revokedSessions": 0
}/partner/firm/members/{userId}/notificationsSets 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.
| Name | In | Required | Description |
|---|---|---|---|
userId string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
notifications | object | yes |
{
"notifications": {
"addonReleasePublished": false
}
}| Status | Description |
|---|---|
| 200 | The person, with their release emails as they now stand |
| 400 | The body names another switch, or a value that is not true or false |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not this firm's administrator |
| 404 | No such person in the firm, or the person was removed from it |
| 409 | The person is the last one at the firm who gets the release emails |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"member": {
"id": "string",
"email": "string",
"name": "string",
"role": "partner-admin",
"status": "active",
"createdAt": "string",
"addonReleaseEmails": false
}
}/partner/firm/members/{userId}/two-factor-resetChanges 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.
| Name | In | Required | Description |
|---|---|---|---|
userId string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
password | string | yes | |
code | string | no | |
backupCode | string | no |
{
"password": "string",
"code": "string",
"backupCode": "string"
}| Status | Description |
|---|---|
| 200 | The confirmation link was emailed (or `emailDeliveryPending`) |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not this firm's administrator, has no second factor, or the person is an administrator |
| 404 | No such person in the firm |
| 409 | The person has no active two-factor authentication to reset |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The administrator's password or code was refused |
| 429 | Too many attempts, or too many links sent to this person |
| 503 | No email is configured to deliver the link |
{
"requested": false,
"userId": "string",
"email": "string",
"name": "string",
"emailDeliveryPending": false
}/partner/customersMetadata 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.
| Status | Description |
|---|---|
| 200 | The referred customers |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not a partner firm's consultant |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"id": "string",
"legalName": "string",
"signupDate": "string",
"subscriptionStatus": "subscribed",
"paymentCount": 0,
"bankConnections": [
{
"connectionId": "string",
"healthy": false
}
],
"access": {
"level": "status"
},
"accessRequest": {
"status": "string",
"requestedLevel": "status"
}
}
]
}/partner/customer-logsOne 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.
| Name | In | Required | Description |
|---|---|---|---|
cursor string | query | no | The previous page's `nextCursor`. A malformed one is 400 `invalid_cursor`. |
| Status | Description |
|---|---|
| 200 | The customers' logs |
| 400 | A malformed `cursor` (`invalid_cursor`) |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not a partner firm's consultant |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/partner/addon-releasesNewest 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.
| Status | Description |
|---|---|
| 200 | The downloadable releases |
| 401 | No partner login |
| 403 | The caller is not a login of a partner firm whose partner type has an add-on |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"id": "string",
"product": "uniconta",
"version": "string",
"notes": "string",
"publishedAt": "string",
"fileKind": "zip",
"fileName": "string",
"sizeBytes": 0,
"sha256": "string",
"latest": false,
"availableUntil": "string"
}
]
}/partner/addon-releases/{id}/fileThe 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Status | Description |
|---|---|
| 200 | The release package (attachment) |
| 401 | No partner login |
| 403 | The caller is not a login of a partner firm whose partner type has an add-on |
| 404 | No release the firm can download now: withdrawn, expired or unknown |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
/partner/firm/signup-linkAny member of the firm. Carries the link's token or its chosen name, at most one of them; both are null until the link is set. Only the System Console sets it.
| Status | Description |
|---|---|
| 200 | The token |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not a partner firm's consultant |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"signupToken": "string",
"signupLinkName": "string"
}/partner/firm/uniconta-pidThe 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.
| Status | Description |
|---|---|
| 200 | The firm's number and its proposals |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not a partner firm's consultant |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"unicontaPid": 0,
"proposals": [
{
"unicontaPid": 0,
"status": "pending",
"proposedAt": "string",
"decidedAt": "string"
}
]
}/partner/firm/uniconta-pid-proposalsChanges 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.
| Property | Type | Required | Description |
|---|---|---|---|
unicontaPid | integer | yes |
{
"unicontaPid": 0
}| Status | Description |
|---|---|
| 200 | The proposed number and its state |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not this firm's administrator |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | The firm already has three numbers waiting to be checked |
{
"proposal": {
"unicontaPid": 0,
"status": "pending"
}
}/partner/me/notificationsWhich 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.
| Status | Description |
|---|---|
| 200 | The caller's switches |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not a partner firm's consultant |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"notifications": {
"customerSignedUp": false,
"accessApproved": false,
"accessDenied": false,
"accessGranted": false,
"accessRevoked": false,
"addonReleasePublished": false
}
}/partner/me/notificationsOnly 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.
| Property | Type | Required | Description |
|---|---|---|---|
notifications | object | yes |
{
"notifications": {
"customerSignedUp": false,
"accessApproved": false,
"accessDenied": false,
"accessGranted": false,
"accessRevoked": false,
"addonReleasePublished": false
}
}| Status | Description |
|---|---|
| 200 | The caller's switches as they now stand |
| 400 | The body names a switch that does not exist, or a value that is not true or false |
| 401 | Sign in required: there is no valid session. |
| 403 | The caller is not a partner firm's consultant |
| 409 | The caller is the last one at the firm who gets the release emails |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"notifications": {
"customerSignedUp": false,
"accessApproved": false,
"accessDenied": false,
"accessGranted": false,
"accessRevoked": false,
"addonReleasePublished": false
}
}/users/{id}/settings| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
settings | object | no |
{
"companyId": "string",
"settings": {
"locale": "string",
"dateFormat": "iso",
"timezone": "string",
"notifications": {
"paymentNeedsApproval": false,
"paymentApproved": false,
"paymentRejected": false,
"statementReceived": false,
"erpDecisionReceipt": false
}
}
}| Status | Description |
|---|---|
| 200 | Updated user |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | An API key, application install or other machine credential is refused (`forbidden`): this operation needs a signed-in person. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/users/{id}/nameA 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
name | string | yes |
{
"companyId": "string",
"name": "string"
}| Status | Description |
|---|---|
| 200 | Updated user |
| 400 | The name is empty, too long or holds control characters |
| 401 | Sign in required: there is no valid session. |
| 403 | Not your own record, and you are not an Admin of this company |
| 404 | No such user in this company |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/users/{id}/erp-grantsThe 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | The live sign-ins |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"items": [
{
"grantId": "string",
"application": "string",
"scopes": [
"string"
],
"createdAt": "string",
"expiresAt": "string"
}
]
}/users/{id}/erp-grants/{grantId}/revokeEnds one of the person's ERP add-on sign-ins; every token it issued stops working on its next request. Admin session only; journalled.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
grantId string | path | yes | |
companyId string | query | no | The 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 | Description |
|---|---|
| 200 | Revoked |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 404 | No live ERP add-on sign-in with that id for this user |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"revoked": false
}/users/{id}/rolesPUT = 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | yes | |
roles | string[] | yes | |
code | string | no | 2FA TOTP code (when step-up applies). |
backupCode | string | no | A 2FA backup code, in place of `code`. |
{
"companyId": "string",
"roles": [
"string"
],
"code": "string",
"backupCode": "string"
}| Status | Description |
|---|---|
| 200 | Updated user |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | The 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 |
| 404 | No such user in this company (`not_found`), answered before any code is checked so a single-use code is not spent |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | Step-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) |
| 429 | Too many wrong 2FA codes (`rate_limited`); see `Retry-After` |
{
"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"
]
}/users/{id}/deactivateKeeps personal data for audit, revokes live sessions and reports approval-quorum impact.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | User deactivated |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"userId": "string",
"deactivated": false,
"banksPaused": [
"string"
]
}/users/{id}/reactivateRestores 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | User reactivated |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"userId": "string",
"reactivated": false,
"status": "string",
"banksResumed": [
"string"
]
}/users/{id}/clear-email-flagClears 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Flag cleared |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"userId": "string",
"cleared": false
}/users/{id}/sign-outEnds 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).
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Signed out; `revoked` counts the sessions ended, `erpGrantsRevoked` the ERP add-on sign-ins |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"userId": "string",
"revoked": 0,
"erpGrantsRevoked": 0
}/users/{id}/reinvite| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Invite re-sent |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Authentication required: the credential is missing, invalid or expired. |
| 403 | Admin required: a session without the Admin role is refused (`forbidden`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this caller or this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/users/{id}/reset-password| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes |
| Property | Type | Required | Description |
|---|---|---|---|
companyId | string | no |
{
"companyId": "string"
}| Status | Description |
|---|---|
| 200 | Reset issued |
| 400 | The body is not JSON (`validation_failed`). Before `BankConnector-Version: 2026-10-20` a body that fails the route's schema is a 400 too. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required: a session without the Admin role, an API key or an application install is refused (`admin_required`). |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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
/installsEvery 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.
| Name | In | Required | Description |
|---|---|---|---|
companyId string | query | no | The 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 integer | query | no | |
cursor string | query | no |
| Status | Description |
|---|---|
| 200 | The organisation's installs. |
| 400 | A `limit` that is not a number (`invalid_parameter`), or a malformed `cursor` (`invalid_cursor`). |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required, or the grants:manage scope is missing |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"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"
}/installs/{id}/narrowThe 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
grantId | string | no | Which of the install's live grants to narrow. May be omitted when the install has exactly one, which is every install OAuth consent creates. |
scopes | string[] | no | The scopes to KEEP. A strict subset of what the grant holds. At least one is required; to remove them all, revoke the install instead. |
reason | string | no | Recorded on the journal event. |
{
"grantId": "string",
"scopes": [
"string"
],
"reason": "string"
}| Status | Description |
|---|---|
| 200 | The grant's remaining scopes, and what was removed. |
| 400 | No scope given, a non-delegable scope, a set that would WIDEN the grant, or the set it already holds. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required, or the grants:manage scope is missing |
| 404 | Unknown or revoked install, or unknown/revoked/expired grant. |
| 409 | This grant has live delegated grants beneath it, revoke those first. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"installId": "string",
"grant": {
"id": "string",
"scopes": [
"string"
]
},
"removed": [
"string"
]
}/installs/{id}/revokeFour 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.
| Name | In | Required | Description |
|---|---|---|---|
id string | path | yes | |
companyId string | query | no | The 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`. |
| Property | Type | Required | Description |
|---|---|---|---|
scope | enum | no | Which 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. |
reason | string | no | Recorded on the journal event. |
{
"scope": "install",
"reason": "string"
}| Status | Description |
|---|---|
| 200 | How many installs were revoked, and under which shape. |
| 400 | Validation failed. |
| 401 | Sign in required: there is no valid session. |
| 403 | Admin required, or the grants:manage scope is missing |
| 404 | Unknown or already-revoked install (scope=install), or an install unknown to this organisation (scope=application). |
| 409 | scope=installer, but this install has no recorded installer to revoke by. |
| 413 | The request body is larger than this operation accepts (`payload_too_large`). |
| 422 | The 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. |
| 429 | Too many requests from this network (`rate_limited`); wait `Retry-After` seconds. |
{
"installId": "string",
"shape": "string",
"revoked": 0
}