Outgoing Transfer Error Codes
Rejection reasons, state reasons, and handling recommendations for outgoing Bre-B transfers
Errors when creating and processing outgoing transfers fall into two categories depending on when they're surfaced:
- Rejection reasons — validation errors returned synchronously when you create a batch. The rejected transfer is never persisted.
- State reasons — errors that occur during asynchronous processing.
You learn about them via
outgoing_transfer.failedwebhooks, where thestate_reasonfield carries the code.
Rejection reasons
These errors are returned in the rejected_transfers array of the
create outgoing transfers
response. Rejected transfers are not created in the system — no webhook
will fire for them, so you must handle them from the synchronous response.
Example response
{
"id": "batch_123e4567-e89b-12d3-a456-426614174000",
"state": "created",
"transfers": [],
"rejected_transfers": [
{
"external_id": "transfer_001",
"reason": "amount_exceeds_max_limit"
},
{
"external_id": "transfer_002",
"reason": "target_not_found"
}
]
}Code reference
| Code | Description | Cause | Suggested fix |
|---|---|---|---|
amount_not_provided | Amount not provided | The amount field is required but was missing or null. | Include amount with a valid value. |
amount_exceeds_max_limit | Amount exceeds the maximum limit | The transfer amount exceeds the maximum allowed per transaction. | Reduce the amount or split into multiple transfers. |
target_amount_mismatch | Amount does not match the target | When using an existing target_id with a fixed transaction_amount (e.g., a static QR), the sent amount must match exactly. | Send the target's amount, or omit amount to use the target's value. |
target_already_exists | Target already used | An active (non-failed) transfer already uses this target_id. Each target may only be consumed once. | Use a different target or wait for the in-flight transfer to reach a terminal state. |
target_not_found | Target not found | The supplied target_id does not exist or does not belong to the current tenant. | Verify the target_id is correct and owned by your tenant. |
State reasons
These errors occur during asynchronous processing and are delivered via the
outgoing_transfer.failed
webhook, with the machine-readable code in event.data.state_reason.
Example webhook payload
{
"timestamp": "2025-12-17T20:14:01.947520Z",
"event": {
"type": "outgoing_transfer.failed",
"data": {
"id": "bbot_031uOJ6qb0sVclNseQfItQ",
"state": "failed",
"state_reason": "target_creditor_mismatch",
"external_id": "21752385-357e-450f-94a3-d9a0984da291",
"amount": { "currency": "COP", "amount": 100 },
"expected_creditor": {
"document_type": "CC",
"document_number": "21482961"
},
"target": {
"creditor": {
"document_type": "CC",
"document_number": "123143455",
"full_name": "Juan Carlos Perez Gomez"
}
}
}
}
}Key resolution errors
Raised while resolving the recipient's Bre-B key.
| Code | Description | Cause | Suggested fix |
|---|---|---|---|
key_not_found | Key not found | The Bre-B key does not exist in the instant payments system. | Verify the key. The recipient must have a registered key. |
key_suspended | Key suspended | The recipient's Bre-B key is temporarily suspended. | Ask the recipient to regularize their key with their financial institution. |
invalid_key_format | Invalid key format | The key format does not match Bre-B rules. | Verify the format against the key types table. |
Recipient validation errors
Raised when recipient data is invalid or doesn't match the key owner.
| Code | Description | Cause | Suggested fix |
|---|---|---|---|
target_creditor_mismatch | Creditor mismatch | The expected_creditor (document type + number) does not match the actual owner of the Bre-B key. | Verify recipient data before sending. This check prevents transfers to the wrong person. |
creditor_account_not_found | Creditor account not found | The bank account associated with the key no longer exists or was closed. | The recipient should verify the account with their financial institution. |
invalid_creditor_account | Invalid creditor account | The recipient's bank account cannot receive transfers (blocked, inactive, etc.). | The recipient should regularize their bank account. |
Funds errors
Raised during funds-hold.
| Code | Description | Cause | Suggested fix |
|---|---|---|---|
insufficient_funds | Insufficient funds | The source account does not have enough balance to cover the transfer. | Ensure there is available balance before creating the transfer. |
amount_exceeds_balance_limit | Amount exceeds balance limit | The amount would push the recipient beyond their allowed balance limit. | Reduce the transfer amount. |
Provider errors
Raised due to Bre-B provider or upstream issues.
| Code | Description | Cause | Suggested fix |
|---|---|---|---|
risk_control | Rejected by risk control | The transfer was rejected by the provider's risk control system. | Review the transaction patterns. May require contacting support. |
breb_timeout | Bre-B provider timeout | The Bre-B provider did not respond in time. | Retry later. If it persists, contact support. |
provider_unavailable | Provider unavailable | The Bre-B provider is temporarily out of service. | Retry later. |
unknown | Unknown error | An uncategorized error occurred. | Contact technical support with the transfer id. |
Integration recommendations
1. Validate before sending
Before calling the create-transfers endpoint, validate:
- The amount is within the allowed limits.
- Recipient data is correct (if using
expected_creditor). - The source account has sufficient balance.
2. Handle rejected_transfers from the batch response
const response = await createBatch(batchData);
if (response.rejected_transfers.length > 0) {
for (const rejected of response.rejected_transfers) {
console.error(`Transfer ${rejected.external_id} rejected: ${rejected.reason}`);
// Notify the user or flag for review
}
}3. Handle outgoing_transfer.failed webhooks
app.post('/webhook', (req, res) => {
const { event } = req.body;
if (event.type === 'outgoing_transfer.failed') {
const { id, external_id, state_reason } = event.data;
switch (state_reason) {
case 'insufficient_funds':
// Notify the user that funds are missing
break;
case 'target_creditor_mismatch':
// Ask the user to re-verify recipient details
break;
case 'key_not_found':
// Surface that the key is invalid
break;
default:
// Fallback handling
}
}
res.status(200).send();
});4. Retry guidance
| Error | Retryable | Recommendation |
|---|---|---|
breb_timeout | Yes | Retry after 1–5 minutes. |
provider_unavailable | Yes | Retry after 5–15 minutes. |
insufficient_funds | Yes* | Retry once funds are available. |
key_not_found | No | Confirm the recipient's key with the user. |
target_creditor_mismatch | No | Correct the recipient data. |
risk_control | No | Contact support. |
Support
When contacting support about a failed transfer, provide the transfer id (and batch id if
applicable), the external_id for correlation, and a description of the scenario and
frequency.