# Webhooks de Pagos (Brasil)

Un **webhook** es una devolución de llamada web que Belvo utiliza para enviar notificaciones sobre un enlace específico.

Este artículo trata sobre webhooks para nuestra solución de Iniciación de Pagos. Para obtener información sobre nuestros webhooks de Agregación y Enriquecimiento, consulta este artículo

## Configurar webhooks

Para configurar un nuevo webhook:

1. En tu panel de control de Belvo, ve a la sección de webhooks de pagos.
2. En la pestaña **Webhooks de Pagos**, haz clic en **+Nuevo webhook**.

3. Completa el formulario de **Nuevo webhook** con la información requerida.
  - **URL**: la URL para recibir las notificaciones del webhook.
  - **Authorization**: un token bearer opcional para usar si tu URL está protegida.
4. Haz clic en **Crear webhook**.

5. Para registrar URLs de webhook adicionales, repite los pasos 2-4 para cada URL que desees agregar.


Múltiples URLs de Webhook
Puedes registrar múltiples URLs de webhook para tu organización. Cuando se registran múltiples URLs, **todas las URLs de webhook registradas recibirán la misma notificación de evento** para cada evento de webhook. Esto te permite enviar notificaciones a diferentes sistemas o entornos simultáneamente.

## Esquemas y Tipos de Webhook

Belvo ofrece dos versiones de esquemas de webhook para los webhooks de Payments Brazil:

- **Versión de Esquema 1**: El formato original de webhook utilizado para los webhooks de CHARGES, ENROLLMENTS, PAYMENT_INTENTS y TRANSACTIONS. Este esquema sigue funcionando para integraciones existentes.
- **Versión de Esquema 2 (Nuevo)**: Un formato de webhook más reciente introducido para una funcionalidad mejorada. Este esquema se utiliza para los webhooks de BANK_ACCOUNTS (V2), CUSTOMERS (V2) y PAYMENT_AUTHORIZATIONS.


Requisitos de la Versión de Esquema 2
Los webhooks de la Versión de Esquema 2 solo se envían cuando los recursos se crean utilizando el encabezado `X-Belvo-API-Resource-Version: Payments-BR.V2`. Si no incluyes este encabezado, recibirás webhooks en el formato V1 (donde sea aplicable).

## Direcciones IP de salida del webhook

Puedes recibir eventos de webhook desde las siguientes direcciones IP:

- `3.130.254.46`
- `18.220.61.186`
- `18.223.45.212`


**Recomendamos encarecidamente** que pongas en la lista blanca estas direcciones IP para que puedas recibir eventos de webhook.

### Mejores prácticas para la respuesta del webhook del lado del cliente

Recomendamos encarecidamente que una vez que recibas un webhook, respondas a Belvo con un código de estado 2XX dentro de cinco segundos para confirmar que has recibido el webhook. De lo contrario, nuestra API volverá a intentar la solicitud.

### Política de reintento de webhook

Si nuestro sistema no recibe un código de estado 2XX, intenta enviar la solicitud nuevamente de forma automática. Este proceso de reintento ocurrirá hasta tres veces, con cada intento espaciado 60 segundos. Por ejemplo, si el primer intento falla, nuestro sistema espera 60 segundos antes de intentar nuevamente y continuará este patrón hasta que reciba una respuesta exitosa o alcance el máximo de tres reintentos.

Terminología de Campos V1 vs V2
Los payloads de webhook proporcionan detalles de error utilizando diferentes nombres de campos dependiendo de la versión del esquema del webhook y el recurso:

- **Webhooks V1 (CHARGES, CUSTOMERS, ENROLLMENTS, PAYMENT_INTENTS, TRANSACTIONS):** Usan `failure_code` (en `minúsculas`) y `failure_message` en el objeto `data`.
- **Webhooks V2 (BANK_ACCOUNT, CHARGE, CUSTOMER, PAYMENT_AUTHORIZATION):** Formato de payload mínimo - recupera detalles completos incluyendo `status_reason_code` y `status_reason_message` a través de una solicitud GET.


Para una tabla completa de todos los posibles códigos de razón de estado, consulta Códigos y Mensajes de Payments Brazil.

## Eventos de Webhook (Versión 2)

Versión de Esquema 2 vs Versión 1
Los webhooks de Bank Account, Charge y Customer están disponibles en ambas versiones de esquema. Al usar el encabezado `X-Belvo-API-Resource-Version: Payments-BR.V2`, recibirás el nuevo formato de Esquema Versión 2 que se muestra a continuación. Sin este encabezado, recibirás el formato V1 documentado en la sección Eventos de Webhook (V1).

Cada vez que haya un evento relacionado con una Bank Account, Charge, Customer o Payment Authorization recibirás el siguiente webhook:

```json Ejemplo de Webhook Versión 2
{
  "schema_version": "2",
  "resource": "BANK_ACCOUNT",
  "resource_id": "7d01c4cf-57ed-4ed9-b109-a5bfb2d8c42b",
  "resource_version": "v2",
  "timestamp": "2025-01-16T10:30:45.123456Z"
}
```

Donde:

| Parámetro  | Requerido | Tipo | Descripción | Ejemplo |
|  --- | --- | --- | --- | --- |
| `schema_version` | si | string | La versión del esquema del webhook. Actualmente, esto siempre será `2`. | `2` |
| `resource` | si | string | El tipo de recurso al que se refiere este webhook. Esto puede ser uno de los siguientes: `BANK_ACCOUNT`, `CHARGE`, `CUSTOMER`, `PAYMENT_AUTHORIZATION`. | `BANK_ACCOUNT` |
| `resource_id` | si | string | El identificador único del recurso. Puedes usar este ID para recuperar los detalles del recurso. | `7d01c4cf-57ed-4ed9-b109-a5bfb2d8c42b` |
| `resource_version` | si | string | La versión de la API utilizada al crear el recurso. | `v2` |
| `timestamp` | si | date-time | La marca de tiempo ISO-8601 de cuándo se actualizó por última vez el recurso. | `2025-01-16T10:30:45.123456Z` |


Una vez que recibas la notificación, tendrás que obtener los detalles del recurso haciendo la siguiente solicitud:

Formato de Solicitud
```shell Formato de Solicitud
curl --request GET 'https://api.belvo.com/payments/br/{resource}/{id}/' \
  -u SECRET_ID:SECRET_PASSWORD \
  -H 'X-Belvo-API-Resource-Version: Payments-BR.V2'
```

Ejemplo (Bank Accounts)
```shell Ejemplo (Bank Accounts)
curl --request GET 'https://api.belvo.com/payments/br/bank-accounts/{id}/' \
  -u SECRET_ID:SECRET_PASSWORD \
  -H 'X-Belvo-API-Resource-Version: Payments-BR.V2'
```

Ejemplo (Charges)
```shell Ejemplo (Charges)
curl --request GET 'https://api.belvo.com/payments/br/charges/{id}/' \
  -u SECRET_ID:SECRET_PASSWORD \
  -H 'X-Belvo-API-Resource-Version: Payments-BR.V2'
```

Ejemplo (Payment Authorizations)
```shell Ejemplo (Payment Authorizations)
curl --request GET 'https://api.belvo.com/payments/br/payment-authorizations/{id}/' \
  -u SECRET_ID:SECRET_PASSWORD \
  -H 'X-Belvo-API-Resource-Version: Payments-BR.V2'
```

Donde:

- `resource` es el tipo de recurso que deseas recuperar (`bank-accounts`, `charges`, `customers`, o `payment-authorizations`).
- `id` es el `resource_id` de la cuenta bancaria (que recibes en el evento del webhook).


## Eventos de Webhook (V1)

Payment Intents
```json Payment Intents Webhook Example
{
  "webhook_id": "3b9a69f7-0f0a-455b-832d-49ad6fd4905c",
  "webhook_type": "PAYMENT_INTENTS",
  "webhook_code": "STATUS_UPDATE",
  "object_id": "d2e40773-19f6-48d1-93c3-3590ec0c74df",
  "external_id": "c3c51aaf-aaa3-400c-926d-87ab62e195fd",
  "data": {
    "status": "FAILED",
    "metadata": {"internal_reference_id": "GGq12345w2"},
    "failure_code": "consent_expired",
    "failure_message": "The payment consent was not accepted in time.",
    "end_to_end_id": "E432158152024081610416f2b595b056"
  }
}
```

Payment Intents (invalid Pix key)
```json Payment Intents Webhook Example (invalid Pix key)
{
  "webhook_id": "0e42a7b9-7b7a-4493-92f7-8285cae08b46",
  "webhook_type": "PAYMENT_INTENTS",
  "webhook_code": "STATUS_UPDATE",
  "object_id": "07f9fa2f-242a-4901-ab39-b244ca67adb6",
  "external_id": "4b8a81a0-e33c-45a6-8567-479efb105f74",
  "data": {
    "status": "FAILED",
    "metadata": {
      "internal_reference_id": "GGq73487w3"
    },
    "failure_code": "invalid_pix_key",
    "failure_message": "The provided Pix Key is invalid."
  }
}
```

Enrollments
```json Enrollments Webhook Example
{
  "webhook_id": "3b9a69f7-0f0a-455b-832d-49ad6fd4905c",
  "webhook_type": "ENROLLMENTS",
  "webhook_code": "STATUS_UPDATE",
  "object_id": "f948c61d-e156-45df-923e-614faef2b2a9",
  "external_id": "ad930710-e5e1-47a6-957b-0df06deca34e",
  "data": {
    "status": "FAILED",
    "status_reason_code": "REJECTED_MANUALLY",
    "status_reason_message": "Manual cancellation, explicitly at the user's request.",
    "details": {
      "status": "REJECTED"
    }
  }
}
```

| Parámetro  | Requerido | Tipo | Descripción | Ejemplo |
|  --- | --- | --- | --- | --- |
| `webhook_id` | true | string | El ID del webhook de Belvo. | `aadf41a1fc8e4f79a49f7f04027ac999` |
| `webhook_type` | true | string | El recurso al que se refiere este webhook. | `CHARGES` |
| `webhook_code` | true | string | El evento que activó el webhook. | `STATUS_UPDATE` |
| `object_id` | true | string | El ID del objeto al que se refiere este webhook. | `d2e40773-19f6-48d1-93c3-3590ec0c74df` |
| `external_id` | true | string | El identificador único que proporcionaste al crear el objeto. Para cargos y transacciones, este campo siempre devolverá `null`. | `c3c51aaf-aaa3-400c-926d-87ab62e195fd` |
| `data` | true | object | Un objeto que contiene datos específicos sobre el evento. Los campos devueltos en este objeto dependen de `webhook_type` y `webhook_code`. | Ver filas siguientes. |
| `data.status` | false | string | El estado del cargo o intención de pago. | `FAILED` |
| `data.status_reason_code` | false | string | Un código de error estandarizado (en formato `UPPERCASE`) que indica por qué cambió el estado de un recurso. Solo aplicable a webhooks de ENROLLMENTS en eventos V1. | `REJECTED_MANUALLY` |
| `data.status_reason_message` | false | string | Una descripción legible que explica el cambio de estado. Proporciona contexto para el `status_reason_code`. Solo aplicable a webhooks de ENROLLMENTS en eventos V1. | `Manual cancellation, explicitly at the user's request.` |
| `data.failure_code` | false | string | En caso de que el cargo o la intención de pago falle, un código único para el error (en formato `lowercase` para Payment Intents y Charges). Por ejemplo, `consent_expired` o `invalid_pix_key` cuando la clave Pix del beneficiario es inválida. | `invalid_pix_key` |
| `data.failure_message` | false | string | En caso de que el cargo o la intención de pago falle, una descripción legible del error. | `The provided Pix Key is invalid.` |
| `data.end_to_end_id` | false | string | El ID del pago en el sistema de pagos de Brasil. | `E432158152024081610416f2b595b056` |
| `data.metadata` | false | object | Si proporcionaste alguna información en el objeto `metadata` al crear tu pago, se incluye en el cuerpo del webhook. | `{ "internal_reference_id": "GGq12345w2" }` |


Para obtener información sobre los datos específicos de un webhook dado, haz clic en el tipo de webhook en la tabla a continuación.

| Tipo | Evento  | Se envía siempre que... |
|  --- | --- | --- |
| CHARGES | `STATUS_UPDATE` | Hay una actualización en el estado de un Cargo:- `SCHEDULED` (El cargo está 'pausado' hasta la fecha de pago programada.)
- `SUCCEEDED` (El cargo ha sido confirmado y procesado por la red de open finance.)
- `FAILED` (El usuario no ha proporcionado consentimiento para el pago, o ha habido un error general en la red de open finance.)
- `CANCELED` (El cargo programado fue cancelado.)

 |
| CUSTOMERS | `OBJECT_CREATED` | Se crea un nuevo cliente (esquema V1). Es decir, cuando el cliente se crea de manera asincrónica y no como resultado de una llamada directa POST. |
| ENROLLMENTS | `STATUS_UPDATE` | Hay una actualización en el estado de una Inscripción:- `PENDING` (La inscripción está esperando que se envíen detalles biométricos.)
- `SUCCEEDED` (La inscripción fue aceptada por la institución.)
- `FAILED` (La inscripción fue rechazada por la institución.)

 |
| PAYMENT_INTENTS | `STATUS_UPDATE` | Hay una actualización en el estado de una Intención de Pago:- `REQUIRES_PAYMENT_METHOD` (Se requieren detalles adicionales para completar el flujo de intención de pago.)
- `REQUIRES_ACTION` (Has enviado `confirm=true` en el flujo de intención de pago y Belvo ahora inicia el flujo de pago en la red de open finance.)
- `PROCESSING` (El pago está siendo procesado en la red de open finance.)
- `SCHEDULED` (El pago está 'pausado' hasta la fecha de pago programada.)
- `CANCELED` (La intención de pago programada fue cancelada.)
- `SUCCEEDED` (El pago ha sido confirmado y procesado por la red de open finance.)
- `FAILED` (El pago ha sido rechazado por el usuario, el usuario no ha proporcionado consentimiento para el pago, ha habido un error general en la red de open finance, o la clave Pix del beneficiario es inválida (`failure_code`: `invalid_pix_key`, `failure_message`: `The provided Pix Key is invalid.`).)

 |
| TRANSACTIONS | `OBJECT_CREATED` | Se crea una nueva transacción. |


Una vez que recibas la notificación, deberás obtener detalles del recurso realizando la siguiente solicitud:

Request Format
```shell Request Format
curl --request GET 'https://api.belvo.com/payments/br/{resource}/{id}/' \
  -u SECRET_ID:SECRET_PASSWORD \
```

Example (Charges)
```shell Example (Charges)
curl --request GET 'https://api.belvo.com/payments/br/charges/{id}/' \
  -u SECRET_ID:SECRET_PASSWORD \
```

Donde:

- `resource` es el tipo de recurso que deseas recuperar (`bank-accounts`, `charges`, `customers`, `payment-intents`, o `transactions`).
- `id` es el `object_id` del recurso (que recibes en el evento del webhook).


## Códigos de Razón de Estado (Legado: Códigos de Fallo)

Códigos Completos de Razón de Estado
Para la tabla completa de todos los valores de `status_reason_code` y sus mensajes correspondientes, consulta Códigos y Mensajes de Pagos Brasil. La tabla a continuación muestra un subconjunto de códigos comunes que pueden aparecer en notificaciones de webhook.

A continuación se presenta una lista de códigos de razón de estado comunes y mensajes que puedes recibir en notificaciones de webhook V1:

| Código de Razón de Estado  | Mensaje de Razón de Estado | Cuándo puede ocurrir |
|  --- | --- | --- |
| `AMOUNT_OVER_LIMIT` | El monto del pago o el número de pagos excede los límites establecidos por la institución. | Actualización de Estado |
| `AUTHORIZATION_EXPIRED` | El tiempo de autorización ha expirado. | Actualización de Estado |
| `CONSENT_PENDING_AUTHORIZATION` | Consentimiento pendiente de autorización de múltiples niveles (estado 'PARTIALLY_ACCEPTED'). | Actualización de Estado |
| `HOLDER_INFRASTRUCTURE_FAILURE` | Hubo una falla en la infraestructura del titular de la cuenta. | Actualización de Estado |
| `ICP_INFRASTRUCTURE_FAILURE` | Hubo una falla en la infraestructura del ICP (Infraestructura de Claves Públicas). | Actualización de Estado |
| `INSUFFICIENT_FUNDS` | La cuenta no tiene fondos suficientes para realizar el pago. | Actualización de Estado |
| `INVALID_CHARGE` | El cargo es inválido o incorrecto. | Actualización de Estado |
| `INVALID_PAYMENT_DETAIL` | Los detalles del pago proporcionados son inválidos. | Actualización de Estado |
| `invalid_pix_key` | La Clave Pix proporcionada es inválida. | Intenciones de Pago `STATUS_UPDATE` (V1 `failure_code` / `failure_message` en el objeto `data`) |
| `NOT_INFORMED` | No se proporcionó una razón de error por parte de la institución. | Al Crear |
| `PAYMENT_CONSENT_MISMATCH` | Los detalles del pago no coinciden con el consentimiento proporcionado. | Al Crear |
| `PAYMENT_REFUSED_BY_HOLDER` | El pago fue rechazado por el titular de la cuenta. | Al Crear, Actualización de Estado |
| `PAYMENT_REFUSED_BY_SPI` | El pago fue rechazado por el SPI (Sistema de Pagos Instantáneos). | Actualización de Estado |
| `PAYMENT_SCHEDULING_FAILURE` | Hubo una falla al programar el pago. | Actualización de Estado |
| `RECEIVING_PSP_INFRASTRUCTURE_FAILURE` | Hubo una falla en la infraestructura del PSP receptor (Proveedor de Servicios de Pago). | Actualización de Estado |
| `SAME_ORIGIN_DESTINATION_ACCOUNTS` | Las cuentas de origen y destino son las mismas. | Actualización de Estado |
| `SPI_INFRASTRUCTURE_FAILURE` | Hubo una falla en la infraestructura del SPI. | Actualización de Estado |
| `SPI_REJECTED_PAYMENT` | Pago rechazado en el Sistema de Pagos Instantáneos (SPI). | Actualización de Estado |
| `USER_REJECTED` | El usuario rechazó la autorización del consentimiento. | Actualización de Estado |