# Payload

> The events Rapid sends by webhook: headers, the fields of each body, full examples and the difference between the v2 and legacy formats.

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

Rapid sends an `HTTP POST` with `Content-Type: application/json` to the configured URL. The body is a JSON object and the `event` field (also in the `X-Webhook-Event` header) says what happened.

## Events

| Event | Product | When it fires | Body |
|---|---|---|---|
| `chargeback_alert.received` | Alert | An alert was received and matched to your company | [Alert received](#chargeback_alertreceived-event) |
| `dispute.fraud.revoke_access` | Dispute | A **fraud** dispute arrived (Visa 10.4 / Mastercard 4837) and the card network requires you to cut off the cardholder's access | [Access revocation](#disputefraudrevoke_access-event) |

The same URL receives every event: use `event` (or the header) to route. If you only handle one of them, respond `200` to the others even without processing them.

There are **two formats**, set by Rapid on your account:
- **`v2`**: the default for new accounts. Described on this page (headers, signature, body).
- **`legacy`**: accounts migrated from the previous system. Same body and headers as the old system, **without a signature**. Described in the [Legacy format](#legacy-format) section at the end of the page. The `legacy` format applies **only** to `chargeback_alert.received`: the other events always go out in `v2`, even on those accounts.

To find out or change your account's format, contact Rapid support.

## Method and headers (`v2` format)

```
POST https://your-system.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 of `${X-Webhook-Timestamp}.${body}` with your signing key. See [Authentication](https://doc.rapidchargeback.com/en/canais/webhook/autenticacao/).
- `X-Webhook-Timestamp`: when Rapid signed, in seconds since the epoch. It is part of the signature (anti-replay) and must be checked against a 5-minute tolerance window.
- `X-Webhook-Event`: the event type (see [Events](#events)). Use it for routing.
- `X-Webhook-Reference-Id`: the event's reference ID: `alert_id` in `chargeback_alert.received`, `dispute_id` in `dispute.fraud.revoke_access`. Allows deduplication without parsing the body.

> The `clientid`/`clientkey` headers are **not** sent in the `v2` format: the signature is what authenticates the delivery. They are still sent only in the `legacy` format (see [Legacy format](#legacy-format)).

---

## `chargeback_alert.received` event

### Body structure

| Field | Type | Description | Required |
|---|---|---|---|
| `event` | string | `chargeback_alert.received` | Yes |
| `alert_id` | string (UUID) | Unique ID of the alert at Rapid; use it to call the search and status update endpoints | Yes |
| `provider_alert_id` | string | ID of the alert in the provider's system. Useful for cross-reference when dealing directly with the provider's support | Yes |
| `provider` | string | Source of the alert: `ethoca_alerts` or `verifi_rdr` | Yes |
| `amount` | number \| null | Amount of the disputed transaction (can be `null` when the provider does not send it) | Yes |
| `currency` | string | ISO 4217 code with 3 uppercase letters | Yes |
| `card_last4` | string | Last 4 digits of the card | Yes |
| `card_bin` | string | Card BIN (6-8 digits) | Yes |
| `transaction_date` | string | Date of the original transaction (ISO 8601, `"2026-04-01T00:00:00.000Z"`) | Yes |
| `descriptor` | string | Name shown on the cardholder's statement | Yes |
| `arn` | string | Acquirer Reference Number | No |
| `caid` | string | Card Acceptor ID | No |
| `auth_code` | string | Authorization code of the transaction | No |
| `alert_type` | string | Alert type (e.g. `fraud`, `dispute`) | No |
| `reason_code` | string | Dispute reason code | No |
| `issuer` | string | Card issuing bank | No |
| `installment_number` | number \| null | Current installment | No |
| `installment_count` | number \| null | Total number of installments | No |
| `status` | string | Initial status of the alert. Always `pending` on receipt | Yes |
| `received_at` | string | When Rapid received the alert (ISO 8601) | Yes |
| `expires_at` | string \| null | Response deadline (ISO 8601), only for Ethoca | No |
| `merchant` | object \| null | Data of the matched merchant (see below); `null` if the alert has not been matched yet | Yes |

#### `merchant` object

| Field | Type | Description |
|---|---|---|
| `id` | string (UUID) | Merchant ID at Rapid |
| `name` | string | Merchant name |

---

### Payload example

```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"
  }
}
```

---

## `dispute.fraud.revoke_access` event

Fired when Rapid receives a **fraud** dispute. The card networks require the merchant to attempt to revoke the goods or services provided to the cardholder and to have a process to prevent reoccurrence (Visa Core Rules §10.4.4.3). The faster the cut-off, the smaller the loss: handle this event automatically if possible.

The `merchant` field says **which of your stores** made the sale: delivery always goes to the company's single webhook, and you route internally.

### Body structure

| Field | Type | Description | Required |
|---|---|---|---|
| `event` | string | `dispute.fraud.revoke_access` | Yes |
| `dispute_id` | string (UUID) | ID of the dispute at Rapid. Use it as the idempotency key; the dispute shows up in the dashboard, under Disputes | Yes |
| `merchant` | object \| null | Matched store (`id`, `name`); `null` if the dispute has not been matched yet | Yes |
| `network` | string | Card network: `visa`, `mastercard`, … | Yes |
| `condition` | string \| null | Card network condition or reason (e.g. `10.4`, `4837`) | No |
| `transaction_id` | string \| null | ID of the transaction on the network, when sent by the acquirer | No |
| `customer_ref` | string \| null | Customer identifier you sent in the transaction (`account_id`), when there is one | No |
| `order_ref` | string | Order reference: order number, your external ID or, if neither exists, the `dispute_id` | Yes |
| `reason` | string | Always `fraud_dispute_received` | Yes |
| `is_account_takeover` | boolean | `true` when there are signs of account takeover (device and IP differ from the customer's history) | Yes |
| `required_actions` | string[] | Required actions: `revoke_access`, `prevent_reoccurrence` and, on account takeover, `re_authenticate` | Yes |
| `citation` | object | The rule behind the requirement (`section`, `visa_id`, `page`, `quote_en`, `ruleset_version`) | Yes |
| `emitted_at` | string | When Rapid emitted the event (ISO 8601) | Yes |
| `deadline_hint` | string | Dispute response deadline (ISO 8601) or `as_soon_as_possible` when no deadline is known | Yes |

### Payload example

```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"
}
```

### Confirming what you did (optional)

Responding `200` already closes the delivery. If you want to record what was done, return a JSON body with the fields below. It shows up in the dashboard, on the dispute, as confirmation from your integration. An unknown key invalidates the whole body (the delivery is still valid, it just does not record the confirmation).

| Field | Type | Description |
|---|---|---|
| `status` | string | `done`, `partial`, `refused`, `not_applicable` or `accepted` |
| `actions_taken` | string[] | Which of the `required_actions` you carried out |
| `revoked_at` | string | When access was cut off (ISO 8601) |
| `note` | string | Free-text note, up to 500 characters |

```json
{
  "status": "done",
  "actions_taken": ["revoke_access", "prevent_reoccurrence"],
  "revoked_at": "2026-09-30T14:25:03Z",
  "note": "account suspended and card blocked for new purchases"
}
```

**Idempotency:** Rapid emits **one** event per dispute (`dispute_id` is unique). Retries repeat the same `dispute_id`, so handle it by the key instead of counting calls. If we cannot deliver it, the dispute shows up in the dashboard with the revocation pending, and the customer confirms it manually there.

---

## Expected response

Your application must return one of the following codes to confirm receipt:

| Code | Meaning |
|---|---|
| `2xx` | Success. `200`, `201`, `202` and `204` are all equivalent; the body is optional |

Any other code (including `4xx` and `5xx`) is treated as a failure and triggers a retry. Register the final URL: a `301`, `302` or `303` on your URL counts as a failure (see [Redirects](https://doc.rapidchargeback.com/en/canais/webhook/retries-e-logs/#redirects)). See [Retries and logs](https://doc.rapidchargeback.com/en/canais/webhook/retries-e-logs/).

In `dispute.fraud.revoke_access`, the body of the `200` can carry the confirmation of what you did (see [above](#confirming-what-you-did-optional)). For the other events the body is ignored.

---

## Fields that may evolve

New fields may be added to the payload in the future. Your application must **ignore unknown fields** instead of failing. Never change or remove fields while processing; only read them.

---

## Legacy format

Accounts migrated from the previous system receive the **same POST as before**. Headers: `Content-Type: application/json`, `x-source: rapid`, `clientid`, `clientkey`, and **no** `X-Webhook-Signature`, `X-Webhook-Event` or `X-Webhook-Reference-Id`.

| Field | Type | Description |
|---|---|---|
| `alert_id` | string | **ID of the alert at the provider** (not Rapid's UUID). It is the value to use in `POST /chargeback-alert/get` and in the `POST /chargeback-alert/update/status` alias |
| `merchant` | string | Merchant name |
| `provider` | string | `ethoca` or `verifi-rdr` |
| `descriptor` | string | Name on the cardholder's statement |
| `transaction_date` | string | Transaction date (ISO 8601) |
| `currency` | string | ISO 4217 |
| `amount` | number \| null | Transaction amount |
| `card_number` | string \| null | `BIN******LAST4`, or `null` when the provider sent neither BIN nor last digits |
| `created_at` | string | When Rapid received the alert |
| `arn` | string \| null | Acquirer Reference Number |
| `authorization_code` | string \| null | Authorization code |
| `issuer` | string \| null | Issuing bank |
| `type` | string \| null | Alert type |
| `global` | boolean | `true` for an international alert |
| `reason_code`, `status_code`, `mcc`, `tier`, `caid` | string \| null | Provider fields, when present |
| `installment_number`, `total_installment_count` | number \| null | Installments |

There is no `event`, `status` or `expires_at` field in this format. Retries, timeout and logs are the same as in `v2`.
