> ## Documentation Index
> Fetch the complete documentation index at: https://api.fanvue.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# App refund and dispute events

> Payload reference for app.refund.created, app.dispute.flagged and app.dispute.created on your app's one-time purchases, with reason and status values.

Refunds and disputes on your app's one-time purchases arrive as two resources, `refund` and `dispute`.

| Event (`type`) | `data.object` | Fires when |
| - | - | - |
| `app.refund.created` | `refund` | A one-time purchase is refunded, charged back or cancelled |
| `app.payment.refunded` | `refund` | Deprecated alias of `app.refund.created`, same body |
| `app.dispute.flagged` | `dispute` | An early chargeback warning is raised, before a formal dispute |
| `app.dispute.created` | `dispute` | A formal dispute (chargeback) is opened |

Every event requires `read:self`. Each arrives in the [envelope](/docs/webhooks/index#event-envelope), and the tables below describe `data`.

<Note>
  These events cover one-time purchases only, identified by a `purchase_reference` with the `appotp_` prefix. Subscription reversals and chargebacks are reconciled through [`GET /apps/{appUuid}/subscription-status`](/docs/payments/app-billing/subscription-status), not these events.
</Note>

## Refund resource

`data.object` is `"refund"`. The refund references the original payment through `payment_id`, carries `amount` rather than `gross`, and has no `status` or `paid_at`. Amounts are integers in USD cents.

| Field | Type | Description |
| - | - | - |
| `object` | string | Always `"refund"` |
| `id` | string | Fanvue invoice number for the reversal |
| `payment_id` | string | Invoice number of the original payment |
| `amount` | integer | Reversed gross in USD minor units, positive |
| `currency` | string | Always `"USD"` |
| `reason` | string | `refund` \| `chargeback` \| `cancel` |
| `purchase_reference` | string | The one-time purchase reference (`appotp_` prefix) |
| `client_reference_id` | string \| null | Your attribution reference from the original purchase's checkout link. `null` when not provided. See [One-time items](/docs/payments/app-billing/one-time-items#attribution) |
| `metadata` | object | `client_metadata` captured with the original purchase. `{}` when none was set |
| `created_at` | string \| null | ISO 8601 time the reversal was paid, or created when unpaid |
| `item` | object | `{ uuid }` of the purchased pricing plan. `uuid` is `null` when unknown |
| `app` | object | `{ uuid }` of your app |
| `buyer` | object | `{ uuid }` of the buyer |

| `reason` | Path |
| - | - |
| `refund` | A refund issued on the purchase |
| `chargeback` | A dispute resolved against the sale |
| `cancel` | The purchase was cancelled before the money settled |

### Example: `app.refund.created`

```json theme={null}
{
  "id": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
  "type": "app.refund.created",
  "timestamp": "2026-06-18T09:30:00.000Z",
  "data": {
    "object": "refund",
    "id": "INV-2026-000456",
    "payment_id": "INV-2026-000123",
    "amount": 999,
    "currency": "USD",
    "reason": "refund",
    "purchase_reference": "appotp_3f9a2b71-1c4e-4f8a-9d2b-7c6e5a4b3d21",
    "client_reference_id": null,
    "metadata": {},
    "created_at": "2026-06-18T09:29:58.000Z",
    "item": { "uuid": "b2d7c9f0-4a13-4e6b-8f25-1a9c3e7d5b80" },
    "app": { "uuid": "a1c3e5f7-9b2d-4c6e-8a0f-2d4b6c8e0a13" },
    "buyer": { "uuid": "c4e6a8b0-2d4f-6a81-0c2e-4b6d8f0a2c46" }
  }
}
```

<Warning>
  Subscribe to `app.refund.created` or to `app.payment.refunded`, never both. Fanvue emits both for every reversal with an identical `data` body and distinct event ids, so handling both counts each refund twice. `app.payment.refunded` is deprecated; new integrations use `app.refund.created`.
</Warning>

## Dispute resource

`data.object` is `"dispute"`. `app.dispute.flagged` and `app.dispute.created` share the resource and differ in `status`.

| Field | Type | Description |
| - | - | - |
| `object` | string | Always `"dispute"` |
| `id` | string | Processor dispute or alert id |
| `status` | string | `warning` on `app.dispute.flagged`, `open` on `app.dispute.created` |
| `amount` | integer \| null | Disputed amount in minor units |
| `currency` | string \| null | ISO 4217 currency code reported by the processor |
| `reason` | string \| null | Dispute reason, when provided |
| `created_at` | string \| null | ISO 8601 time the dispute was reported |
| `payment` | object | The disputed payment: `{ id, transaction_id }`, where `id` is the original invoice number |
| `item` | object | `{ uuid }` of the purchased pricing plan. `uuid` is `null` when unknown |
| `app` | object | `{ uuid }` of your app |
| `buyer` | object | `{ uuid }` of the buyer |
| `metadata` | object | `client_metadata` captured with the original purchase. `{}` when none was set |

`app.dispute.flagged` is an early chargeback warning. A dispute is likely and no formal chargeback has been filed, so prepare evidence or refund pre-emptively. `app.dispute.created` is the formal dispute. The same payment can produce a `flagged` event and later a `created` event, and the money moves only when `app.refund.created` arrives with `reason: "chargeback"`.

### Example: `app.dispute.created`

```json theme={null}
{
  "id": "5f60718293a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7081920",
  "type": "app.dispute.created",
  "timestamp": "2026-06-19T08:41:00.000Z",
  "data": {
    "object": "dispute",
    "id": "dp_7f3a9c2e1b4d",
    "status": "open",
    "amount": 999,
    "currency": "USD",
    "reason": null,
    "created_at": "2026-06-19T08:41:00.000Z",
    "payment": { "id": "INV-2026-000123", "transaction_id": "txn_4b8e2a9f" },
    "item": { "uuid": "b2d7c9f0-4a13-4e6b-8f25-1a9c3e7d5b80" },
    "app": { "uuid": "a1c3e5f7-9b2d-4c6e-8a0f-2d4b6c8e0a13" },
    "buyer": { "uuid": "c4e6a8b0-2d4f-6a81-0c2e-4b6d8f0a2c46" },
    "metadata": {}
  }
}
```

`app.dispute.flagged` uses the identical shape with `"type": "app.dispute.flagged"` and `"status": "warning"`.

## Reconciling

`data.payment_id` on a refund and `data.payment.id` on a dispute carry the invoice number of the original payment, which you re-read with `GET /apps/{appUuid}/payments/{invoiceNumber}`. See [Reconciliation](/docs/webhooks/app/overview#reconciliation).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.