sandbox.bankconnector.com API Reference

Operate / Operator API reference

Operator API reference

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

Download the spec: openapi.json · openapi.yaml — the full spec covers both tracks.

Connections

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

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

Read-only metadata: which channel each bank uses (sftp / danske-ws / nordea-ca / bankconnect / ebics), its pre-known server/endpoint details, and SFTP wizard config. No auth required.

Responses
StatusDescription
200Connectivity profiles
Example response (200)
{
  "items": [
    {}
  ]
}
GET/connections
List bank connections for a company
Parameters
NameInRequiredDescription
platformId stringqueryyes
companyId stringqueryyes
Responses
StatusDescription
200Connection list
401Sign in required
Example response (200)
{
  "items": [
    {
      "id": "string",
      "bankKey": "nordea-dk",
      "bankName": "Nordea Danmark",
      "environment": "test",
      "channelType": "sftp",
      "active": false,
      "steps": {
        "introEmailSent": false,
        "pgpGenerated": false,
        "bankPublicKeyAdded": false,
        "serverInfoAdded": false,
        "sftpUserAdded": false,
        "approversAssigned": false,
        "certsIssued": false,
        "bankCertAdded": false,
        "ebicsKeysGenerated": false,
        "ebicsBankKeysFetched": false,
        "wsConfigAdded": false
      },
      "sshPublicKey": "string",
      "pgpPublicKey": "string",
      "approverUserIds": [
        "string"
      ],
      "createdAt": "2026-01-01T00: 00: 00Z"
    }
  ]
}
POST/connections
Create (or find existing) bank connection: starts the setup wizard

Creates a bank connection for the given company, or returns the existing one if already set up. Platform-admin note: if you are authenticated as a workspace (platform) admin, you must enter a company context first via POST /auth/company-context before calling this endpoint. Without it you will receive: "select a company context first."

Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
bankKeyBankKeyyes
environmentenumno
Example
{
  "platformId": "string",
  "companyId": "string",
  "bankKey": "nordea-dk",
  "environment": "test"
}
Responses
StatusDescription
201Connection created
400Invalid request
401Sign in required
403Admin required
Example response (201)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
GET/connections/{id}
Get a single connection + readiness
Parameters
NameInRequiredDescription
id stringpathyes
platformId stringqueryyes
companyId stringqueryyes
Responses
StatusDescription
200Connection + readiness
404Not found
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
PUT/connections/{id}/signing-cert
Pin the bank's published signing certificate

Stores the bank's PUBLISHED X.509 signing certificate (PEM or base64-DER) on the connection so inbound Web Services signatures are verified against it (fail-closed on any mismatch). Admin only. Validates the cert parses (400 on bad input). Returns the cert subject + expiry so the operator can confirm they pinned the right cert; the raw PEM is never returned. GET /connections/{id} then surfaces signingCertSubject / signingCertExpiry.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
certstringyesThe bank's published signing certificate — PEM (-----BEGIN CERTIFICATE-----) or base64-DER.
Example
{
  "platformId": "string",
  "companyId": "string",
  "cert": "string"
}
Responses
StatusDescription
200Pinned
400Bad certificate or non-WS connection
401Sign in required
403Admin required
Example response (200)
{
  "connectionId": "string",
  "certSubject": "string",
  "certExpiry": "2026-01-01T00: 00: 00Z"
}
POST/connections/{id}/generate-pgp
Generate our PGP key pair (SFTP channel)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
200PGP key pair generated
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/bank-key
Save the bank's PGP public key (SFTP channel)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
armoredKeystringyesASCII-armored PGP public key block.
Example
{
  "platformId": "string",
  "companyId": "string",
  "armoredKey": "string"
}
Responses
StatusDescription
200Bank key saved
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/server-info
Save SFTP server info (host, port, paths, fingerprint)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
hoststringyes
portintegerno
uploadPathstringno
downloadPathstringno
hostFingerprintstringno
Example
{
  "platformId": "string",
  "companyId": "string",
  "host": "string",
  "port": 22,
  "uploadPath": "string",
  "downloadPath": "string",
  "hostFingerprint": "string"
}
Responses
StatusDescription
200Server info saved
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/sftp-user
Set SFTP username and generate SSH key pair (single combined call)

Sets the SFTP username AND generates the SSH key pair in one call: you cannot pre-generate the key before you have the username. The username must be obtained from the bank first; only then can you call this endpoint. The response includes the connection + readiness state, from which you can retrieve the generated SSH public key to send to the bank for whitelisting.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
usernamestringyesSFTP username assigned by the bank. Required: the SSH key generation and username registration are a single atomic operation.
Example
{
  "platformId": "string",
  "companyId": "string",
  "username": "string"
}
Responses
StatusDescription
200Username set + SSH key generated
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/approvers
Assign approver users to a connection

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

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
userIdsstring[]yesUser IDs of company members with the Approver role. Must already exist in the company. Max 200 (enforced server-side): each id costs a user lookup, so the list is bounded rather than unbounded input behind admin auth.
Example
{
  "platformId": "string",
  "companyId": "string",
  "userIds": [
    "string"
  ]
}
Responses
StatusDescription
200Approvers assigned
401Sign in required
403Admin required
422One or more user IDs are not valid approvers in this company
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/activate
Mark SFTP connection active (after the bank has whitelisted the SSH key)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
200Connection activated
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/intro-email-sent
Mark intro email as sent (tracks wizard progress)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
200Updated
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/ws-environment
Toggle a Web Services connection between TEST and PRODUCTION

Requires an already-activated connection (certificates issued); does not re-run PKI.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
environmentenumyes
Example
{
  "platformId": "string",
  "companyId": "string",
  "environment": "TEST"
}
Responses
StatusDescription
200Environment updated
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/covered-banks
Set which member banks a shared connection covers

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

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
coveredBankKeysstring[]yesBank keys this connection serves (clamped to the bank's group).
Example
{
  "platformId": "string",
  "companyId": "string",
  "coveredBankKeys": [
    "string"
  ]
}
Responses
StatusDescription
200Covered banks updated
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
GET/connections/{id}/intro-email
Render the bank intro email (draft to send to the bank contact)
Parameters
NameInRequiredDescription
id stringpathyes
platformId stringqueryyes
companyId stringqueryyes
Responses
StatusDescription
200Rendered email (subject + body)
404Not found
GET/banks/{bankKey}/setup-info
Per-bank setup descriptor for the wizard UI

Returns the channel kind, requirements text, field definitions, pre-known server/endpoint details, and SFTP wizard screens for a bank. Used by the setup wizard to render the correct flow.

Parameters
NameInRequiredDescription
bankKey BankKeypathyes
Responses
StatusDescription
200Setup descriptor
404Unknown bank
POST/banks/{bankKey}/guide-feedback
Report that a bank's setup guide is wrong

Sends the customer's note about a bank's setup guide to BankConnector. The bank, its data central, the company and the platform are attached server-side from the route + session — the body carries only the message, so a caller cannot file feedback as another company.

Parameters
NameInRequiredDescription
bankKey BankKeypathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
messagestringyesWhat was confusing, or what the bank did differently.
Example
{
  "platformId": "string",
  "companyId": "string",
  "message": "string"
}
Responses
StatusDescription
200Feedback sent
400Empty or over-long message
401Not signed in
404Unknown bank
502The feedback could not be mailed — retry
Example response (200)
{
  "sent": false
}
GET/banks/{bankKey}/settings
Get per-company settings for a specific bank
Parameters
NameInRequiredDescription
bankKey BankKeypathyes
platformId stringqueryyes
companyId stringqueryyes
Responses
StatusDescription
200Bank settings (null if none saved)
PATCH/banks/{bankKey}/settings
Update per-company settings for a specific bank (partial patch)

Payment-affecting fields (agreementId, debtorAgreementId, chargeBearer, executionDateOffsetDays, approvalPolicyId, painVersion, batchBooking, authorisationCode, authorisationProprietary) require Admin. The selected pin is open to any member. debtorAgreementId is the bank's second agreement identifier (e.g. the Nordea CAW/CCM agreement number) — auto-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.

Parameters
NameInRequiredDescription
bankKey BankKeypathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringno
companyIdstringno
agreementIdstringno
debtorAgreementIdstringno
chargeBearerenumno
executionDateOffsetDaysintegerno
approvalPolicyIdstringno
painVersionenumno
batchBookingbooleanno
authorisationCodeenumno
authorisationProprietarystringno
selectedbooleanno
Example
{
  "platformId": "string",
  "companyId": "string",
  "agreementId": "string",
  "debtorAgreementId": "string",
  "chargeBearer": "SLEV",
  "executionDateOffsetDays": 0,
  "approvalPolicyId": "string",
  "painVersion": "pain.001.001.03",
  "batchBooking": false,
  "authorisationCode": "AUTH",
  "authorisationProprietary": "string",
  "selected": false
}
Responses
StatusDescription
200Settings saved
401Sign in required
403Admin required for payment-affecting fields
GET/bank-settings
List all per-company bank settings in one call
Parameters
NameInRequiredDescription
platformId stringqueryyes
companyId stringqueryyes
Responses
StatusDescription
200All saved bank settings for this company
Example response (200)
{
  "settings": [
    {}
  ]
}
POST/connections/{id}/activate-danske
Activate Danske EDI Web Services (automated cert enrolment)

Calls the Danske bxd.fi activation endpoint with the one-time PIN, self-issues the signing + encryption certificates, and marks the connection active. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
userIdstringyesAgreement number (User ID) from Danske.
pinstringyesOne-time transfer key from Danske.
Example
{
  "platformId": "string",
  "companyId": "string",
  "userId": "string",
  "pin": "string"
}
Responses
StatusDescription
200Activated
400Activation failed (wrong PIN, network, etc.)
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/activate-nordea
Activate Nordea Corporate Access (HMAC cert enrolment via SMS code)

Generates a Nordea-format signing CSR, sends the HMAC-signed enrolment request to Nordea's Corporate Access endpoint using the SMS activation code, and stores the issued certificate. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
holderNamestringyesCertificate-holder name (CN) as printed in the Nordea agreement.
signerIdstringyesSigner ID from the agreement.
senderIdstringno
countrystringyes
activationCodestringyes10-digit SMS activation code from Nordea.
Example
{
  "platformId": "string",
  "companyId": "string",
  "holderName": "string",
  "signerId": "string",
  "senderId": "string",
  "country": "string",
  "activationCode": "string"
}
Responses
StatusDescription
200Activated
400Activation failed
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/activate-bankconnect
Activate Bank Connect (DK gateway: automated cert enrolment)

Enrols the signing certificate with the Bank Connect data central (BD/BEC/SDC), stores the issued certificate and bank public key, and marks the connection active. Data central and country are pre-filled from the bank profile. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
organisationIdstringyesBank registration number.
functionIdstringyesPer-agreement routing code from the bank.
activationCodestringyesOne-time activation code from the bank.
Example
{
  "platformId": "string",
  "companyId": "string",
  "organisationId": "string",
  "functionId": "string",
  "activationCode": "string"
}
Responses
StatusDescription
200Activated
400Activation failed or bank has no Bank Connect data central
401Sign in required
403Admin required
404Connection not found
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/renew-danske
Renew the Danske EDI Web Services certificates

Issues fresh signing + encryption keypairs/CSRs to Danske's PKI via RenewCertificate — the request is enveloped-signed with the current signing certificate and XML-encrypted to the bank certificate (PKI WS spec §7) — and commits the new keys + certificates atomically on success. Run before the 2-year certificate expiry (the cert-expiring alerts fire at 30/14/7 days). A failed renewal leaves the current credentials untouched. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
200Renewed
400Renewal failed (current credentials left untouched)
401Sign in required
403Admin required
404Connection not found
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/renew-op
Renew the OP (Finland) Web Services signing certificate

Issues a fresh keypair + CSR (same subject as the current certificate: CN=WS username, C=FI) to OP's Certificate Service — the CertApplicationRequest is signed with the CURRENT key (guide §4.1.4), so NO transfer key is needed while the current certificate is valid — and commits the new key + certificate atomically on success, refusing a certificate whose public key does not match the CSR (OP silently returns copies of prior certificates). Run before the ~2-year expiry (alerts at 30/14/7 days; the daily auto-renew sweep also acts inside the 30-day horizon): a LAPSED OP certificate cannot be renewed at all — the customer starts over with a NEW transfer key from OP. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
200Renewed
404Connection not found
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/renew-nordea
Renew the Nordea Corporate Access signing certificate

Issues a fresh keypair + CSR (same subject as the current certificate) to Nordea's Certificate Service — the CertApplicationRequest is signed with the current certificate in place of the HMAC (Certificate Management §3.1.2), so no new SMS activation code is needed while the current certificate is valid — and commits the new key + certificate atomically on success. Run before the 2-year expiry (alerts at 30/14/7 days). A failed renewal leaves the current credentials untouched. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
200Renewed
400Renewal failed (current credentials left untouched)
401Sign in required
403Admin required
404Connection not found
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/renew-bankconnect
Renew the Bank Connect customer certificate

Issues a fresh keypair + CSR (CN=functionId) to the Bank Connect data central via renewCustomerCertificate, signed with the current certificate, and commits the new key + certificate atomically on success. Run before the 3-year certificate expiry (the cert-expiring alerts fire at 30/14/7 days); the bank revokes the previous certificate 48 hours after a successful renewal. Admin only.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
200Renewed
400Renewal failed (current credentials left untouched)
401Sign in required
403Admin required
404Connection not found
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/ebics-params
Save EBICS connection parameters (Host ID, Partner ID, User ID, …)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
urlstringyesEBICS server URL.
hostIdstringyesBank-assigned Host ID.
partnerIdstringyesCustomer ID (PartnerID) from the bank.
userIdstringyesSubscriber ID (UserID) from the bank.
protocolVersionstringno
signatureVersionstringno
subscriberModeenumnoOne shared technical subscriber, or one EBICS subscriber per approver.
veuOnlybooleannoPer-user only: this agreement routes every order through VEU (refuses multi-signature uploads) — delivery uploads one ES and adds the rest via HVE.
uploaderUserIdstringnoPer-user only: DESIGNATED uploader (app user id) — which subscriber transports payment uploads and acts for VEU orders. Must be a user in this company; the subscriber must be ACTIVE at delivery time (delivery fails with a clear error otherwise). Empty string clears the designation (default: first active subscriber). May be a non-approver transport-class subscriber for veuOnly agreements.
Example
{
  "platformId": "string",
  "companyId": "string",
  "url": "string",
  "hostId": "string",
  "partnerId": "string",
  "userId": "string",
  "protocolVersion": "H005",
  "signatureVersion": "A006",
  "subscriberMode": "technical",
  "veuOnly": false,
  "uploaderUserId": "string"
}
Responses
StatusDescription
200EBICS params saved
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/ebics-generate-keys
Generate EBICS subscriber keys (authentication, encryption, signature)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
200Keys generated
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/ebics-fetch-htd
Fetch the bank's record of the EBICS agreement (HTD/HKD) and store the discovery snapshot

Runs EBICS HTD (technical subscriber) or HKD (per-user mode) against the bank and persists the result on the connection: accounts on the agreement, permitted order types/BTFs with bank-side signature quorums, and each subscriber's bank-side status + signature class. Requires the bank keys (run ebics-fetch-hpb first). Pre-activation returns notActivatedYet instead of failing, so it can be polled as an activation check. In per-user mode, approvers the bank reports as ready are advanced to active automatically.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
200Discovery result (fetched flag, message, and the parsed agreement data when available)
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/ebics-renew
Rotate the EBICS subscriber keys in-band (HCS)

Sends an HCS order: the NEW three keys (signature/authentication/encryption), authorised by the CURRENT signature key — no new INI letter or bank re-activation. Two-phase and key-loss safe: the new keyset is staged before sending and promoted only on a confirmed accept; an ambiguous (post-commit) outcome keeps both keysets and the next call resolves automatically by probing which keyset the bank accepts. Per-user mode rotates one approver at a time (pass userId).

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
userIdstringnoPer-user mode: the approver whose subscriber to rotate.
Example
{
  "platformId": "string",
  "companyId": "string",
  "userId": "string"
}
Responses
StatusDescription
200Renewal outcome (renewed | ambiguous | resolved-kept-old | resolved-promoted | unresolved)
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/ebics-veu-pending
List the orders pending signature at the bank (EBICS VEU / HVU)

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

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
200Pending orders (veuPending array on the connection response)
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/ebics-suspend
Emergency-suspend the subscriber's EBICS access (SPR)

Sends an authenticated SPR order telling the bank to immediately suspend this subscriber's access — the compromised-key kill switch. One-directional: restoring access requires re-onboarding (new INI/HIA + letter). Also deactivates the connection locally so polling/delivery stops. Per-user mode suspends the named (or first active) approver.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
userIdstringnoPer-user mode: the approver to suspend.
Example
{
  "platformId": "string",
  "companyId": "string",
  "userId": "string"
}
Responses
StatusDescription
200Suspend result (bank return code + message)
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
POST/connections/{id}/ebics-veu-complete
Complete an interrupted VEU co-sign for a pending order (HVE)

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

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
documentIdstringnoThe sent payment (its frozen pain.001 is signed).
orderDigeststringnoThe pending order's dataDigest, to resolve the payment.
orderIdstringnoThe bank order number to select the pending order.
Example
{
  "platformId": "string",
  "companyId": "string",
  "documentId": "string",
  "orderDigest": "string",
  "orderId": "string"
}
Responses
StatusDescription
200Co-sign results (per approver) + executionReady
401Sign in required
403Admin required
Example response (200)
{
  "connection": {
    "id": "string",
    "bankKey": "nordea-dk",
    "bankName": "Nordea Danmark",
    "environment": "test",
    "channelType": "sftp",
    "active": false,
    "steps": {
      "introEmailSent": false,
      "pgpGenerated": false,
      "bankPublicKeyAdded": false,
      "serverInfoAdded": false,
      "sftpUserAdded": false,
      "approversAssigned": false,
      "certsIssued": false,
      "bankCertAdded": false,
      "ebicsKeysGenerated": false,
      "ebicsBankKeysFetched": false,
      "wsConfigAdded": false
    },
    "sshPublicKey": "string",
    "pgpPublicKey": "string",
    "approverUserIds": [
      "string"
    ],
    "createdAt": "2026-01-01T00: 00: 00Z"
  },
  "readiness": {
    "ready": false,
    "missing": [
      "string"
    ],
    "score": 0
  }
}
GET/connections/{id}/ebics-letter
Download the EBICS initialisation letter (PDF, base64-encoded)

Returns the signed INI/HIA initialisation letter as a base64-encoded PDF. Print, sign, and send to the bank to complete EBICS subscriber activation.

Parameters
NameInRequiredDescription
id stringpathyes
platformId stringqueryyes
companyId stringqueryyes
Responses
StatusDescription
200PDF as base64
404Not found or keys not yet generated
Example response (200)
{
  "pdfBase64": "string",
  "filename": "string"
}

Approvals

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

GET/approvals/pending
List payments awaiting approval
Parameters
NameInRequiredDescription
companyId stringqueryyes
Responses
StatusDescription
200Pending approval requests
401Sign in required
Example response (200)
{
  "items": [
    {}
  ],
  "nextCursor": "string"
}
POST/approvals/{id}/approve
Approve a pending payment (maker ≠ checker enforced)

An approver other than the maker approves the request; once the policy's required approvals are met the payment proceeds to delivery. May require a 2FA code/backup code if step-up is configured.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
reasonstringno
codestringno2FA TOTP code (if step-up required).
backupCodestringno
Example
{
  "platformId": "string",
  "companyId": "string",
  "reason": "string",
  "code": "string",
  "backupCode": "string"
}
Responses
StatusDescription
200Approval recorded (and payment dispatched if fully approved)
401Sign in required
403Maker cannot approve own payment / not an approver
POST/approvals/{id}/reject
Reject a pending payment
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
reasonstringno
Example
{
  "platformId": "string",
  "companyId": "string",
  "reason": "string"
}
Responses
StatusDescription
200Rejection recorded
401Sign in required
GET/approvals/policies
List approval policies for a company
Parameters
NameInRequiredDescription
companyId stringqueryyes
Responses
StatusDescription
200Policies
401Sign in required
Example response (200)
{
  "policies": [
    {}
  ]
}
POST/approvals/policies
Create an approval policy (Admin)

Defines required approver count + amount thresholds. Admin only.

Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
namestringyes
requiredApprovalsintegerno
thresholdAmountstringno
currencystringno
Example
{
  "platformId": "string",
  "companyId": "string",
  "name": "string",
  "requiredApprovals": 0,
  "thresholdAmount": "string",
  "currency": "string"
}
Responses
StatusDescription
201Policy created
401Sign in required
403Admin required
POST/approvals/policies/{id}
Edit a DRAFT approval policy (Admin)

Edit a policy's name / required approver count / thresholds. Works only on a DRAFT version — an Active version is immutable (409); change it via /approvals/policies/{id}/propose then co-sign.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
namestringno
requiredApprovalsintegerno
thresholdAmountstringno
currencystringno
Example
{
  "platformId": "string",
  "companyId": "string",
  "name": "string",
  "requiredApprovals": 0,
  "thresholdAmount": "string",
  "currency": "string"
}
Responses
StatusDescription
200Updated draft policy
401Sign in required
403Admin required
409Version is not a draft / conflict
Example response (200)
{
  "policy": {}
}
POST/approvals/policies/{id}/lock
Activate (lock) a draft approval policy (Admin)

Locks a DRAFT version → Active and immutable. Runs the quorum check (a dual policy needs ≥2 named approvers); fails 409 if it can't be met. An Active version is changed only via propose + co-sign.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
200Policy activated
401Sign in required
403Admin required
409Quorum not met / conflict
Example response (200)
{
  "policy": {}
}
POST/approvals/policies/{id}/propose
Propose a change to an Active policy (Admin)

Clones the Active version to an editable draft v(n+1). Edit the draft (POST /approvals/policies/{draftId}), then submit it for activation via POST /approvals/changes/{changeId}/submit and have a second Admin co-sign via POST /approvals/changes/{changeId}/cosign. The old version is retained forever once superseded.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
201Draft version created
401Sign in required
403Admin required
409Base not Active / change already in progress
Example response (201)
{
  "policy": {}
}
GET/approvals/bank-rosters
Who may approve payments on each covered bank

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

Parameters
NameInRequiredDescription
companyId stringqueryyes
bankKeys stringqueryyesComma-separated covered bank keys (repeatable).
Responses
StatusDescription
200One roster row per covered bank
400No bank keys named
401Sign in required
Example response (200)
{
  "items": [
    {
      "bankKey": "string",
      "policyId": "string",
      "policyName": "string",
      "builtIn": false,
      "bound": false,
      "approverUserIds": [
        "string"
      ],
      "requiredApprovals": 0,
      "sharedWith": [
        "string"
      ]
    }
  ]
}
POST/approvals/bank-rosters
Set who may approve payments on covered banks (Admin)

ALL-OR-NOTHING across the set: the ratchet judges each bank, but 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. No policy is ever edited in place — each bank is moved to a policy carrying the wanted roster on its current rule, so a policy shared with other banks is left untouched.

Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
targetsobject[]yes
Example
{
  "platformId": "string",
  "companyId": "string",
  "targets": [
    {
      "bankKey": "string",
      "approverUserIds": [
        "string"
      ]
    }
  ]
}
Responses
StatusDescription
200In force now
202Accepted — NOT in force; awaiting a second Admin's co-sign
400Malformed roster set
401Sign in required
403Admin required
409Refused by the ratchet (e.g. only one Admin) / a change is already awaiting co-sign
Example response (200)
{
  "banks": [
    {}
  ],
  "pending": false
}
GET/approvals/changes
List approval-policy change requests (Admin)

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

Parameters
NameInRequiredDescription
status enumqueryno
Responses
StatusDescription
200Change requests
401Sign in required
403Admin required
Example response (200)
{
  "changes": [
    {}
  ]
}
POST/approvals/changes/{changeId}/{action}
Submit / co-sign / cancel a policy change (Admin)

action=submit — the proposer submits the draft for activation (counts as the FIRST of 2 co-signs). action=cosign — a SECOND, distinct Admin co-signs: the new version goes Active, the base is Superseded, and attached banks re-point to the new version. action=cancel — any Admin cancels a pending change (the draft is discarded; the base stays Active). A 2nd co-sign by the same Admin is refused (409).

Parameters
NameInRequiredDescription
changeId stringpathyes
action enumpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
Example
{
  "platformId": "string",
  "companyId": "string"
}
Responses
StatusDescription
200Change updated
401Sign in required
403Admin required
409Same-admin co-sign / conflict
Example response (200)
{
  "change": {},
  "policy": {},
  "supersededId": "string",
  "affectedBanks": [
    "string"
  ]
}

Auth

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

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

PUBLIC. Exchanges subdomain + 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). If 2FA is enabled, returns a step-up challenge instead (complete it at POST /auth/2fa).

Request body required
PropertyTypeRequiredDescription
subdomainstringyes
emailstringyes
passwordstringyes
Example
{
  "subdomain": "demo",
  "email": "string",
  "password": "string"
}
Responses
StatusDescription
200Logged in (session cookie set) OR a 2FA step-up challenge
401Invalid credentials
Example response (200)
{
  "expiresAt": "2026-01-01T00: 00: 00Z",
  "csrfToken": "string",
  "twoFactorRequired": false
}
Code samples
curl -X POST https://your-host/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"subdomain":"demo","email":"you@acme.com","password":"…"}'
const res = await fetch("https://your-host/auth/login", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"subdomain":"demo","email":"you@acme.com","password":"…"}),
});
const data = await res.json();
import requests

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

Generates a NOT-yet-active TOTP secret for the signed-in user and returns its otpauth:// URI (render as a QR). Activate it with POST /2fa/confirm. Session-only.

Responses
StatusDescription
200Pending secret + otpauth URI
401Sign in first
Example response (200)
{
  "secret": "string",
  "otpauthUri": "string",
  "issuer": "string"
}
POST/2fa/confirm
Confirm 2FA enrollment with a TOTP code — returns one-time backup codes

Verifies a code against the pending secret and activates 2FA. The backup codes are returned EXACTLY ONCE — surface + warn. Session-only; throttled per user.

Request body required
PropertyTypeRequiredDescription
codestringyes6-digit TOTP code
Example
{
  "code": "string"
}
Responses
StatusDescription
200Enabled + one-time backup codes
400Setup not started
409Already enabled
422Code didn't match
429Too many attempts (Retry-After)
Example response (200)
{
  "enabled": false,
  "backupCodes": [
    "string"
  ]
}
POST/2fa/disable
Disable 2FA (requires a fresh code; blocked when the company forces 2FA)

Turns off the signed-in user's 2FA after verifying a fresh TOTP or backup code; refused (403) when the company requires 2FA. Revokes the user's OTHER sessions. Session-only; throttled.

Request body required
PropertyTypeRequiredDescription
codestringno
backupCodestringno
Example
{
  "code": "string",
  "backupCode": "string"
}
Responses
StatusDescription
200Disabled
403Company requires 2FA
409Not enabled
422A valid code is required
429Too many attempts (Retry-After)
Example response (200)
{
  "enabled": false
}
POST/company/require-2fa
Admin: set the company-wide 2FA requirement

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

Request body required
PropertyTypeRequiredDescription
enabledbooleanyes
Example
{
  "enabled": false
}
Responses
StatusDescription
200Updated company policy
403Admin role required
Example response (200)
{
  "require2fa": false
}
GET/auth/me
Current principal (who am I)
Responses
StatusDescription
200The signed-in user + roles + company
401Not signed in
POST/auth/logout
Log out (invalidates the session)
Responses
StatusDescription
200Logged out
GET/auth/platform-info
Public platform branding for the login page

Returns the branding for the platform resolved from the request's subdomain (no auth — called before login). On a known subdomain: the platform's display name + subdomain. Otherwise the generic BankConnector branding. logoUrl is reserved for a later phase (null for now).

Responses
StatusDescription
200Platform branding
Example response (200)
{
  "platformId": "string",
  "displayName": "string",
  "subdomain": "string",
  "logoUrl": "string"
}
POST/auth/2fa
Complete a 2FA login step-up (PUBLIC)

PUBLIC. Submits the TOTP (or backup) code against the challenge from POST /auth/login to obtain the session (delivered ONLY as the httpOnly bc_session cookie — the raw token is never in the response body).

Request body required
PropertyTypeRequiredDescription
challengestringyesThe challenge id from /auth/login.
codestringyes
backupCodestringno
Example
{
  "challenge": "string",
  "code": "string",
  "backupCode": "string"
}
Responses
StatusDescription
200Session granted (session cookie set)
401Invalid code
Example response (200)
{
  "expiresAt": "2026-01-01T00: 00: 00Z",
  "csrfToken": "string"
}

User Management

Create, invite, and manage users within a company. Also covers workspace (platform) admin accounts.

GET/platforms/{platformId}/admins
List workspace admins for a platform

Returns all workspace (platform) admin accounts. Workspace-admin session required.

Parameters
NameInRequiredDescription
platformId stringpathyes
Responses
StatusDescription
200Workspace admins
403Not a workspace admin
Example response (200)
{
  "items": [
    {
      "id": "string",
      "email": "string",
      "name": "string"
    }
  ],
  "nextCursor": "string"
}
POST/platforms/{platformId}/admins
Create a workspace admin

Creates a new workspace (platform) admin account with a password. Bootstrap note: when the server is running in open/unauthenticated mode (no BANKCONNECTOR_API_KEYS set, e.g. first-time setup), this endpoint is accessible without a session: use it to create the very first admin. Once auth is enabled, an existing workspace-admin session is required.

Parameters
NameInRequiredDescription
platformId stringpathyes
Request body required
PropertyTypeRequiredDescription
emailstringyes
namestringyes
passwordstringyesInitial password. Minimum 8 characters.
Example
{
  "email": "admin@acme.com",
  "name": "Alice Admin",
  "password": "string"
}
Responses
StatusDescription
201Admin created
400Invalid request or duplicate email
403Not a workspace admin (when auth is enabled)
Example response (201)
{
  "id": "string",
  "email": "string",
  "name": "string"
}
GET/users
List users in a company

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

Parameters
NameInRequiredDescription
platformId stringqueryyes
companyId stringqueryyes
Responses
StatusDescription
200Company users
401Sign in required
Example response (200)
{
  "users": [
    {
      "id": "string",
      "email": "string",
      "name": "string",
      "roles": [
        "admin"
      ],
      "status": "active"
    }
  ]
}
POST/users
Create or invite a company user

Company admin only. Two modes:

  • With password: creates the user immediately (active). Use for programmatic provisioning.
  • Without password: sends an invite email. The user receives a link to /auth/set-password where they set their own 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.

Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
emailstringyes
namestringyes
rolesenum[]yes
passwordstringnoIf omitted, an invite email is sent and the user sets their own password.
Example
{
  "platformId": "string",
  "companyId": "string",
  "email": "approver@acme.com",
  "name": "Bob Approver",
  "roles": [
    "approver"
  ],
  "password": "string"
}
Responses
StatusDescription
201User created or invite sent
400Invalid request, duplicate email, or no valid roles
403Company admin required
Example response (201)
{
  "id": "string",
  "email": "string",
  "name": "string",
  "roles": [
    "string"
  ],
  "invited": false
}
POST/auth/set-password
Complete an invite: set password from email token (PUBLIC)

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

Request body required
PropertyTypeRequiredDescription
tokenstringyesThe one-time invite token from the email link.
passwordstringyesThe user's chosen password.
Example
{
  "token": "string",
  "password": "string"
}
Responses
StatusDescription
200Password set
400Invalid or expired token
429Too many attempts: IP rate-limited
Example response (200)
{
  "ok": false,
  "email": "string"
}

Platform

Tenant dashboard + per-bank test payments

POST/client-errors
Report a browser-side crash

REACT-6(b) / ADR-0047. The React island error boundary posts here when a render throws, so a crash on a payments or approvals screen is not invisible to the operator. Tenant-scoped by the SESSION — the body's tenant is never trusted.

ALWAYS answers 202, even when nothing is stored: a report is best-effort telemetry, the browser cannot act on the difference, and an error reporter that returns errors is a second failure on an already-broken screen. recorded says which happened.

OFF BY DEFAULT: unless BANKCONNECTOR_CLIENT_ERROR_CAPTURE=1 the payload is not even parsed. Per ADR-0047 it stays off in production until the DPA and privacy notice cover the processing activity. When on, 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 retained deliberately, so a report identifies the record that broke.

Request body required
PropertyTypeRequiredDescription
islandstringnoIsland label from the mounter, e.g. "approvals-queue".
routestringnoRoute in view. Query string is dropped by client AND server.
messagestringno
stackstringno
componentStackstringnoReact component stack.
userAgentstringno
Example
{
  "island": "string",
  "route": "string",
  "message": "string",
  "stack": "string",
  "componentStack": "string",
  "userAgent": "string"
}
Responses
StatusDescription
202Accepted. `recorded` distinguishes stored from dropped (capture off, no session, empty).
Example response (202)
{
  "ok": false,
  "recorded": false
}
GET/bank-requests
List all bank requests (Admin only)
Responses
StatusDescription
200All requests
401Sign in required
403Admin required
Example response (200)
{
  "items": [
    {}
  ]
}
POST/bank-requests
Request a bank we don't support yet

Any signed-in user (or anonymous) can submit a BIC or bank name. The request is queued for the development team.

Request body required
PropertyTypeRequiredDescription
querystringyesBIC code or bank name.
emailstringno
Example
{
  "query": "string",
  "email": "string"
}
Responses
StatusDescription
201Request recorded
400Empty query
Example response (201)
{
  "ok": false,
  "request": {
    "id": "string",
    "query": "string",
    "createdAt": "2026-01-01T00: 00: 00Z"
  }
}

Workspace Admin

GET/platforms/{platformId}/companies
List the companies under a platform

Workspace (platform) admin only. The company list a workspace admin manages: drives the GUI company list + company-switcher (POST /auth/company-context).

Parameters
NameInRequiredDescription
platformId stringpathyes
Responses
StatusDescription
200Companies
403Not a workspace admin
Example response (200)
{
  "items": [
    {
      "id": "string",
      "name": "string",
      "createdAt": "2026-01-01T00: 00: 00Z"
    }
  ],
  "nextCursor": "string"
}
POST/platforms/{platformId}/companies
Create a company under a platform

Workspace (platform) admin only. Creates a new company (tenant) under the platform. Requires a session (workspace-admin login): not an API key. After creation, use POST /auth/company-context to enter the company and make company-scoped calls.

Parameters
NameInRequiredDescription
platformId stringpathyes
Request body required
PropertyTypeRequiredDescription
namestringyesDisplay name for the company.
Example
{
  "name": "Acme Payments Ltd"
}
Responses
StatusDescription
201Company created
400Invalid request
403Not a workspace admin
Example response (201)
{
  "company": {
    "id": "comp_…",
    "name": "string",
    "createdAt": "2026-01-01T00: 00: 00Z"
  }
}
POST/auth/company-context
Enter a company context (platform admin acts AS a company)

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

Request body required
PropertyTypeRequiredDescription
companyIdstringyes
Example
{
  "companyId": "string"
}
Responses
StatusDescription
200Context set
403Not a workspace admin
404Unknown company in your platform
Example response (200)
{
  "ok": false
}
DELETE/auth/company-context
Exit the company context (back to pure platform-admin scope)
Responses
StatusDescription
200Context cleared
403Not a workspace admin
Example response (200)
{
  "ok": false
}
GET/platforms/{platformId}/api-keys
List a platform's API keys (metadata only: never the secret)

Workspace (platform) admin only. Returns active (non-revoked) keys with id, label, createdAt and lastUsedAt, plus any operator-provisioned environment keys (source:"env") — identity only, no dates, and no API revocation (remove them from BANKCONNECTOR_API_KEYS and restart). The raw key is NEVER returned here: it is shown once, at creation.

Parameters
NameInRequiredDescription
platformId stringpathyes
Responses
StatusDescription
200API keys (no secret)
403Not a workspace admin
Example response (200)
{
  "items": [
    {
      "id": "string",
      "label": "string",
      "source": "db",
      "createdAt": "2026-01-01T00: 00: 00Z",
      "lastUsedAt": "2026-01-01T00: 00: 00Z"
    }
  ],
  "nextCursor": "string"
}
POST/platforms/{platformId}/api-keys
Create an API key: the raw key is returned ONCE

Workspace (platform) admin only. Mints a new platform API key; the raw key value appears ONLY in this 201 response and is never stored or retrievable again. Store it securely.

Parameters
NameInRequiredDescription
platformId stringpathyes
Request body required
PropertyTypeRequiredDescription
labelstringyesHuman name, e.g. "Production ERP".
Example
{
  "label": "string"
}
Responses
StatusDescription
201Key created: raw key shown once
400Invalid request
403Not a workspace admin
Example response (201)
{
  "id": "string",
  "key": "string",
  "label": "string",
  "createdAt": "2026-01-01T00: 00: 00Z"
}
DELETE/platforms/{platformId}/api-keys/{keyId}
Revoke an API key

Workspace (platform) admin only. Soft-revokes the key (it stays for audit but stops authenticating immediately).

Parameters
NameInRequiredDescription
platformId stringpathyes
keyId stringpathyes
Responses
StatusDescription
200Revoked
403Not a workspace admin
404Unknown key for this platform

Tenancy

PATCH/platforms/{platformId}/companies/{companyId}
Update a company (rename / sandboxOnly flag) — workspace admin

Partial update: name renames the company; sandboxOnly flips the pilot safety flag (a sandbox-only company can never activate a production connection or deliver a production payment). Platform-admin only.

Parameters
NameInRequiredDescription
platformId stringpathyes
companyId stringpathyes
Request body required
PropertyTypeRequiredDescription
namestringno
sandboxOnlybooleanno
Example
{
  "name": "string",
  "sandboxOnly": false
}
Responses
StatusDescription
200Updated company
400Nothing to update
403Not a workspace admin
GET/platforms/{platformId}/approval-settings
Read the platform's approval-governance settings
Parameters
NameInRequiredDescription
platformId stringpathyes
Responses
StatusDescription
200Approval settings
PATCH/platforms/{platformId}/approval-settings
Patch the platform's approval-governance settings

Sanitised partial patch of approvalMode / forbidSelfApproval / externalApprovalAuthority. Unknown fields are stripped; an empty effective patch is a 400.

Parameters
NameInRequiredDescription
platformId stringpathyes
Request body required
Responses
StatusDescription
200Updated settings
400Nothing to update
PATCH/users/{id}/settings
Update a user's settings blob (partial)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
settingsobjectyes
Example
{
  "platformId": "string",
  "companyId": "string",
  "settings": {}
}
Responses
StatusDescription
200Updated user
PUT/users/{id}/roles
Replace a user's role set

PUT = full replacement of the role array (there is no partial role patch).

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
PropertyTypeRequiredDescription
platformIdstringyes
companyIdstringyes
rolesstring[]yes
Example
{
  "platformId": "string",
  "companyId": "string",
  "roles": [
    "string"
  ]
}
Responses
StatusDescription
200Updated user
POST/users/{id}/deactivate
Deactivate a user (command — keeps data, revokes access)

A state command, deliberately POST (ADR-0011 keeps commands as POST): keeps PII for audit, revokes live sessions, and reports approval-quorum impact.

Parameters
NameInRequiredDescription
id stringpathyes
Request body required
Responses
StatusDescription
200User deactivated
POST/users/{id}/reinvite
Re-send a user's invite (command)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
Responses
StatusDescription
200Invite re-sent
POST/users/{id}/reset-password
Trigger a password reset for a user (command)
Parameters
NameInRequiredDescription
id stringpathyes
Request body required
Responses
StatusDescription
200Reset issued