# Connections & credentials

A connection is how a merchant POS system authenticates to BaxPay. One per till or pump lane,
scoped to exactly what it needs.

Create connections with your API key, or from the Business dashboard under **Developers →
Connections**. Each connection issues a bearer credential (`bxc_…`) used on every in-store
[Session API](https://developers.baxpay.com/terminal-api) call. A connection created with a `bx_test_` key is a test
connection, and only ever opens test sessions.

> **Looking for Pennylane / QuickBooks / Sage?**
> Catalog sync with accounting software is under **Developers → Accounting**, documented in
> [Accounting & ERP sync](https://developers.baxpay.com/accounting). Do not create an ERP link on the Connections page.

## Anatomy of a connection

- `label` (required):
  A name you'll recognise later, 2–120 characters: `Lane 4`, `Pump 3 controller`.
- `systemType` (required):
  `ECR` · `FORECOURT` · `ECOMMERCE`: what's on the other end. (`ERP` is provisioned from
  [Accounting](https://developers.baxpay.com/accounting).)
- `terminalId`:
  The BaxPay terminal this connection's sessions go to. Without it, sessions are created but no
  terminal picks them up, so only the sandbox `simulate` call can complete them.
- `protocol`:
  `NATIVE` (default) · `NEXO` · `OPI` · `IFSF`: which message dialect it speaks. Anything other than
  `NATIVE` is routed through the matching adapter.
- `topology`:
  `LOCAL` (default: you poll for the result) or `CLOUD` (we POST it to your `callbackUrl`).
- `callbackUrl` (cloud only):
  Where signed session results are delivered. A `CLOUD` connection without one is refused with
  `403`.
- `saleSystemId · poiId` (nexo):
  Identifiers your nexo estate already uses for the sale system and the point of interaction.

## Provisioning

- `POST /connections` — with your API key
- `GET /connections` — list this mode's connections
- `DELETE /connections/{id}` — revoke (204)

```bash
curl -X POST https://sandbox-api.baxpay.com/v1/connections \
  -H "Authorization: Bearer $BAXPAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Lane 4",
    "systemType": "ECR",
    "terminalId": "TERM-PARIS-04"
  }'
```

```js
const res = await fetch('https://sandbox-api.baxpay.com/v1/connections', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.BAXPAY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    label: 'Head office (cloud)',
    systemType: 'ECR',
    topology: 'CLOUD',
    callbackUrl: 'https://pos.mystore.com/baxpay',
  }),
});
const body = await res.json();
if (!res.ok) throw new Error(JSON.stringify(body));

// Visible exactly once: persist both now.
// body.data.credential      → bxc_…   (your till sends it on every call)
// body.data.callbackSecret  → whsec_… (verifies our callbacks; cloud only)
console.log(JSON.stringify(body, null, 2));
```

```json
{
  "success": true,
  "data": {
    "connectionId": "358f1a7a-…",
    "credential": "bxc_hwsOcP3Y65z9G1X4…"
  }
}
```

A `CLOUD` connection's response also carries `callbackSecret`.

> **Shown once**
> `credential` appears in this response and nowhere else; BaxPay stores only its hash, so it can't
> be recovered. `callbackSecret` is also shown only once. If either is lost, revoke the connection
> and create a new one.

A cloud connection gets its result pushed. Open a sale on the cloud connection and, in sandbox,
approve it: the signed callback reaches `callbackUrl`.

```bash
SESSION=$(curl -s -X POST https://sandbox-api.baxpay.com/v1/integration/sessions \
  -H "Authorization: Bearer bxc_hwsOcP3Y65z9G1X4…" -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "saleReferenceId": "cloud-receipt-1", "amountMinor": 990 }' | jq -r .data.sessionId)

curl -X POST "https://sandbox-api.baxpay.com/v1/integration/sessions/$SESSION/simulate" \
  -H "Authorization: Bearer bxc_hwsOcP3Y65z9G1X4…" -H "Content-Type: application/json" \
  -d '{ "outcome": "APPROVED" }'
```

## Using and revoking

Send the credential as a bearer token on every in-store call:

```text
Authorization: Bearer bxc_hwsOcP3Y65z9G1X4…
```

To rotate, create the new connection first, cut the till over to it, then revoke the old one, in
that order, so no lane is ever without a working credential.

```bash
curl https://sandbox-api.baxpay.com/v1/connections \
  -H "Authorization: Bearer $BAXPAY_API_KEY"
```

Newest first:

```json
{
  "success": true,
  "data": [
    {
      "id": "9c41d0e2-…",
      "label": "Head office (cloud)",
      "livemode": false,
      "systemType": "ECR",
      "protocol": "NATIVE",
      "topology": "CLOUD",
      "status": "ACTIVE",
      "terminalId": null,
      "callbackUrl": "https://pos.mystore.com/baxpay",
      "createdAt": "2026-07-16T14:00:00.000Z"
    }
  ]
}
```

```bash
curl -X DELETE https://sandbox-api.baxpay.com/v1/connections/358f1a7a-… \
  -H "Authorization: Bearer $BAXPAY_API_KEY"
```

Revocation is immediate: the next call with that credential gets `401`.

> **How finely should you scope?**
> One connection per lane or pump lets you cut off a single till without touching the others.
> Note that any of your connections can read and void any session of yours in its mode, so a leaked
> credential still means revoking it quickly.

## Related

- [Accounting & ERP sync](https://developers.baxpay.com/accounting): Pennylane, QuickBooks, Sage, catalog webhooks
- [Terminal & Session API](https://developers.baxpay.com/terminal-api): drive payments with the connection credential
- [Authentication](https://developers.baxpay.com/authentication): `bx_` vs `bxc_` overview
