sandbox.bankconnector.com API Reference

Getting started

Audience: 🔌 Integration Client, 🧑‍💼 Company Admin

This page takes you from nothing to an executed payment in a sandbox: provision, send, read. You only need an email address to receive a code.

The interactive playground provisions a sandbox after you confirm your email and animates the round-trip. This guide is the same flow in curl.

What you'll have after Step 1

POST /api/sandbox/provision emails you a code, and POST /api/sandbox/provision/verify creates an isolated sandbox for you once you send it back: a company, an API key, and an already-active demo bank connection. Two credentials matter (see Authentication for the full model):

  • API key (X-API-Key: key_…), the machine credential for the data plane: submitting payments, reading results, webhooks. It is bound to your sandbox company: you pass that companyId.
  • Admin session, the control plane, for inviting users, issuing API keys and setting up bank connections. The provision call creates no sign-in: sign up at /signup with an email you verify to get one. You don't need it for the payment loop below; see Managing companies & users.

Sandbox tenants are deleted after 30 days of inactivity. Provisioning a new one takes the two calls in Step 1. Each email address holds one live sandbox.

Environments at a glance

Every host runs in one of two postures:

PostureDemo bankAuthUse for
production❌ offclosedlive payments
sandbox✅ onclosed, real keys, TLSintegration testing

The public sandbox.bankconnector.com turns every bank into a simulated Demo Bank (default danske-dk), and real-payment sends are off engine-wide. Separately, each bank connection carries its own environment: test | production flag. A production posture refuses a production connection pointed at a bank's test host.

⚠️ On sandbox.bankconnector.com, real payments can never move. See Going live.

Step 1: Provision a sandbox

Send your email address. Nothing is created yet: BankConnector emails a 6-digit code.

curl -X POST https://sandbox.bankconnector.com/api/sandbox/provision \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com"}'

You get back a 202 with a verificationId (expiresIn is 3600 seconds):

{ "message": "…", "email": "you@example.com", "verificationId": "…", "expiresIn": 3600 }

Send the code with that verificationId:

curl -X POST https://sandbox.bankconnector.com/api/sandbox/provision/verify \
  -H "Content-Type: application/json" \
  -d '{"verificationId":"…","code":"123456"}'

A wrong code answers 422 sandbox_code_invalid with details.attemptsLeft (5 tries, 60 minutes). An address that already has a live sandbox gets 409 sandbox_exists_for_email. You can request at most 3 codes per address per hour. The email also carries a link that opens the sandbox start page with the code filled in.

You get back a 201 with everything you need:

{
  "apiKey":     "key_…",               // data-plane credential (X-API-Key)
  "companyId":  "comp_…",              // the company to act as
  "baseUrl":    "https://sandbox.bankconnector.com",
  "bank":       { "key": "danske-dk", "name": "Danske Bank", "country": "DK" },
  "firstPayment":   { /* a copy-paste-ready first request */ }
}

Export the key so the snippets below can use it:

export BC_KEY="key_…"
export BC_COMPANY="comp_…"

The response's firstPayment object is a ready-to-send request for this bank. Want a different bank? Pass "bankKey":"nordea-dk" in the first call's body (list them with GET /api/profiles).

Step 2: (Optional) Preview a conversion

Validate and convert a canonical payment to XML with no state change and no delivery:

curl -X POST https://sandbox.bankconnector.com/api/journal/payments/preview \
  -H "X-API-Key: $BC_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "companyId": "'"$BC_COMPANY"'",
    "bankKey":   "danske-dk",
    "payment":   { ... see Core concepts for the full object ... }
  }'
# 200 { ..., "xml": "<Document>...</Document>" }

A 200 means the payment is structurally valid and converts cleanly; a 422 returns the exact issues in error.details.issues. Use it to iterate on your payload.

Step 3: Submit a payment

In sandbox this runs the full pipeline (validation, conversion, approval planning, asynchronous delivery to the demo bank) without sending a real payment:

curl -X POST https://sandbox.bankconnector.com/api/journal/payments \
  -H "X-API-Key: $BC_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 2f9a1c7e-order-10432" \
  -d '{
    "companyId":   "'"$BC_COMPANY"'",
    "bankKey":     "danske-dk",
    "environment": "test",
    "payment":     { ... }
  }'
# 201 { "id": "...", "journalNo": "...", "status": "...", "xml": "...", "deliveryMode": "..." }

A 201 means accepted and converted, not yet sent to the bank. The status field tells you what happened next: queued-for-delivery when the payment was released straight to delivery (the sandbox's auto-release default), or pending-approval when an approval policy holds it for a User approver. The journal-document fields (id, journalNo, status, …) come back at the top level alongside xml and deliveryMode.

Step 4: Read the result

The demo bank replies within a few seconds with a real-format pain.002 and camt.053. Read the reconciled state:

curl -H "X-API-Key: $BC_KEY" \
  "https://sandbox.bankconnector.com/api/journal/reconciliation?companyId=$BC_COMPANY"
# status "executed", state "cleared"

GET /api/journal/list?companyId=$BC_COMPANY gives the same as a paged list. See Receiving results for webhooks + polling in depth.

Where to go next