> ## Documentation Index
> Fetch the complete documentation index at: https://rain-sandbox-trial.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Disputes

> Follow the dispute lifecycle: creation, status updates, evidence requests, and chargebacks.

Rain sends webhook notifications when disputes are created or updated. These webhooks work the same way for both consumer and corporate programs.

The following events are available:

| Event                                                     | Description                                                           |
| --------------------------------------------------------- | --------------------------------------------------------------------- |
| [`dispute.created`](#dispute-created)                     | A new dispute is opened.                                              |
| [`dispute.updated`](#dispute-updated)                     | A dispute changes status or you update evidence.                      |
| [`dispute.evidenceRequested`](#dispute-evidencerequested) | Rain requests additional evidence for a dispute.                      |
| [`dispute.chargebackCreated`](#dispute-chargebackcreated) | Rain processes a chargeback after the card network accepts a dispute. |

A dispute is a back-and-forth with the card network. After it opens, you may need to submit evidence by a deadline, and the outcome can be a chargeback or a resolution.

<div className="wf-diagram">
  <div className="legend">
    <span className="lg"><span className="swatch send" />Webhook Rain sends you</span>
    <span className="lg"><span className="swatch handle" />Your handler (ack 2xx)</span>
    <span className="lg"><span className="swatch action" />Action / API call</span>
    <span className="lg"><span className="swatch ext" />Card network</span>
    <span className="lg"><span className="swatch cond" />Conditional step</span>
    <span className="lg"><span className="swatch disp" />Exception (dispute)</span>
  </div>

  <div className="diagram-shell">
    <svg id="flow-dispute" role="img" aria-label="How a dispute flows: the cardholder disputes a charge, Rain sends dispute.created, Rain requests evidence, you submit a representment, the network decides, and Rain sends dispute.chargebackCreated and dispute.updated" viewBox="0 0 1080 1324" width="1080" height="1324" style={{width: "100%", height: "auto"}}><defs><marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" className="marker-fill-default" /></marker><marker id="arrowSend" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" className="marker-fill-send" /></marker><marker id="arrowDisp" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" className="marker-fill-disp" /></marker></defs><text x="20" y="230" className="phase-label" transform="rotate(-90 20 230)" text-anchor="middle">Open</text><rect x="6" y="380" width="1068" height="400" className="phase-band" rx="9" /><text x="20" y="580" className="phase-label" transform="rotate(-90 20 580)" text-anchor="middle">Evidence</text><text x="20" y="1047" className="phase-label" transform="rotate(-90 20 1047)" text-anchor="middle">Resolution</text><line x1="138" y1="70" x2="138" y2="1312" className="lane-line" stroke-width="1.5" stroke-dasharray="2 6" /><line x1="416.6666666666667" y1="70" x2="416.6666666666667" y2="1312" className="lane-line" stroke-width="1.5" stroke-dasharray="2 6" /><line x1="695.3333333333334" y1="70" x2="695.3333333333334" y2="1312" className="lane-line" stroke-width="1.5" stroke-dasharray="2 6" /><line x1="974" y1="70" x2="974" y2="1312" className="lane-line" stroke-width="1.5" stroke-dasharray="2 6" /><path d="M 695.3333333333334 168 C 695.3333333333334 184, 138 184, 138 200" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow)" opacity="0.92" /><path d="M 138 268 C 138 284, 974 284, 974 300" fill="none" className="conn-send" stroke-width="1.7" stroke-dasharray="5 4" marker-end="url(#arrowSend)" opacity="0.92" /><path d="M 974 368 C 974 384, 138 384, 138 400" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow)" opacity="0.92" /><path d="M 138 468 C 138 484, 974 484, 974 500" fill="none" className="conn-send" stroke-width="1.7" stroke-dasharray="5 4" marker-end="url(#arrowSend)" opacity="0.92" /><path d="M 974 568 C 974 584, 138 584, 138 600" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow)" opacity="0.92" /><path d="M 138 668 C 138 684, 974 684, 974 700" fill="none" className="conn-send" stroke-width="1.7" stroke-dasharray="5 4" marker-end="url(#arrowSend)" opacity="0.92" /><path d="M 974 768 C 974 784, 416.6666666666667 784, 416.6666666666667 800" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow)" opacity="0.92" /><path d="M 416.6666666666667 868 C 416.6666666666667 884, 138 884, 138 900" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow)" opacity="0.92" /><path d="M 138 968 C 138 984, 974 984, 974 1000" fill="none" className="conn-send" stroke-width="1.7" stroke-dasharray="5 4" marker-end="url(#arrowSend)" opacity="0.92" /><path d="M 974 1068 C 974 1084, 138 1084, 138 1100" fill="none" className="conn-default" stroke-width="1.7" marker-end="url(#arrow)" opacity="0.92" /><path d="M 138 1168 C 138 1184, 974 1184, 974 1200" fill="none" className="conn-send" stroke-width="1.7" stroke-dasharray="5 4" marker-end="url(#arrowSend)" opacity="0.92" /><foreignObject x="44" y="16" width="188" height="54"><div className="lane-head rain"><span className="ico">🌧️</span><span className="nm">Rain (issuer · processor)</span></div></foreignObject><foreignObject x="322.6666666666667" y="16" width="188" height="54"><div className="lane-head"><span className="ico">🌐</span><span className="nm">Card network</span></div></foreignObject><foreignObject x="601.3333333333334" y="16" width="188" height="54"><div className="lane-head"><span className="ico">👤</span><span className="nm">Cardholder</span></div></foreignObject><foreignObject x="880" y="16" width="188" height="54"><div className="lane-head"><span className="ico">🖥️</span><span className="nm">Partner backend (you)</span></div></foreignObject><foreignObject x="601.3333333333334" y="100" width="188" height="68"><div className="card action"><span className="bn">1</span><span className="ct"><span className="tag">Cardholder</span><span className="lab">Disputes a charge</span></span></div></foreignObject><foreignObject x="44" y="200" width="188" height="68"><div className="card send"><span className="bn">2</span><span className="ct"><span className="tag">Webhook · opened</span><span className="lab mono">dispute.created</span></span></div></foreignObject><foreignObject x="880" y="300" width="188" height="68"><div className="card handle"><span className="bn">3</span><span className="ct"><span className="tag">Handle</span><span className="lab">ack 2xx</span></span></div></foreignObject><foreignObject x="44" y="400" width="188" height="68"><div className="card send"><span className="bn">4</span><span className="ct"><span className="tag">Webhook · action needed</span><span className="lab mono">dispute.evidenceRequested</span></span></div></foreignObject><foreignObject x="880" y="500" width="188" height="68"><div className="card api"><span className="bn">5</span><span className="ct"><span className="tag">Respond</span><span className="lab">Submit evidence (representment)</span></span></div></foreignObject><foreignObject x="44" y="600" width="188" height="68"><div className="card send"><span className="bn">6</span><span className="ct"><span className="tag">Webhook · stage change</span><span className="lab mono">dispute.updated</span></span></div></foreignObject><foreignObject x="880" y="700" width="188" height="68"><div className="card handle"><span className="bn">7</span><span className="ct"><span className="tag">Handle</span><span className="lab">ack 2xx</span></span></div></foreignObject><foreignObject x="322.6666666666667" y="800" width="188" height="68"><div className="card ext"><span className="bn">8</span><span className="ct"><span className="tag">Network</span><span className="lab">Network decision</span></span></div></foreignObject><foreignObject x="44" y="900" width="188" height="68"><div className="card send cond"><span className="bn">9</span><span className="ct"><span className="tag">Webhook · if dispute accepted</span><span className="lab mono">dispute.chargebackCreated</span></span></div></foreignObject><foreignObject x="880" y="1000" width="188" height="68"><div className="card handle cond"><span className="bn">10</span><span className="ct"><span className="tag">Handle</span><span className="lab">ack 2xx</span></span></div></foreignObject><foreignObject x="44" y="1100" width="188" height="68"><div className="card send"><span className="bn">11</span><span className="ct"><span className="tag">Webhook · resolved</span><span className="lab mono">dispute.updated</span></span></div></foreignObject><foreignObject x="880" y="1200" width="188" height="68"><div className="card handle"><span className="bn">12</span><span className="ct"><span className="tag">Handle</span><span className="lab">ack 2xx</span></span></div></foreignObject></svg>
  </div>
</div>

## `dispute.created`

Rain sends this webhook immediately after you successfully create a dispute. You can only have one active dispute (pending or in-review) per transaction. This webhook is informational only and does not require a response.

```json Payload theme={null}
{
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "resource": "dispute",
    "action": "created",
    "version": "1.1.0",
    "body": {
        "id": "dispute_abc123",
        "transactionId": "txn_def456",
        "status": "pending",
        "disputeType": "fraud",
        "textEvidence": "I did not authorize this transaction",
        "disputeAmount": 2500,
        "createdAt": "2026-01-27T15:30:00.000Z",
        "transaction": {
            "id": "txn_def456",
            "cardholderUserId": "user_789",
            "cardholderFirstName": "John",
            "cardholderLastName": "Doe",
            "amount": 5000,
            "merchantName": "UNKNOWN MERCHANT",
            "postedAt": "2026-01-25T10:00:00.000Z"
        }
    }
}
```

| Field                             | Type                | Description                                                                                          |
| --------------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------- |
| `id`                              | `string`            | The dispute ID                                                                                       |
| `transactionId`                   | `string`            | The ID of the disputed transaction                                                                   |
| `status`                          | `string`            | Dispute status. See [Status values](#status-values).                                                 |
| `disputeType`                     | `string` (optional) | Type of dispute. See the dispute types below.                                                        |
| `textEvidence`                    | `string` (optional) | Text evidence provided for the dispute                                                               |
| `disputeAmount`                   | `number` (optional) | The disputed amount in cents. Equals the full transaction amount unless a partial dispute was filed. |
| `createdAt`                       | `string`            | ISO 8601 timestamp of dispute creation                                                               |
| `updatedAt`                       | `string` (optional) | ISO 8601 timestamp of last update                                                                    |
| `resolvedAt`                      | `string` (optional) | ISO 8601 timestamp of resolution                                                                     |
| `transaction`                     | `object` (optional) | Details of the disputed transaction                                                                  |
| `transaction.id`                  | `string`            | Transaction ID                                                                                       |
| `transaction.cardholderUserId`    | `string` (optional) | Cardholder's user ID                                                                                 |
| `transaction.cardholderFirstName` | `string` (optional) | Cardholder's first name                                                                              |
| `transaction.cardholderLastName`  | `string` (optional) | Cardholder's last name                                                                               |
| `transaction.amount`              | `number`            | Transaction amount in USD cents                                                                      |
| `transaction.merchantName`        | `string` (optional) | Merchant name                                                                                        |
| `transaction.postedAt`            | `string` (optional) | ISO 8601 timestamp when the transaction was posted                                                   |
| `transaction.currency`            | `string` (optional) | The transaction's currency, lowercase ISO-4217. Requires version `1.2.0` or later.                   |
| `currency`                        | `string` (optional) | The dispute currency, lowercase ISO-4217. Requires version `1.2.0` or later.                         |

The `disputeType` field can be one of these types:

| Type                 | Description                            |
| -------------------- | -------------------------------------- |
| `fraud`              | Unauthorized or fraudulent transaction |
| `creditNotProcessed` | A credit or refund was not processed   |
| `serviceNotReceived` | Service was not received               |
| `merchandiseIssue`   | Issue with merchandise received        |
| `other`              | Other dispute reason                   |

## `dispute.updated`

Rain sends this webhook whenever a dispute status changes or you update text evidence. This includes status changes to `"inReview"`, `"accepted"`, `"rejected"`, `"canceled"`, and `"resolvedByMerchant"`, as well as updates to text evidence. This webhook is informational only and does not require a response.

```json Payload theme={null}
{
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "resource": "dispute",
    "action": "updated",
    "version": "1.1.0",
    "body": {
        "id": "dispute_abc123",
        "transactionId": "txn_def456",
        "status": "accepted",
        "disputeType": "fraud",
        "textEvidence": "I did not authorize this transaction",
        "disputeAmount": 2500,
        "createdAt": "2026-01-27T15:30:00.000Z",
        "updatedAt": "2026-02-03T09:00:00.000Z",
        "resolvedAt": "2026-02-03T09:00:00.000Z",
        "transaction": {
            "id": "txn_def456",
            "cardholderUserId": "user_789",
            "cardholderFirstName": "John",
            "cardholderLastName": "Doe",
            "amount": 5000,
            "merchantName": "UNKNOWN MERCHANT",
            "postedAt": "2026-01-25T10:00:00.000Z"
        }
    }
}
```

The `dispute.updated` payload uses the same dispute object as [`dispute.created`](#dispute-created), plus one field of its own. Rain populates the `resolvedAt` timestamp when the status is `accepted`, `rejected`, `canceled`, or `resolvedByMerchant`.

| Field        | Type                | Description                                                                       |
| ------------ | ------------------- | --------------------------------------------------------------------------------- |
| `reviewedBy` | `string` (optional) | Who resolved the dispute: `rain` or `network`. Requires version `1.3.0` or later. |

### Status values

The `status` field can be one of the following:

| Status               | Description                                                      |
| -------------------- | ---------------------------------------------------------------- |
| `pending`            | Dispute has been created and is awaiting review                  |
| `inReview`           | Dispute is being reviewed                                        |
| `accepted`           | Dispute was accepted                                             |
| `rejected`           | Dispute was rejected                                             |
| `canceled`           | Dispute was canceled                                             |
| `resolvedByMerchant` | Dispute was resolved because the merchant issued a direct refund |

## Automatic resolution from merchant refunds

When a merchant issues a refund on a transaction with an active dispute, Rain automatically resolves the dispute with status `"resolvedByMerchant"`. This occurs when:

1. A cardholder files a dispute on a transaction (status: `"pending"` or `"inReview"`)
2. The merchant independently processes a refund for that transaction
3. Rain detects the merchant refund settlement

When Rain detects the refund:

* The dispute status changes to `"resolvedByMerchant"`
* The credit to the cardholder equals the merchant refund amount
* Rain populates the `resolvedAt` timestamp
* You receive a `dispute.updated` webhook with the new status
* Rain credits the cardholder account with the refund amount

This status is distinct from other terminal states:

* `"accepted"` - Dispute was won through the card network dispute process
* `"rejected"` - Dispute was denied through the card network dispute process
* `"canceled"` - Dispute was withdrawn or invalidated
* `"resolvedByMerchant"` - Dispute was automatically resolved because the merchant issued a direct refund

<Info>
  When a dispute is resolved by merchant refund, you do not receive a `dispute.chargebackCreated` webhook because the credit comes from the merchant refund settlement, not from a chargeback process.
</Info>

## `dispute.evidenceRequested`

Rain may request additional documentation to process a dispute. When this happens, you receive the `dispute.evidenceRequested` webhook. Check the `message` field to see what evidence is needed, then prompt the cardholder to submit it.

<Note>
  Rain does not currently emit this event; evidence requests reach you through your Rain contact instead. The schema below is reserved so you can build the handler ahead of time.
</Note>

```json Payload theme={null}
{
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "resource": "dispute",
    "action": "evidenceRequested",
    "version": "1.0.0",
    "body": {
        "id": "dispute_abc123",
        "transactionId": "txn_def456",
        "message": "Please provide receipt for the disputed transaction"
    }
}
```

| Field           | Type     | Description                                              |
| --------------- | -------- | -------------------------------------------------------- |
| `id`            | `string` | The dispute ID                                           |
| `transactionId` | `string` | The ID of the disputed transaction                       |
| `message`       | `string` | The message from Rain describing what evidence is needed |

## `dispute.chargebackCreated`

Rain sends this webhook after the card network accepts a dispute and Rain processes the reimbursement. It lets you directly link the chargeback transaction back to the original dispute without having to match amounts and timing. This webhook is informational only and does not require a response.

```json Payload theme={null}
{
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "resource": "dispute",
    "action": "chargebackCreated",
    "version": "1.0.0",
    "body": {
        "id": "dispute_abc123",
        "disputeId": "dispute_abc123",
        "transactionId": "txn_chargeback_xyz789",
        "originalTransactionId": "txn_original_def456",
        "amount": -2500,
        "originalTransactionAmount": 5000
    },
    "eventReceivedAt": "2026-02-18T12:00:00.000Z"
}
```

| Field                       | Type                | Description                                                                     |
| --------------------------- | ------------------- | ------------------------------------------------------------------------------- |
| `id`                        | `string`            | The dispute ID                                                                  |
| `disputeId`                 | `string`            | The dispute ID                                                                  |
| `transactionId`             | `string`            | The ID of the new chargeback transaction                                        |
| `originalTransactionId`     | `string`            | The ID of the original disputed transaction                                     |
| `amount`                    | `number`            | Chargeback amount in USD cents (always negative)                                |
| `originalTransactionAmount` | `number`            | Original transaction amount in USD cents                                        |
| `currency`                  | `string` (optional) | The chargeback currency, lowercase ISO-4217. Requires version `1.1.0` or later. |
| `eventReceivedAt`           | `string` (optional) | ISO 8601 timestamp of when Rain received the event                              |

### When is this webhook sent?

Rain sends the `dispute.chargebackCreated` webhook after:

1. The card network accepts a dispute (status changes to `"accepted"`)
2. Rain creates the reimbursement transaction
3. Rain credits the account

You will also receive a `transaction.completed` webhook for the chargeback transaction. The `dispute.chargebackCreated` webhook provides the explicit link between the chargeback and the dispute.

## Dispute reimbursement

After the card network accepts a dispute (`status` changes to `"accepted"`), Rain automatically processes the reimbursement and credits the account.

Rain files and reimburses only disputes that meet the minimum dispute amount. See [Dispute Thresholds and Fees](/docs/transaction-issues-disputes#dispute-thresholds-and-fees) for the thresholds, effective dates, and fee details.

When the reimbursement is processed, you will receive two webhooks:

1. **`dispute.chargebackCreated`** - Links the chargeback transaction directly to the dispute (see above)
2. **`transaction.completed`** - Standard transaction webhook for the chargeback transaction

The chargeback transaction has:

* Negative transaction amount (credit to the account)
* Amount matches the credit issued for the dispute
* Transaction appears in your transaction history
* Account balance updated to reflect the credit

### Identify reimbursement transactions

You can identify reimbursement transactions by:

* The `dispute.chargebackCreated` webhook, which provides the `transactionId` linked to the `disputeId`
* Negative transaction amount (credit)
* Transaction type of `"spend"`

<Tip>
  Use the `dispute.chargebackCreated` webhook for the most reliable way to link chargeback transactions back to disputes.
</Tip>

## What's next

<Columns cols={2}>
  <Card title="Handle disputes & refunds" icon="life-ring" href="/docs/transaction-issues-disputes">
    Walk through filing a dispute, the reimbursement process, and common questions.
  </Card>

  <Card title="Decline reasons" icon="circle-exclamation" href="/docs/decline-reasons">
    Look up what a `declinedReason` value means and what to do about it.
  </Card>
</Columns>
