sandbox.bankconnector.com API Reference

Webhooks

BankConnector POSTs signed events to your endpoint as payments move through their lifecycle. This page covers managing and configuring endpoints. For the event envelope, signature verification, retries and the event catalog, see Receiving results. To post into Teams or Slack, see Teams and Slack webhook URLs.

Register an endpoint

curl -X POST https://sandbox.bankconnector.com/api/webhooks \
  -H "X-API-Key: $BC_KEY" -H "Content-Type: application/json" \
  -H "BankConnector-Version: 2026-10-21" \
  -d '{
    "companyId":  "comp_…",
    "url":        "https://erp.example.com/hooks/bankconnector",
    "eventTypes": ["payment.sent", "payment.executed", "payment.rejected"]
  }'

The 201 body has two top-level keys, endpoint and secret. The endpoint id is at endpoint.id (there is no top-level id):

{
  "endpoint": {
    "id": "wh_…", // ← the id you pass to every /api/webhooks/<id>/… route
    "url": "https://erp.example.com/hooks/bankconnector",
    "eventTypes": ["payment.sent", "payment.executed", "payment.rejected"],
    "enabled": true,
    // …
  },
  "secret": "whsec_…", // ← the signing secret, shown ONCE
}

Read the id as body.endpoint.id. body.id is undefined.

FieldRequiredNotes
companyIdrequiredscope: the API key's own company
urlrequiredfor every transport, including slack, teams and email; omitting it is a 400 url_required. Max 2048 chars. It must be a public HTTPS URL, and a redirect is not followed: it counts as a failed attempt
eventTypesoptionalarray of event names. Omit (or send ["*"]) to receive every event in the catalog; an empty [] is rejected with a 400
transportoptional"https" (default), "slack", "teams", or "email"
emailTooptional (email)destination address for the email transport. Omit it and the event is emailed to the company's admins instead
filterPredicateoptionaldeliver only matching events; see Filters

Capture secret on creation: it's the whsec_… HMAC signing key and is shown only once. You verify every delivery against it (see Receiving results).

Unknown fields are rejected with 400 validation_failed.

If webhooks are switched off for your organisation, registration answers 403 capability_disabled and no events are sent. They are on by default for the Direct API; ask support to switch them on.

Filters

filterPredicate takes up to four keys, and an event must match every one you set:

  • bankKey and currency match the event's own bankKey and currency. An event that carries no such field, for example approval.given, never matches and is dropped.
  • minAmount and maxAmount are in EUR. An event in another currency is compared on its EUR equivalent at the cached reference rate, and one with no rate is delivered whatever its amount.

Only approval.needed, payment.double-debit and statement.unmatched-our-reference carry an amount. On any other event type the amount bounds do nothing. If you list eventTypes and none of them carries an amount, a request with minAmount or maxAmount is refused with 400.

{ "eventTypes": ["approval.needed"], "filterPredicate": { "bankKey": "danske-dk", "minAmount": 1000 } }

Managing endpoints

Method & pathWhat it does
GET /api/webhookslist your endpoints (metadata only, never the secret)
GET /api/webhooks/<id>fetch one endpoint
DELETE /api/webhooks/<id>?confirm=<id>remove an endpoint; without ?confirm=<id> the answer is 400 confirmation_required
POST /api/webhooks/<id>/enable, /disableswitch the endpoint on or off. A disabled endpoint receives nothing, and events sent meanwhile are not kept for later
POST /api/webhooks/<id>/testsend one signed webhook.test event; see below
GET /api/webhooks/<id>/deliverieskeyset-paginated delivery attempts (newest first; see Pagination)
POST /api/webhooks/<id>/deliveries/<deliveryId>/redeliverreplay one delivery as a new attempt
POST /api/webhooks/<id>/redeliver-failed?since=<iso>bulk-replay failed deliveries since a timestamp, at most 500 per call; see below
POST /api/webhooks/<id>/re-enableclear an auto-disabled endpoint (see below)
POST /api/webhooks/<id>/rotate-secretrotate the signing secret; body { "overlapHours": 24 } (default 24, clamped 1–72)

Managing webhooks needs an admin session or an API key (for the key's own company).

/test is one synchronous POST that answers { "ok": true } or { "ok": false }. It is never retried, writes no delivery-log row and does not count toward auto-disable. For an email endpoint the test is queued instead and appears in the delivery log.

redeliver-failed answers { "count", "nextCursor" }. If nextCursor is set, call again with &cursor=<nextCursor> for the rest. It also replays events that were skipped because the endpoint was auto-disabled. Deliveries are kept for 30 days, so since reaches back no further than that.

Reliability

  • Delivery is at-least-once, so deduplicate on the event id. Success is any HTTP 2xx; each attempt times out at 10 s.
  • 31 delivery attempts, exponential backoff 30 s → 1 m → 2 m → 4 m → 8 m → 16 m → 32 m → 1 h between them, then a flat 1 h wait for each of the 23 attempts after that, about 1443.5 minutes (roughly 24 hours) end to end (±20% jitter). After the 31st attempt the delivery settles failed; recover it with POST /api/webhooks/<id>/redeliver-failed?since=<iso> or the single-delivery redeliver above.
  • Circuit breaker: after 5 consecutive failed events an endpoint is auto-disabled and stops receiving until you POST /api/webhooks/<id>/re-enable. The webhook.auto-disabled transition is audit-log only (not itself a webhook), so back webhooks with a periodic poll and watch the X-Delivery-Sequence header for gaps.

Secret rotation

POST /api/webhooks/<id>/rotate-secret answers { "webhookId", "newSecret", "overlapUntil" }. The new secret is shown once. The old one stays valid until overlapUntil, which is overlapHours from now. During the overlap, deliveries carry multiple v1= signatures (old and new): accept a match against any of them, then cut over to the new secret. See Receiving results.

Transports

  • HTTPS (default): a signed POST to your url.
  • Slack: set transport: "slack" and make url your Slack incoming-webhook URL.
  • Microsoft Teams: set transport: "teams" and make url your Teams Workflow webhook URL. Each event is posted as a card. Teams and Slack webhook URLs shows how to get either URL.
  • Email: set transport: "email" and (optionally) emailTo; events are formatted as email and go to the company's admins when emailTo is omitted. url is still required, although the email transport doesn't POST to it.