# Bre-B transaction

Provision a reusable Bre-B Llave, then process online Bre-B payouts using Pay by Bank.

## Overview

Bre-B deposits don't use a standard transaction initiation request. Instead, you provision a reusable Bre-B Llave once per shopper, display the `brebKey` from that response to the shopper as the destination they should pay to, and the shopper transfers funds from their own banking app. PXP creates the deposit when the processor notifies it, and sends you the `breb-transaction-order-executed` webhook as your first and authoritative notice of the deposit.

You can submit a Bre-B payout (withdrawal) in these ways:

- **By bank account number:** Supply the already provisioned Llave (including the `@` prefix). Use this for the first payout, and you can keep using it on later payouts if you prefer. Capture `fundingData.payByBank.gatewayTokenId` from the response to reuse the destination later.
- **By gateway token:** Supply `gatewayTokenId` from an earlier accepted payout instead of resending the Llave.


Bre-B supports `COP` only. Provision and payout requests use Colombian shopper identity details (`country` / `countryCode` `CO` in the examples below). Treat merchant webhooks as the authoritative final outcome. There's no hosted redirect step for Bre-B, and Bre-B doesn't support alias updates. [Learn more about webhooks](/guides/get-started/about-webhooks).

## Provision a Bre-B Llave

/v1/transaction-contexts

Use the following request to provision a reusable Bre-B Llave for a shopper. The call creates no transaction. Set `apmProvider` to `Breb`.

```json
{
  "merchant": "MERCHANT-1",
  "site": "SITE-1",
  "apmProvider": "Breb",
  "shopperId": "Shopper_CO_01",
  "userName": "juan.perez",
  "email": "juan.perez@example.com",
  "firstName": "Juan",
  "lastName": "Perez",
  "phoneNumber": "3001234567",
  "country": "CO",
  "documentType": "IdentityDocument",
  "documentNumber": "1234567890"
}
```

| Parameter | Description |
|  --- | --- |
| `merchant`string (≤ 20 characters) | Your unique merchant identifier, as assigned by PXP. |
| `site`string (≤ 20 characters) | Your unique site identifier, as assigned by PXP. |
| `apmProvider`string | The APM provider for this provision request. For Bre-B, this must be `Breb`. |
| `shopperId`string | Your unique identifier for this shopper. |
| `userName`string (3-50 characters) | The shopper's username for Bre-B provision. |
| `email`string (email, 3-50 characters) | The shopper's email address. |
| `firstName`string (3-50 characters) | The shopper's first name. |
| `lastName`string (3-50 characters) | The shopper's last name. |
| `phoneNumber`string (10 characters) | The shopper's phone number. Exactly 10 digits with no country code (e.g., `3001234567`). |
| `country`string (2 characters) | The shopper's country, in ISO 3166-1 alpha-2 format. For Bre-B, use `CO`. |
| `documentType`string | The shopper identity document type.Possible values:- `IdentityDocument`
- `Passport`
- `TaxIdNumber`
- `ForeignResidentCard`
- `CivilRegisterId`

 |
| `documentNumber`string | The shopper identity document number. It must match Colombia format rules for the chosen `documentType`:- `IdentityDocument` and `TaxIdNumber`: 1-10 digits
- `ForeignResidentCard`: 6-7 digits
- `Passport`: 1-12 alphanumeric
- `CivilRegisterId`: 10 digits

 |


### Response example

If your request is successful, you'll receive a `200` response with `status` set to `Success`. Show the `brebKey` to the shopper. `isEligibleForWithdrawal` is always returned: it's `false` immediately after provision and becomes `true` after a successful pay-in. On failure, `status` is `Error` and `stateData` carries the mapped fault detail. `brebKey` and `provisionedAt` are omitted when they don't apply.

```json
{
  "transactionContextId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "brebKey": "@pxpshopper01",
  "provisionedAt": "2026-08-28T12:00:00Z",
  "isEligibleForWithdrawal": false,
  "status": "Success"
}
```

After you display the Llave, don't call any API when the shopper deposits. Wait for the `breb-transaction-order-executed` webhook, which creates and confirms the deposit. Deposit notifications may have a null `merchantTransactionId` because there was no merchant create call.

## Initiate a Bre-B payout

/v1/transactions

### Request examples

Payout (bank account number)
Use the following request to start a Bre-B withdrawal when you supply the already provisioned destination Llave. The shopper must be eligible for withdrawal (`isEligibleForWithdrawal` is `true` after a successful pay-in). Don't also send `gatewayTokenId`. Capture `fundingData.payByBank.gatewayTokenId` from the response so you can reuse the same destination later.

```json
{
  "merchant": "MERCHANT-1",
  "site": "SITE-1",
  "merchantTransactionId": "BREB-PAYOUT-001",
  "merchantTransactionDate": "2026-08-28T12:00:00Z",
  "transactionMethod": {
    "intent": "Payout",
    "entryType": "Ecom",
    "fundingType": "PayByBank"
  },
  "fundingData": {
    "payByBank": {
      "apmProvider": "Breb",
      "bankAccountNumber": "@pxpshopper01"
    }
  },
  "amounts": {
    "transaction": 100.00,
    "currencyCode": "COP"
  },
  "shopper": {
    "id": "Shopper_CO_01",
    "firstName": "Juan",
    "lastName": "Perez",
    "email": "juan.perez@example.com",
    "countryCode": "CO",
    "documentType": "IdentityDocument",
    "documentNumber": "1234567890"
  }
}
```

| Parameter | Description |
|  --- | --- |
| `merchant`string (≤ 20 characters) | Your unique merchant identifier, as assigned by PXP. |
| `site`string (≤ 20 characters) | Your unique site identifier, as assigned by PXP. |
| `merchantTransactionId`string (≤ 50 characters) | A unique identifier for this transaction. |
| `merchantTransactionDate`date-time | The date and time when the transaction happened, in ISO 8601 format. |
| `transactionMethod`object | Details about the transaction method. |
| `transactionMethod.entryType`string | The entry type. For e-commerce Bre-B transactions, this is always `Ecom`. |
| `transactionMethod.fundingType`string | The funding type. For Bre-B, this is always `PayByBank`. |
| `transactionMethod.intent`string | The payment intent. For a Bre-B withdrawal, set this to `Payout`. Purchase create isn't supported for Bre-B on this endpoint. [Learn more about intents](/guides/transactions/how-it-works#intents). |
| `amounts`object | Details about the transaction amount. |
| `amounts.transaction`number | The transaction amount. The numbers after the decimal will be zero padded if they are less than the expected `currencyCode` exponent. For example, GBP 1.1 = GBP 1.10, EUR 1 = EUR 1.00, or BHD 1.3 = 1.300. The transaction will be rejected if numbers after the decimal are greater than the expected `currencyCode` exponent (e.g., GBP 1.234), or if a decimal is supplied when the `currencyCode` exponent does not require it (e.g., JPY 1.0). |
| `amounts.currencyCode`string (1-3 characters) | The currency code associated with the transaction, in ISO 4217 format. For Bre-B, this must be `COP`. |
| `fundingData`object | Details about the payment method used for the transaction. For Bre-B, use the Pay by bank funding shape only. |
| `fundingData.payByBank`object | Pay by bank funding details for Bre-B. |
| `fundingData.payByBank.apmProvider`string | The APM provider. For Bre-B, this must be `Breb`. |
| `fundingData.payByBank.bankAccountNumber`string (6-21 characters) | The destination Bre-B Llave, including the `@` prefix. Required when `gatewayTokenId` isn't supplied. Use the `brebKey` returned when you provisioned the shopper. Treat as sensitive. |
| `shopper`object | Details about the shopper receiving the payout. Include `id`, `email`, `firstName`, `lastName`, `countryCode`, `documentType`, and `documentNumber`. |
| `shopper.countryCode`string (2 characters) | The shopper's country, in ISO 3166-1 alpha-2 format. For Bre-B, use `CO`. |
| `shopper.documentType`string | The shopper identity document type.Possible values:- `IdentityDocument`
- `Passport`
- `TaxIdNumber`
- `ForeignResidentCard`
- `CivilRegisterId`

 |
| `shopper.documentNumber`string | The shopper identity document number. It must match Colombia format rules for the chosen `documentType`. |


Payout (gateway token)
Use the following request to start a Bre-B withdrawal when you already have a `gatewayTokenId` from an earlier accepted payout. You don't need to resend the Llave.

```json
{
  "merchant": "MERCHANT-1",
  "site": "SITE-1",
  "merchantTransactionId": "BREB-PAYOUT-002",
  "merchantTransactionDate": "2026-08-28T12:00:00Z",
  "transactionMethod": {
    "intent": "Payout",
    "entryType": "Ecom",
    "fundingType": "PayByBank"
  },
  "fundingData": {
    "payByBank": {
      "apmProvider": "Breb",
      "gatewayTokenId": "b6e2f1a4-c3d8-4f7a-b1e9-d2c3f4a5b6c7"
    }
  },
  "amounts": {
    "transaction": 100.00,
    "currencyCode": "COP"
  },
  "shopper": {
    "id": "Shopper_CO_01",
    "firstName": "Juan",
    "lastName": "Perez",
    "email": "juan.perez@example.com",
    "countryCode": "CO",
    "documentType": "IdentityDocument",
    "documentNumber": "1234567890"
  }
}
```

| Parameter | Description |
|  --- | --- |
| `merchant`string (≤ 20 characters) | Your unique merchant identifier, as assigned by PXP. |
| `site`string (≤ 20 characters) | Your unique site identifier, as assigned by PXP. |
| `merchantTransactionId`string (≤ 50 characters) | A unique identifier for this transaction. |
| `merchantTransactionDate`date-time | The date and time when the transaction happened, in ISO 8601 format. |
| `transactionMethod`object | Details about the transaction method. |
| `transactionMethod.entryType`string | The entry type. For e-commerce Bre-B transactions, this is always `Ecom`. |
| `transactionMethod.fundingType`string | The funding type. For Bre-B, this is always `PayByBank`. |
| `transactionMethod.intent`string | The payment intent. For a Bre-B withdrawal, set this to `Payout`. Purchase create isn't supported for Bre-B on this endpoint. [Learn more about intents](/guides/transactions/how-it-works#intents). |
| `amounts`object | Details about the transaction amount. |
| `amounts.transaction`number | The transaction amount. The numbers after the decimal will be zero padded if they are less than the expected `currencyCode` exponent. For example, GBP 1.1 = GBP 1.10, EUR 1 = EUR 1.00, or BHD 1.3 = 1.300. The transaction will be rejected if numbers after the decimal are greater than the expected `currencyCode` exponent (e.g., GBP 1.234), or if a decimal is supplied when the `currencyCode` exponent does not require it (e.g., JPY 1.0). |
| `amounts.currencyCode`string (1-3 characters) | The currency code associated with the transaction, in ISO 4217 format. For Bre-B, this must be `COP`. |
| `fundingData`object | Details about the payment method used for the transaction. For Bre-B, use the Pay by bank funding shape only. |
| `fundingData.payByBank`object | Pay by bank funding details for Bre-B. |
| `fundingData.payByBank.apmProvider`string | The APM provider. For Bre-B, this must be `Breb`. |
| `fundingData.payByBank.gatewayTokenId`string | The reference to a stored PXP payment account for the destination Llave. Required when `bankAccountNumber` isn't supplied. Use the `fundingData.payByBank.gatewayTokenId` value from an earlier accepted Bre-B payout response. |
| `shopper`object | Details about the shopper receiving the payout. Include `id`, `email`, `firstName`, `lastName`, `countryCode`, `documentType`, and `documentNumber`. |
| `shopper.countryCode`string (2 characters) | The shopper's country, in ISO 3166-1 alpha-2 format. For Bre-B, use `CO`. |
| `shopper.documentType`string | The shopper identity document type.Possible values:- `IdentityDocument`
- `Passport`
- `TaxIdNumber`
- `ForeignResidentCard`
- `CivilRegisterId`

 |
| `shopper.documentNumber`string | The shopper identity document number. It must match Colombia format rules for the chosen `documentType`. |


### Response example

If your request is successful, you'll receive a `200` response. For a successful Bre-B payout initiation, expect a `Pending` state with no `redirectUrl`, plus `fundingData.payByBank.paymentId` and `fundingData.payByBank.gatewayTokenId`.

The final outcome is delivered by a Bre-B merchant webhook (e.g., `breb-transaction-order-executed`). [See *Webhooks* below](#webhooks).

Always use the `systemTransactionId` for later PXP API calls against the same transaction. Provider payment identifiers are for reconciliation and support only.

```json
{
  "state": "Pending",
  "systemTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b",
  "merchantTransactionId": "BREB-PAYOUT-001",
  "fundingData": {
    "payByBank": {
      "apmProvider": "Breb",
      "paymentId": "7c1d8e32-4a6b-4f9c-b2d3-1e2f3a4b5c6d",
      "gatewayTokenId": "b6e2f1a4-c3d8-4f7a-b1e9-d2c3f4a5b6c7"
    }
  }
}
```

Bre-B deposits support a full refund only. Refund against the pay-in `systemTransactionId` with `operation` set to `Refund`, `fundingType` set to `PayByBank`, and `apmProvider` set to `Breb`. See our standalone [Refund](/guides/transactions/refund) guide for the request shape and response.

## Webhooks

Treat Bre-B merchant webhooks as the authoritative final outcome for deposits, payouts, and refunds. Don't treat the transaction initiation response alone as settlement for a payout.

Use `transactionMethod.intent` to tell deposits (`Purchase`) and payouts (`Payout`) apart when they share the same event code. For deposits, `breb-transaction-order-executed` is your first notice of the transaction, so `merchantTransactionId` may be `null`. Correlate deposits by using `systemTransactionId` and the shopper's Bre-B context. Deposit notifications include `fundingData.alias` and `fundingData.payByBank.bankOwnershipDetails`.

The following event codes apply to Bre-B:

| Event code  | State | Description  |
|  --- | --- | --- |
| `breb-transaction-order-executed` | `Authorised` | A Bre-B deposit or payout has reached a successful terminal state. For deposits, this is the first notice of the transaction. |
| `breb-transaction-order-declined` | `Refused` | A Bre-B payout was declined. |
| `breb-transaction-order-expired` | `Expired` | A Bre-B payout expired. |
| `breb-transaction-order-failed` | `Refused` | A Bre-B payout failed. |
| `breb-transaction-order-refunded` | `Refunded` | A Bre-B refund was confirmed. |
| `breb-transaction-order-rejected` | `Rejected` | A Bre-B payout was rejected. |
| `breb-transaction-order-cross-entry` | `Refused` | A Bre-B payout was refused because of a cross-entry outcome. |


### Examples

Authorised
A successful Bre-B deposit (`Purchase`) or payout (`Payout`) uses `breb-transaction-order-executed` with state `Authorised`.

Deposit (first notice of the pay-in; `merchantTransactionId` may be `null`):

```json
{
  "eventDate": "2026-08-28T12:00:00.0000000Z",
  "eventCategory": "transaction",
  "eventOwner": {
    "merchantGroup": "merchant-group-1",
    "merchant": "MERCHANT-1",
    "site": "SITE-1"
  },
  "eventData": {
    "eventCode": "breb-transaction-order-executed",
    "state": "Authorised",
    "stateData": {
      "code": "APM003",
      "message": "Payment authorised"
    },
    "amounts": {
      "transaction": 100,
      "currencyCode": "COP"
    },
    "merchant": "MERCHANT-1",
    "site": "SITE-1",
    "transactionMethod": {
      "intent": "Purchase",
      "entryType": "Ecom",
      "fundingType": "PayByBank"
    },
    "fundingData": {
      "payByBank": {
        "apmProvider": "Breb",
        "bankOwnershipDetails": {
          "accountHolderFullName": "Juan Perez",
          "accountNumber": "1234567890",
          "bankName": "Banco de Bogota",
          "beneficiaryAccountNumber": "0987654321"
        }
      },
      "alias": "@pxpshopper01"
    },
    "providerResponse": {
      "provider": "Breb",
      "providerTransactionStatus": "Authorised",
      "providerResponseCode": "EXECUTED",
      "providerResponseMessage": "Payment authorised"
    },
    "merchantTransactionId": null,
    "systemTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b"
  }
}
```

Payout:

```json
{
  "eventDate": "2026-08-28T12:05:00.0000000Z",
  "eventCategory": "transaction",
  "eventOwner": {
    "merchantGroup": "merchant-group-1",
    "merchant": "MERCHANT-1",
    "site": "SITE-1"
  },
  "eventData": {
    "eventCode": "breb-transaction-order-executed",
    "state": "Authorised",
    "stateData": {
      "code": "APM003",
      "message": "Payment authorised"
    },
    "amounts": {
      "transaction": 100,
      "currencyCode": "COP"
    },
    "merchant": "MERCHANT-1",
    "site": "SITE-1",
    "transactionMethod": {
      "intent": "Payout",
      "entryType": "Ecom",
      "fundingType": "PayByBank"
    },
    "fundingData": {
      "payByBank": {
        "apmProvider": "Breb"
      }
    },
    "providerResponse": {
      "provider": "Breb",
      "providerTransactionStatus": "Authorised",
      "providerResponseCode": "EXECUTED",
      "providerResponseMessage": "Payment authorised"
    },
    "merchantTransactionId": "BREB-PAYOUT-001",
    "systemTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b"
  }
}
```

Refused
Declined, failed, and cross-entry payouts resolve to state `Refused`.

Declined (`breb-transaction-order-declined`):

```json
{
  "eventDate": "2026-08-28T12:15:00.0000000Z",
  "eventCategory": "transaction",
  "eventOwner": {
    "merchantGroup": "merchant-group-1",
    "merchant": "MERCHANT-1",
    "site": "SITE-1"
  },
  "eventData": {
    "eventCode": "breb-transaction-order-declined",
    "state": "Refused",
    "stateData": {
      "code": "APM004",
      "message": "Payment declined"
    },
    "amounts": {
      "transaction": 100,
      "currencyCode": "COP"
    },
    "merchant": "MERCHANT-1",
    "site": "SITE-1",
    "transactionMethod": {
      "intent": "Payout",
      "entryType": "Ecom",
      "fundingType": "PayByBank"
    },
    "fundingData": {
      "payByBank": {
        "apmProvider": "Breb"
      }
    },
    "providerResponse": {
      "provider": "Breb",
      "providerTransactionStatus": "Refused",
      "providerResponseCode": "DECLINED",
      "providerResponseMessage": "Payment declined"
    },
    "merchantTransactionId": "BREB-PAYOUT-001",
    "systemTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b"
  }
}
```

Failed (`breb-transaction-order-failed`):

```json
{
  "eventDate": "2026-08-28T12:25:00.0000000Z",
  "eventCategory": "transaction",
  "eventOwner": {
    "merchantGroup": "merchant-group-1",
    "merchant": "MERCHANT-1",
    "site": "SITE-1"
  },
  "eventData": {
    "eventCode": "breb-transaction-order-failed",
    "state": "Refused",
    "stateData": {
      "code": "APM012",
      "message": "Payment failed"
    },
    "amounts": {
      "transaction": 100,
      "currencyCode": "COP"
    },
    "merchant": "MERCHANT-1",
    "site": "SITE-1",
    "transactionMethod": {
      "intent": "Payout",
      "entryType": "Ecom",
      "fundingType": "PayByBank"
    },
    "fundingData": {
      "payByBank": {
        "apmProvider": "Breb"
      }
    },
    "providerResponse": {
      "provider": "Breb",
      "providerTransactionStatus": "Refused",
      "providerResponseCode": "FAILED",
      "providerResponseMessage": "Payment failed"
    },
    "merchantTransactionId": "BREB-PAYOUT-001",
    "systemTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b"
  }
}
```

Cross-entry (`breb-transaction-order-cross-entry`):

```json
{
  "eventDate": "2026-08-28T12:40:00.0000000Z",
  "eventCategory": "transaction",
  "eventOwner": {
    "merchantGroup": "merchant-group-1",
    "merchant": "MERCHANT-1",
    "site": "SITE-1"
  },
  "eventData": {
    "eventCode": "breb-transaction-order-cross-entry",
    "state": "Refused",
    "stateData": {
      "code": "APM004",
      "message": "Payment declined"
    },
    "amounts": {
      "transaction": 100,
      "currencyCode": "COP"
    },
    "merchant": "MERCHANT-1",
    "site": "SITE-1",
    "transactionMethod": {
      "intent": "Payout",
      "entryType": "Ecom",
      "fundingType": "PayByBank"
    },
    "fundingData": {
      "payByBank": {
        "apmProvider": "Breb"
      }
    },
    "providerResponse": {
      "provider": "Breb",
      "providerTransactionStatus": "Refused",
      "providerResponseCode": "CROSS_ENTRY",
      "providerResponseMessage": "Payment declined"
    },
    "merchantTransactionId": "BREB-PAYOUT-001",
    "systemTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b"
  }
}
```

Expired
An expired Bre-B payout uses `breb-transaction-order-expired` with state `Expired`.

```json
{
  "eventDate": "2026-08-28T12:20:00.0000000Z",
  "eventCategory": "transaction",
  "eventOwner": {
    "merchantGroup": "merchant-group-1",
    "merchant": "MERCHANT-1",
    "site": "SITE-1"
  },
  "eventData": {
    "eventCode": "breb-transaction-order-expired",
    "state": "Expired",
    "stateData": {
      "code": "APM011",
      "message": "Payment expired"
    },
    "amounts": {
      "transaction": 100,
      "currencyCode": "COP"
    },
    "merchant": "MERCHANT-1",
    "site": "SITE-1",
    "transactionMethod": {
      "intent": "Payout",
      "entryType": "Ecom",
      "fundingType": "PayByBank"
    },
    "fundingData": {
      "payByBank": {
        "apmProvider": "Breb"
      }
    },
    "providerResponse": {
      "provider": "Breb",
      "providerTransactionStatus": "Expired",
      "providerResponseCode": "EXPIRED",
      "providerResponseMessage": "Payment expired"
    },
    "merchantTransactionId": "BREB-PAYOUT-001",
    "systemTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b"
  }
}
```

Refunded
A confirmed Bre-B refund uses `breb-transaction-order-refunded` with state `Refunded`.

```json
{
  "eventDate": "2026-08-28T12:30:00.0000000Z",
  "eventCategory": "transaction",
  "eventOwner": {
    "merchantGroup": "merchant-group-1",
    "merchant": "MERCHANT-1",
    "site": "SITE-1"
  },
  "eventData": {
    "eventCode": "breb-transaction-order-refunded",
    "state": "Refunded",
    "stateData": {
      "code": "APM007",
      "message": "Payment refunded"
    },
    "amounts": {
      "transaction": 100,
      "currencyCode": "COP"
    },
    "merchant": "MERCHANT-1",
    "site": "SITE-1",
    "transactionMethod": {
      "intent": "Refund",
      "entryType": "Ecom",
      "fundingType": "PayByBank"
    },
    "fundingData": {
      "payByBank": {
        "apmProvider": "Breb"
      }
    },
    "providerResponse": {
      "provider": "Breb",
      "providerTransactionStatus": "Refunded",
      "providerResponseCode": "REFUNDED",
      "providerResponseMessage": "Payment refunded"
    },
    "merchantTransactionId": "BREB-RFD-001",
    "systemTransactionId": "3ab45678-cdef-9012-3456-789abcdef012"
  }
}
```

Rejected
A rejected Bre-B payout uses `breb-transaction-order-rejected` with state `Rejected`.

```json
{
  "eventDate": "2026-08-28T12:35:00.0000000Z",
  "eventCategory": "transaction",
  "eventOwner": {
    "merchantGroup": "merchant-group-1",
    "merchant": "MERCHANT-1",
    "site": "SITE-1"
  },
  "eventData": {
    "eventCode": "breb-transaction-order-rejected",
    "state": "Rejected",
    "stateData": {
      "code": "APM013",
      "message": "Payment rejected"
    },
    "amounts": {
      "transaction": 100,
      "currencyCode": "COP"
    },
    "merchant": "MERCHANT-1",
    "site": "SITE-1",
    "transactionMethod": {
      "intent": "Payout",
      "entryType": "Ecom",
      "fundingType": "PayByBank"
    },
    "fundingData": {
      "payByBank": {
        "apmProvider": "Breb"
      }
    },
    "providerResponse": {
      "provider": "Breb",
      "providerTransactionStatus": "Rejected",
      "providerResponseCode": "REJECTED",
      "providerResponseMessage": "Payment rejected"
    },
    "merchantTransactionId": "BREB-PAYOUT-001",
    "systemTransactionId": "1ed768bb-e88a-4636-91ae-67927ccbb02b"
  }
}
```

To learn how to set up and process webhooks, see [Manage webhooks](/guides/get-started/manage-webhooks).

## Testing

### How it works

In your sandbox environment, you can use the Bre-B simulator to test provisioning, deposits, payouts, and refunds without contacting the real provider or moving real money. You choose the outcome by using specific `SIM-` values when you provision a shopper (for payouts) or when you initiate a refund. Deposits always resolve to `Authorised`. Payout and refund outcomes are applied automatically about 10 seconds after you initiate them. There's no simulator UI or manual callback endpoint.

Payout requests use the same shapes as production: either send the provisioned Llave as `bankAccountNumber`, or supply `gatewayTokenId` from an earlier accepted payout. The `SIM-` shopper ID you provision decides which outcome that Llave maps to.

The Bre-B simulator is available only when it's enabled in a sandbox environment. Simulator-only endpoints return `404 Not Found` in production.

To perform an end-to-end test:

1. Provision a simulator shopper with a `shopperId` that starts with `SIM-BREBKEY-`. For a specific payout outcome, use `SIM-BREBKEY-PAYOUT-{OUTCOME}`.
2. Simulate an incoming bank transfer to that shopper. A shopper must receive at least one deposit before any payout to it is accepted.
3. Receive the authorised pay-in webhook.
4. Initiate a payout by sending that shopper's Llave as `bankAccountNumber`.
5. Wait for the matching payout outcome and webhook.
6. Optionally, initiate a full refund of the deposit using a `SIM-REFUND-{OUTCOME}` merchant transaction ID, then wait for the matching refund outcome and webhook.


#### Available provisioning shopper IDs

Use these `shopperId` values when you [provision a Bre-B Llave](#provision-a-bre-b-llave). The `shopperId` decides which Llave is returned and which payout outcome that Llave maps to.

| `shopperId`  | Llave returned  | Payout outcome for that Llave |
|  --- | --- | --- |
| `SIM-BREBKEY-{text}` | `@SIM-{hash}` (stable 12-character hash of the `shopperId`) | `Authorised` (`EXECUTED`) |
| `SIM-BREBKEY-PAYOUT-EXECUTED` | `@SIM-PAYOUT-EXECUTED` | `Authorised` (`EXECUTED`) |
| `SIM-BREBKEY-PAYOUT-DECLINED` | `@SIM-PAYOUT-DECLINED` | `Refused` (`DECLINED`) |
| `SIM-BREBKEY-PAYOUT-FAILED` | `@SIM-PAYOUT-FAILED` | `Refused` (`FAILED`) |
| `SIM-BREBKEY-PAYOUT-EXPIRED` | `@SIM-PAYOUT-EXPIRED` | `Expired` (`EXPIRED`) |
| `SIM-BREBKEY-PAYOUT-REJECTED` | `@SIM-PAYOUT-REJECTED` | `Rejected` (`REJECTED`) |
| `SIM-BREBKEY-PAYOUT-SUSPECT` | `@SIM-PAYOUT-SUSPECT` | Remains `Pending` (`SUSPECT`). No merchant webhook. |
| `SIM-BREBKEY-PAYOUT-PENDING` | `@SIM-PAYOUT-PENDING` | Remains `Pending`. No automatic callback. |
| `SIM-BREBKEY-{text}-ERROR` | None | Provisioning fails synchronously with `status` set to `Error`. No context or Llave is created. |


Use each `SIM-BREBKEY-PAYOUT-{OUTCOME}` value exactly as listed. Don't append extra text: for example, `SIM-BREBKEY-PAYOUT-DECLINED-2` returns a Llave that the simulator doesn't recognise as a named outcome, so payouts to it resolve to `Authorised`. One shopper per merchant and site per outcome is enough. You can send any number of payouts to the same Llave.

Cross-entry, a missing provider payment ID, and a synchronous provider error aren't selectable for payouts.

#### Available refund merchant transaction IDs

When you initiate a full refund of a simulated deposit, set `merchantTransactionId` to one of the following values to select the automatic result. Values that don't start with `SIM-REFUND-` default to `Refunded`.

| `merchantTransactionId`  | Automatic result  | Refund state and webhook |
|  --- | --- | --- |
| `SIM-REFUND-REFUNDED` | `REFUNDED` after ~10 seconds | `Refunded` (`breb-transaction-order-refunded`) |
| `SIM-REFUND-EXECUTED` | `EXECUTED` after ~10 seconds | `Refunded` (`breb-transaction-order-executed`, provider status `EXECUTED`) |
| `SIM-REFUND-DECLINED` | `DECLINED` after ~10 seconds | `Refused` (`breb-transaction-order-declined`) |
| `SIM-REFUND-FAILED` | `FAILED` after ~10 seconds | `Refused` (`breb-transaction-order-failed`) |
| `SIM-REFUND-EXPIRED` | `EXPIRED` after ~10 seconds | `Expired` (`breb-transaction-order-expired`) |
| `SIM-REFUND-REJECTED` | `REJECTED` after ~10 seconds | `Refused` (`breb-transaction-order-rejected`) |
| `SIM-REFUND-PENDING` | No callback job is scheduled | Remains `Pending`. No merchant webhook. |
| `SIM-REFUND-MISSING-PAYMENTID` | Provider-style response has no payment ID | `Refused` immediately. No merchant webhook. |
| `SIM-REFUND-ERROR` | Refund provider call fails synchronously | `Error` immediately. No merchant webhook. |


Use each value exactly as listed. A suffix such as `SIM-REFUND-DECLINED-2`, or an unknown outcome such as `SIM-REFUND-CROSS-ENTRY` or `SIM-REFUND-SUSPECT`, is rejected synchronously with state `Error`.

`SIM-REFUND-REFUNDED`, `SIM-REFUND-EXECUTED`, and `SIM-REFUND-PENDING` work once per merchant and site while an earlier refund with that value is pending or completed. Values whose outcome is a refusal, expiry, or error can be reused after that attempt fails. For repeatable successful refunds, use any ordinary unique `merchantTransactionId`. A `SIM-REFUND-PENDING` refund never completes, so use a dedicated deposit for that test.

### What happens after

#### Provision a simulator shopper

Call the standard [provision endpoint](#provision-a-bre-b-llave) with a `SIM-BREBKEY-` shopper ID. Provisioning is idempotent per merchant, site, and `shopperId`: repeating the request returns the existing context and Llave. It doesn't create a payment or send a webhook. `isEligibleForWithdrawal` is `false` until the shopper receives a deposit.

Retain `transactionContextId` for the deposit request, `brebKey` for payouts that use `bankAccountNumber`, and the original `shopperId` to use as `shopper.id` on payouts.

#### Simulate a deposit

Call the simulator deposit endpoint with the provisioned `transactionContextId`:

/v1/altp-breb-processor/simulator/deposits

```json
{
  "merchant": "MERCHANT-1",
  "site": "SITE-1",
  "transactionContextId": "11111111-1111-1111-1111-111111111111",
  "amount": 25.50,
  "currency": "COP",
  "transferReference": "transfer-001"
}
```

If your request is successful, you'll receive a response with `state` set to `Authorised` and a `systemTransactionId`. The deposit is processed immediately and sends a `breb-transaction-order-executed` merchant webhook. A failed or rejected bank transfer never arrives and therefore doesn't create a pay-in.

`transferReference` is the idempotency key for the simulated bank transfer:

- A new value creates a new deposit.
- Replaying the same value returns the original `systemTransactionId` with `alreadyProcessed` set to `true`.
- An idempotent replay doesn't send another webhook.


#### Initiate a payout

A simulator payout is accepted only when all of the following are true:

- You send exactly one of `bankAccountNumber` or `gatewayTokenId`:
  - `bankAccountNumber` must be exactly the `brebKey` returned when the shopper was provisioned, character for character.
  - `gatewayTokenId` must be from an earlier accepted payout for that Llave. The token resolves to the same Llave and outcome.
- `shopper.id` is the `shopperId` used at provisioning, under the same merchant and site.
- The shopper has received at least one simulated deposit.
- `merchantTransactionId` is unique for the merchant and site. It may be reused only after a previous attempt with that value ended in a refused, error, or expired state.
- `merchantTransactionDate` is within the last 30 days and not more than 2 days in the future.


For every accepted payout, the immediate response is `Pending` and includes the `gatewayTokenId` minted for the Llave. When the encoded outcome is applied, the corresponding merchant webhook is sent. A `SUSPECT` or `PENDING` payout stays `Pending` indefinitely; use a fresh `merchantTransactionId` for the next test.

#### Initiate a refund

Use the pay-in deposit's `systemTransactionId`, not a payout ID or transaction-context ID. Bre-B supports one full refund per pay-in. Partial refunds are rejected. For normal terminal outcomes, the immediate response is `Pending`.

The refund request must also satisfy these checks:

- The pay-in must belong to the same merchant and site and be in state `Authorised`.
- `amounts.transaction` and `currencyCode` must equal the original deposit exactly.
- `merchantTransactionDate` must be within the last 30 days and not more than 2 days in the future.
- Only one pending or completed refund may exist per pay-in; a second refund of the same pay-in is refused unless the earlier attempt failed.


The original pay-in remains the purchase record. The refund has its own `systemTransactionId` and state.