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

# Refund Webhook Events: Full Payload Reference Guide

> Reference for refund webhook events—created, updated, deleted, and sundry—with payload shapes, field tables, and co-firing rules with payment events.

Grow CRM emits webhook events whenever a refund record is created, changed, or removed. Your endpoint may receive four event keys: `refund.created`, `refund.updated`, `refund.deleted`, and `refund.sundry`. There is no `refund.activity` — refunds have no comments, attachments, or activity logs. A refund always belongs to exactly one payment, and a payment can have at most one refund. Because refunding and un-refunding a payment also mutates the payment record itself, each of those actions fires a companion `payment.updated` event alongside the refund event — subscribe to whichever fits your integration, or both if you need the full picture.

<Note>
  The webhook envelope structure, delivery behaviour, and retry logic are documented in [Introduction](/introduction). Signature verification is covered in [Verification](/verification). Those conventions apply to every event on this page and are not repeated here.
</Note>

***

## Refund and payment events fire together

A refund can be created or removed from two places — the Refunds section, or the refund button on the Payments list. Both trigger the same events regardless of which UI path is used.

| Action          | Events fired                                                            |
| --------------- | ----------------------------------------------------------------------- |
| Refund recorded | `refund.created` **and** `payment.updated` (`change: "refunded"`)       |
| Refund removed  | `refund.deleted` **and** `payment.updated` (`change: "refund_removed"`) |

You do not need to subscribe to both event keys. Choose the event that describes the fact your integration cares about: `refund.created` / `refund.deleted` gives you the refund record details; `payment.updated` gives you the payment's updated status.

***

## The refund object

Every event key except `refund.deleted` carries the full refund object. In `refund.created` the object appears flat inside `data`; in `refund.updated` and `refund.sundry` it is nested under `data.refund`.

| Field        | Type             | Notes                                                                                                                            |
| ------------ | ---------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `id`         | integer          | Unique refund identifier.                                                                                                        |
| `uniqueid`   | string           | Secondary unique identifier for the refund.                                                                                      |
| `amount`     | string           | Decimal as string. Always the full payment amount — refunds are not partial.                                                     |
| `date`       | string           | Date only — also present in `dates.date`.                                                                                        |
| `notes`      | string \| null   |                                                                                                                                  |
| `payment_id` | integer          | The id of the refunded payment.                                                                                                  |
| `invoice`    | object           | `{ id, formatted_id }` — copied from the payment.                                                                                |
| `client`     | object           | `{ id, name }` — copied from the payment.                                                                                        |
| `dates`      | object           | Raw database values. `created` uses `Y-m-d H:i:s` format, **not** the ISO-with-microseconds format used by most other resources. |
| `tags`       | array of strings |                                                                                                                                  |

<Info>
  The `dates.created` timestamp on refund objects is a raw database value in `Y-m-d H:i:s` format (for example `"2026-07-31 09:00:00"`), not the ISO 8601 with microseconds format you see on invoices, payments, and expenses.
</Info>

```json theme={null}
{
  "id": 31,
  "uniqueid": "k38fj2ma",
  "amount": "250.00",
  "date": "2026-07-31",
  "notes": "Duplicate charge",
  "payment_id": 118,
  "invoice": { "id": 402, "formatted_id": "INV-0402" },
  "client": { "id": 12, "name": "Acme Inc" },
  "dates": { "date": "2026-07-31", "created": "2026-07-31 09:00:00" },
  "tags": []
}
```

***

## `refund.created`

Fires when a refund is created, whether from the Refunds section or the Payments list. `data` is the full refund object.

```json theme={null}
{
  "event": "refund.created",
  "id": 31,
  "created": "2026-07-31T09:00:00+00:00",
  "data": {
    "id": 31,
    "uniqueid": "k38fj2ma",
    "amount": "250.00",
    "date": "2026-07-31",
    "notes": "Duplicate charge",
    "payment_id": 118,
    "invoice": { "id": 402, "formatted_id": "INV-0402" },
    "client": { "id": 12, "name": "Acme Inc" },
    "dates": { "date": "2026-07-31", "created": "2026-07-31 09:00:00" },
    "tags": []
  }
}
```

***

## `refund.updated`

Fires when a significant change is made to a refund. Read `data.change` to determine what changed; `data.refund` contains the full refund object.

| `data.change` | Fires when                                                                                                                               |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `edited`      | The refund edit form is saved. Only the date and notes are editable — the amount is fixed to the payment's amount and cannot be changed. |

```json theme={null}
{
  "event": "refund.updated",
  "id": 31,
  "created": "2026-07-31T09:10:00+00:00",
  "data": {
    "change": "edited",
    "refund": {
      "id": 31,
      "date": "2026-08-01",
      "notes": "Corrected date",
      "...": "..."
    }
  }
}
```

***

## `refund.sundry`

Fires when a minor or cosmetic field is edited. Read `data.field` to determine which field changed; `data.refund` contains the full refund object.

| `data.field` | Fires when                     |
| ------------ | ------------------------------ |
| `tags`       | The refund's tags are changed. |

```json theme={null}
{
  "event": "refund.sundry",
  "id": 31,
  "created": "2026-07-31T09:12:00+00:00",
  "data": {
    "field": "tags",
    "refund": {
      "id": 31,
      "tags": ["disputed"],
      "...": "..."
    }
  }
}
```

***

## `refund.deleted`

Fires after the refund is permanently deleted, whether from the Refunds section or the Payments list. Because the record no longer exists, `data` contains only the refund `id`.

When you delete refunds from the Refunds section using the checkbox selection, removing several refunds at once delivers one event **per refund** — not one event containing a list.

```json theme={null}
{
  "event": "refund.deleted",
  "id": 31,
  "created": "2026-07-31T09:20:00+00:00",
  "data": { "id": 31 }
}
```
