# Payload

> Los eventos que Rapid envía por webhook: headers, campos de cada cuerpo, ejemplos completos y la diferencia entre los formatos v2 y legacy.

Página: https://doc.rapidchargeback.com/es/canais/webhook/payload/

Rapid envía un `HTTP POST` con `Content-Type: application/json` a la URL configurada. El cuerpo es un objeto JSON y el campo `event` (también en el header `X-Webhook-Event`) dice qué pasó.

## Eventos

| Evento | Producto | Cuándo se dispara | Cuerpo |
|---|---|---|---|
| `chargeback_alert.received` | Alerta | Se recibió una alerta y se asoció a tu empresa | [Alerta recibida](#evento-chargeback_alertreceived) |
| `dispute.fraud.revoke_access` | Disputa | Llegó una disputa por **fraude** (Visa 10.4 / Mastercard 4837) y la red de la tarjeta exige que cortes el acceso del titular | [Revocación de acceso](#evento-disputefraudrevoke_access) |

La misma URL recibe todos los eventos: usa `event` (o el header) para enrutar. Si solo tratas uno de ellos, responde `200` a los demás aunque no los proceses.

Hay **dos formatos**, definidos por Rapid en tu cuenta:
- **`v2`**: el predeterminado para cuentas nuevas. Descrito en esta página (headers, firma, cuerpo).
- **`legacy`**: cuentas migradas del sistema anterior. Mismo cuerpo y headers que el sistema antiguo, **sin firma**. Descrito en la sección [Formato legacy](#formato-legacy) al final de la página. El formato `legacy` vale **solo** para `chargeback_alert.received`: los demás eventos salen siempre en `v2`, incluso en esas cuentas.

Para saber o cambiar el formato de tu cuenta, habla con el soporte de Rapid.

## Método y headers (formato `v2`)

```
POST https://tu-sistema.com/webhooks/rapid
Content-Type: application/json
X-Webhook-Signature: sha256=<hmac_hex>
X-Webhook-Timestamp: 1790000000
X-Webhook-Event: chargeback_alert.received
X-Webhook-Reference-Id: <alert_id>
```

- `X-Webhook-Signature`: HMAC-SHA256 de `${X-Webhook-Timestamp}.${body}` con tu clave de firma. Ver [Autenticación](https://doc.rapidchargeback.com/es/canais/webhook/autenticacao/).
- `X-Webhook-Timestamp`: cuándo firmó Rapid, en segundos desde la epoch. Forma parte de la firma (anti-replay) y debe verificarse contra una ventana de tolerancia de 5 minutos.
- `X-Webhook-Event`: tipo del evento (ver [Eventos](#eventos)). Úsalo para enrutar.
- `X-Webhook-Reference-Id`: ID de referencia del evento: `alert_id` en `chargeback_alert.received`, `dispute_id` en `dispute.fraud.revoke_access`. Permite deduplicar sin parsear el body.

> Los headers `clientid`/`clientkey` **no** se envían en el formato `v2`: lo que autentica la entrega es la firma. Siguen enviándose solo en el formato `legacy` (ver [Formato legacy](#formato-legacy)).

---

## Evento `chargeback_alert.received`

### Estructura del cuerpo

| Campo | Tipo | Descripción | Obligatorio |
|---|---|---|---|
| `event` | string | `chargeback_alert.received` | Sí |
| `alert_id` | string (UUID) | ID único de la alerta en Rapid; úsalo para llamar a los endpoints de consulta y actualización de estado | Sí |
| `provider_alert_id` | string | ID de la alerta en el sistema del proveedor. Útil como referencia cruzada si tratas directamente con el soporte del proveedor | Sí |
| `provider` | string | Origen de la alerta: `ethoca_alerts` o `verifi_rdr` | Sí |
| `amount` | number \| null | Monto de la transacción disputada (puede venir `null` cuando el proveedor no lo informa) | Sí |
| `currency` | string | Código ISO 4217 con 3 letras mayúsculas | Sí |
| `card_last4` | string | Últimos 4 dígitos de la tarjeta | Sí |
| `card_bin` | string | BIN de la tarjeta (6-8 dígitos) | Sí |
| `transaction_date` | string | Fecha de la transacción original (ISO 8601, `"2026-04-01T00:00:00.000Z"`) | Sí |
| `descriptor` | string | Nombre que aparece en el resumen del titular | Sí |
| `arn` | string | Acquirer Reference Number | No |
| `caid` | string | Card Acceptor ID | No |
| `auth_code` | string | Código de autorización de la transacción | No |
| `alert_type` | string | Tipo de alerta (ej.: `fraud`, `dispute`) | No |
| `reason_code` | string | Código del motivo de la disputa | No |
| `issuer` | string | Banco emisor de la tarjeta | No |
| `installment_number` | number \| null | Cuota actual | No |
| `installment_count` | number \| null | Total de cuotas | No |
| `status` | string | Estado inicial de la alerta. Siempre `pending` al recibirla | Sí |
| `received_at` | string | Cuándo Rapid recibió la alerta (ISO 8601) | Sí |
| `expires_at` | string \| null | Plazo de respuesta (ISO 8601), solo para Ethoca | No |
| `merchant` | object \| null | Datos del merchant asociado (ver abajo); `null` si la alerta todavía no se asoció | Sí |

#### Objeto `merchant`

| Campo | Tipo | Descripción |
|---|---|---|
| `id` | string (UUID) | ID del merchant en Rapid |
| `name` | string | Nombre del merchant |

---

### Ejemplo de payload

```json
{
  "event": "chargeback_alert.received",
  "alert_id": "00000000-0000-0000-0000-000000000099",
  "provider_alert_id": "2UBOD4MKAI42RPXEYU4UVQPS",
  "provider": "ethoca_alerts",
  "amount": 150.00,
  "currency": "USD",
  "card_last4": "4242",
  "card_bin": "424242",
  "transaction_date": "2026-04-01T00:00:00.000Z",
  "descriptor": "LOJA EXEMPLO",
  "arn": "74537119547024600128228",
  "caid": "123456789",
  "auth_code": "123456",
  "alert_type": "fraud",
  "reason_code": "4853",
  "issuer": "Chase Bank",
  "installment_number": null,
  "installment_count": null,
  "status": "pending",
  "received_at": "2026-04-14T10:00:00Z",
  "expires_at": "2026-04-15T10:00:00Z",
  "merchant": {
    "id": "00000000-0000-0000-0000-000000000001",
    "name": "Minha Loja"
  }
}
```

---

## Evento `dispute.fraud.revoke_access`

Se dispara cuando Rapid recibe una disputa por **fraude**. Las redes de tarjetas exigen que el comercio intente revocar el producto o servicio entregado al titular y tenga un proceso para evitar la reincidencia (Visa Core Rules §10.4.4.3). Cuanto más rápido el corte, menor la pérdida: trata este evento de forma automática si es posible.

El campo `merchant` dice **cuál de tus tiendas** hizo la venta: la entrega siempre va al webhook único de la empresa, y tú enrutas internamente.

### Estructura del cuerpo

| Campo | Tipo | Descripción | Obligatorio |
|---|---|---|---|
| `event` | string | `dispute.fraud.revoke_access` | Sí |
| `dispute_id` | string (UUID) | ID de la disputa en Rapid. Úsalo como clave de idempotencia; la disputa aparece en el panel, en Disputas | Sí |
| `merchant` | object \| null | Tienda asociada (`id`, `name`); `null` si la disputa todavía no se asoció | Sí |
| `network` | string | Red de la tarjeta: `visa`, `mastercard`, … | Sí |
| `condition` | string \| null | Condición o motivo de la red (ej.: `10.4`, `4837`) | No |
| `transaction_id` | string \| null | ID de la transacción en la red, cuando lo informa el adquirente | No |
| `customer_ref` | string \| null | Identificador del cliente que enviaste en la transacción (`account_id`), cuando existe | No |
| `order_ref` | string | Referencia del pedido: número de pedido, tu ID externo o, si no hay ninguno, el `dispute_id` | Sí |
| `reason` | string | Siempre `fraud_dispute_received` | Sí |
| `is_account_takeover` | boolean | `true` cuando hay indicios de cuenta tomada (dispositivo e IP difieren del historial del cliente) | Sí |
| `required_actions` | string[] | Acciones exigidas: `revoke_access`, `prevent_reoccurrence` y, en cuenta tomada, `re_authenticate` | Sí |
| `citation` | object | Regla que fundamenta la exigencia (`section`, `visa_id`, `page`, `quote_en`, `ruleset_version`) | Sí |
| `emitted_at` | string | Cuándo Rapid emitió el evento (ISO 8601) | Sí |
| `deadline_hint` | string | Plazo de respuesta de la disputa (ISO 8601) o `as_soon_as_possible` cuando no hay plazo conocido | Sí |

### Ejemplo de payload

```json
{
  "event": "dispute.fraud.revoke_access",
  "dispute_id": "00000000-0000-0000-0000-0000000000d1",
  "merchant": {
    "id": "00000000-0000-0000-0000-000000000001",
    "name": "Minha Loja"
  },
  "network": "visa",
  "condition": "10.4",
  "transaction_id": "ch_3Qx0000000",
  "customer_ref": "acct-8842",
  "order_ref": "PED-5078",
  "reason": "fraud_dispute_received",
  "is_account_takeover": false,
  "required_actions": ["revoke_access", "prevent_reoccurrence"],
  "citation": {
    "section": "10.4.4.3",
    "visa_id": "0030642",
    "page": 634,
    "quote_en": "An Acquirer must ensure that its Merchant attempts to revoke provision of goods or services from the Cardholder after a Dispute category 10 (Fraud) Dispute and that the Merchant has a process in place to prevent reoccurrence by the Cardholder.",
    "ruleset_version": "visa-core-rules-2026-04-18"
  },
  "emitted_at": "2026-09-30T14:25:00.000Z",
  "deadline_hint": "2026-10-14T14:20:00.000Z"
}
```

### Confirmar lo que hiciste (opcional)

Responder `200` ya cierra la entrega. Si quieres registrar lo que se hizo, devuelve en el cuerpo un JSON con los campos de abajo. Aparece en el panel, en la disputa, como confirmación de tu integración. Una clave desconocida invalida todo el cuerpo (la entrega sigue siendo válida, solo no registra la confirmación).

| Campo | Tipo | Descripción |
|---|---|---|
| `status` | string | `done`, `partial`, `refused`, `not_applicable` o `accepted` |
| `actions_taken` | string[] | Cuáles de las `required_actions` ejecutaste |
| `revoked_at` | string | Cuándo se cortó el acceso (ISO 8601) |
| `note` | string | Observación libre, hasta 500 caracteres |

```json
{
  "status": "done",
  "actions_taken": ["revoke_access", "prevent_reoccurrence"],
  "revoked_at": "2026-09-30T14:25:03Z",
  "note": "cuenta suspendida y tarjeta bloqueada para nuevas compras"
}
```

**Idempotencia:** Rapid emite **un** evento por disputa (`dispute_id` es único). Los reintentos repiten el mismo `dispute_id`, así que trátalo por la clave en lugar de contar llamadas. Si no logramos entregarlo, la disputa aparece en el panel con la revocación pendiente, y el cliente la confirma manualmente ahí.

---

## Respuesta esperada

Tu aplicación debe devolver uno de los siguientes códigos para confirmar la recepción:

| Código | Significado |
|---|---|
| `2xx` | Éxito. `200`, `201`, `202` y `204` valen lo mismo; el cuerpo es opcional |

Cualquier otro código (incluidos `4xx` y `5xx`) se trata como falla y dispara un reintento. Registra la URL final: un `301`, `302` o `303` en tu URL cuenta como falla (ver [Redirección](https://doc.rapidchargeback.com/es/canais/webhook/retries-e-logs/#redirección)). Ver [Reintentos y logs](https://doc.rapidchargeback.com/es/canais/webhook/retries-e-logs/).

En `dispute.fraud.revoke_access`, el cuerpo del `200` puede traer la confirmación de lo que ejecutaste (ver [arriba](#confirmar-lo-que-hiciste-opcional)). En los demás eventos el cuerpo se ignora.

---

## Campos que pueden evolucionar

Se pueden agregar campos nuevos al payload en el futuro. Tu aplicación debe **ignorar los campos desconocidos** en lugar de fallar. Nunca modifiques ni elimines campos al procesar; solo léelos.

---

## Formato legacy

Las cuentas migradas del sistema anterior reciben el **mismo POST de antes**. Headers: `Content-Type: application/json`, `x-source: rapid`, `clientid`, `clientkey`, y **sin** `X-Webhook-Signature`, `X-Webhook-Event` ni `X-Webhook-Reference-Id`.

| Campo | Tipo | Descripción |
|---|---|---|
| `alert_id` | string | **ID de la alerta en el proveedor** (no es el UUID de Rapid). Es el valor a usar en `POST /chargeback-alert/get` y en el alias `POST /chargeback-alert/update/status` |
| `merchant` | string | Nombre del merchant |
| `provider` | string | `ethoca` o `verifi-rdr` |
| `descriptor` | string | Nombre en el resumen del titular |
| `transaction_date` | string | Fecha de la transacción (ISO 8601) |
| `currency` | string | ISO 4217 |
| `amount` | number \| null | Monto de la transacción |
| `card_number` | string \| null | `BIN******LAST4`, o `null` cuando el proveedor no informó BIN ni últimos dígitos |
| `created_at` | string | Cuándo Rapid recibió la alerta |
| `arn` | string \| null | Acquirer Reference Number |
| `authorization_code` | string \| null | Código de autorización |
| `issuer` | string \| null | Banco emisor |
| `type` | string \| null | Tipo de alerta |
| `global` | boolean | `true` para alerta internacional |
| `reason_code`, `status_code`, `mcc`, `tier`, `caid` | string \| null | Campos del proveedor, cuando existen |
| `installment_number`, `total_installment_count` | number \| null | Cuotas |

No hay campo `event`, `status` ni `expires_at` en este formato. Reintentos, timeout y logs son los mismos que en `v2`.
