API mocks

On this page

Bre-B participant node (Colombia)

Bre-B is Colombia's instant payment rail. A business reaches it through its bank's participant node, and it uses the node to:

  • register dynamic-QR payment requests;
  • ask what happened to them;
  • receive a signed notification for every credit to its business llave.

This mock is such a node for one business customer. It also plays the payer's bank: a test page pays or refuses a request, and a fixture sends a llave transfer without a QR.

Nodes publish their APIs to their customers under contract, and none is public. So this mock defines a neutral REST contract with what any node provides, in the rail's ISO 20022 vocabulary: ACSC settled, PDNG pending, RJCT rejected. Your adapter maps it to your bank's API. Testlie is not affiliated with Banco de la República or any participant, no money moves, and no bank is contacted.

Connect

Create a Bre-B participant node under Banking and set its webhook URL (for example https://<your app>/api/webhooks/breb). Send Authorization: Bearer <API key> on every call.

Credential Environment variable Use
API key BREB_NODE_API_KEY Bearer token
Business llave type and value BREB_BUSINESS_LLAVE_TYPE, BREB_BUSINESS_LLAVE The llave credited, e.g. ALPHANUMERIC @testlie123456; payment requests must name it
Notification signing key (hex) BREB_NODE_WEBHOOK_KEY HMAC-SHA256 key, as 32 bytes in hex, that signs each notification

Errors are { "code", "message" }: UNAUTHORIZED (401), INVALID_BODY (400), LLAVE_NOT_OWNED and ALREADY_EXPIRED (422), NOT_FOUND (404), ALREADY_PAID (409).

API

Call
POST /v1/payment-requests { reference (≤ 35), amountMinor, currency: "COP", llave: { type, value }, expiresAt }. Returns 201 with qrTransactionId (the QR's tag 90, 19 characters), qrSecurityHash (tag 91, SHA-256, base64url), status: "PDNG" and payUrl.
GET /v1/payment-requests/{qrTransactionId} `{ state: "paid"
GET /v1/transfers?qrTransactionId= or ?reference= { data: [...] }: the credits for a request (refused ones included) or a reference, newest first
GET /v1/transfers/{transferId} One credit, with the notification's fields
POST /__testlie/credits The payer's bank sends a credit: { reference, amountMinor, status?, qrTransactionId?, debtorAgent?, reasonCode? }. Leave out qrTransactionId for a llave transfer whose reference is, for example, a subscriber's account number.

payUrl opens the simulated payer's bank. Pick a test bank (TESTBANK01, TESTBANK02 or TESTWALLET, which becomes the debtorAgent), then choose Pay, or Insufficient funds (RJCT AM04).

Credit notifications

Every credit is POSTed to the webhook URL as the node's envelope, Content-Type: application/json:

json
{ "payload": "{\"transferId\":\"TX…\",\"endToEndId\":\"E…\",\"qrTransactionId\":\"T…\",\"reference\":\"INV-1001\",\"amountMinor\":5000000,\"currency\":\"COP\",\"status\":\"ACSC\",\"creditorLlave\":\"@testlie123456\",\"settledAt\":\"2026-10-27T10:00:00.000Z\",\"debtorAgent\":\"TESTBANK01\"}",
  "signature": "<hex HMAC-SHA256 of payload under the signing key>", "scheme": "hmac-sha256" }

payload is the exact JSON string that was signed: verify the signature over those bytes, then parse it. Its fields:

  • transferId (TxId) and endToEndId;
  • qrTransactionId, which is null for a llave transfer;
  • reference, amountMinor (minor units) and currency;
  • status;
  • creditorLlave, the business llave;
  • settledAt;
  • debtorAgent, the paying participant's code, never the payer's account.

The webhook scenarios apply: delay, drop, duplicate, and bad signature (signed with another key). Failed deliveries are retried.

Scenarios

Outcome Credits
Auto / succeed As asked: the page's choice, or the fixture's status (default ACSC)
Decline RJCT, with the chosen reason code (AM04, AC06, AB05, FF01, MS03)
Requires action PDNG at once, then ACSC after the mock's async delay. Both notifications are sent, and status queries follow.