> ## 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 Refunds and Disputes

> app.refund.created, the deprecated app.payment.refunded alias, app.dispute.flagged, and app.dispute.created.

Refunds and disputes use two resources: `refund` and `dispute`. Both are
delivered in the [Standard-Webhooks
envelope](/docs/app-store/webhooks#event-envelope); the fields below describe the
`data` object. Every event requires the `read:self` scope.

| Event (`type`)         | Resource | 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` (see below)           |
| `app.dispute.flagged`  | dispute  | An early chargeback warning is raised, before a formal dispute |
| `app.dispute.created`  | dispute  | A formal dispute (chargeback) is opened                        |

<Note>
  These events cover **one-time purchases only**, identified by a
  `purchase_reference` with the `appotp_` prefix. Subscription reversals and
  chargebacks are reconciled through the [App
  Subscriptions](/docs/app-store/app-subscriptions) endpoints, not these webhooks.
</Note>

## Refund resource

`data.object` is `"refund"`. The refund references the original payment via
`payment_id`, carries `amount` (not `gross`), and has no `status` or `paid_at`.

| Field                 | Type           | Description                                                     |
| --------------------- | -------------- | --------------------------------------------------------------- |
| `object`              | string         | Always `"refund"`                                               |
| `id`                  | string         | Fanvue invoice number for the refund                            |
| `payment_id`          | string         | Invoice number of the original payment                          |
| `amount`              | integer        | Refunded amount in minor units (positive)                       |
| `currency`            | string \| null | ISO 4217 currency code                                          |
| `reason`              | string         | `refund` \| `chargeback` \| `cancel`                            |
| `purchase_reference`  | string         | The one-time purchase reference (`appotp_` prefix)              |
| `client_reference_id` | string \| null | Reserved passthrough reference (currently always `null`)        |
| `created_at`          | string \| null | ISO 8601 creation time                                          |
| `item`                | object         | `{ uuid }` of the purchased pricing plan (`uuid` may be `null`) |
| `app`                 | object         | `{ uuid }` of your app                                          |
| `buyer`               | object         | `{ uuid }` of the buyer                                         |
| `metadata`            | object         | Reserved passthrough metadata map (currently always empty)      |

### 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,
    "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" },
    "metadata": {}
  }
}
```

<Note>
  `reason` tells the three refund paths apart: `refund` (a normal refund),
  `chargeback` (a dispute resolved against the sale), and `cancel` (the purchase
  was cancelled).
</Note>

<Warning>
  **`app.payment.refunded` is deprecated.** It is the legacy alias of
  `app.refund.created` and is dual-emitted with an identical `data` body (only
  the `type` differs) during the migration window so existing integrations keep
  working. Subscribe to `app.refund.created` for new integrations; do not handle
  both, or you will double-count refunds.
</Warning>

## Dispute resource

`data.object` is `"dispute"`. Both `app.dispute.flagged` (an early warning,
before a formal chargeback) and `app.dispute.created` (the formal chargeback)
share the `dispute` resource. Use `source` to identify the provider that
reported it.

<Note>
  `app.dispute.flagged` is an **early chargeback warning**: a partner has
  signalled that a dispute is likely, but no formal chargeback has been filed
  yet. Treat it as a heads-up to prepare evidence or pre-emptively refund.
  `app.dispute.created` is the **formal dispute** being opened, and the same
  payment can produce a `flagged` event and later a `created` event.
</Note>

| Field        | Type            | Description                                                     |
| ------------ | --------------- | --------------------------------------------------------------- |
| `object`     | string          | Always `"dispute"`                                              |
| `id`         | string          | Processor dispute / alert id                                    |
| `status`     | string \| null  | Processor status (e.g. `needs_response`)                        |
| `amount`     | integer \| null | Disputed amount in minor units                                  |
| `currency`   | string \| null  | ISO 4217 currency code                                          |
| `reason`     | string \| null  | Dispute reason, if provided                                     |
| `source`     | string          | `chargeback_help` \| `primer`                                   |
| `created_at` | string \| null  | ISO 8601 time the dispute was reported                          |
| `payment`    | object          | The disputed payment: `{ id, transaction_id }`                  |
| `item`       | object          | `{ uuid }` of the purchased pricing plan (`uuid` may be `null`) |
| `app`        | object          | `{ uuid }` of your app                                          |
| `buyer`      | object          | `{ uuid }` of the buyer                                         |
| `metadata`   | object          | Reserved passthrough metadata map (currently always empty)      |

### 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_abc123",
    "status": "needs_response",
    "amount": 999,
    "currency": "USD",
    "reason": null,
    "source": "primer",
    "created_at": "2026-06-19T08:41:00.000Z",
    "payment": { "id": "INV-2026-000123", "transaction_id": "txn_abc" },
    "item": { "uuid": "b2d7c9f0-4a13-4e6b-8f25-1a9c3e7d5b80" },
    "app": { "uuid": "a1c3e5f7-9b2d-4c6e-8a0f-2d4b6c8e0a13" },
    "buyer": { "uuid": "c4e6a8b0-2d4f-6a81-0c2e-4b6d8f0a2c46" },
    "metadata": {}
  }
}
```

The `app.dispute.flagged` event uses the identical shape with
`"type": "app.dispute.flagged"`; treat it as an early heads-up to prepare
evidence before a formal chargeback is filed.

## Reconciling

`data.payment_id` (refund) and `data.payment.id` (dispute) both carry the
invoice number of the original payment, which you can re-read with the app
payments endpoints. See
[Reconciliation](/docs/app-store/webhooks#reconciliation).
