> ## 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.

# Payment Webhook Events: Full Payload Reference Guide

> Reference for payment webhook events—created, updated, deleted, and sundry—with full payload shapes, field tables, and pairing with invoice events.

Grow CRM emits webhook events for every stage of a payment's life. Your endpoint may receive four event keys: `payment.created`, `payment.updated`, `payment.deleted`, and `payment.sundry`. There is no `payment.activity` — payments have no comments, attachments, or activity logs. Recording a payment against an invoice always fires `payment.created`; if that payment brings the invoice balance to zero, the same underlying action also fires `invoice.updated` with `change: "paid"` — subscribe to both if your integration needs to act on each fact separately.

<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>

***

## One action, two webhooks

Recording a payment against an invoice always fires `payment.created`. If that payment brings the invoice's balance to fully paid, the **same** underlying action also fires [`invoice.updated` with `change: "paid"`](/webhooks/invoices#invoice-updated). Subscribe to both events if you need to know both "a payment came in" and "this invoice is now settled".

***

## The payment object

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

| Field            | Type             | Notes                                                                                             |
| ---------------- | ---------------- | ------------------------------------------------------------------------------------------------- |
| `id`             | integer          | Unique payment identifier.                                                                        |
| `status`         | string           | `paid` or `refunded`.                                                                             |
| `amount`         | string           | Decimal as string.                                                                                |
| `date`           | string           | Date only — also present in `dates.date`.                                                         |
| `gateway`        | string           | `paypal`, `stripe`, `cash`, or `bank`.                                                            |
| `transaction_id` | string \| null   | Gateway transaction reference, when applicable.                                                   |
| `notes`          | string \| null   |                                                                                                   |
| `invoice`        | object           | `{ id, formatted_id }`.                                                                           |
| `client`         | object           | `{ id, name }`.                                                                                   |
| `project_id`     | integer \| null  |                                                                                                   |
| `dates`          | object           | `date` is a raw date; `created` is ISO 8601 with microseconds.                                    |
| `refund`         | object           | `has_refund` (boolean) plus `id`, `amount`, and `date` — all `null` when `has_refund` is `false`. |
| `tags`           | array of strings |                                                                                                   |

```json theme={null}
{
  "id": 610,
  "status": "paid",
  "amount": "247.50",
  "date": "2026-07-16",
  "gateway": "bank",
  "transaction_id": null,
  "notes": null,
  "invoice": { "id": 295, "formatted_id": "INV-000295" },
  "client": { "id": 12, "name": "Acme Inc" },
  "project_id": null,
  "dates": {
    "date": "2026-07-16",
    "created": "2026-07-16T08:20:00.000000Z"
  },
  "refund": { "has_refund": false, "id": null, "amount": null, "date": null },
  "tags": []
}
```

***

## `payment.created`

Fires when a payment is recorded against an invoice. `data` is the full payment object.

```json theme={null}
{
  "event": "payment.created",
  "id": 610,
  "created": "2026-07-16T08:20:00+00:00",
  "data": {
    "id": 610,
    "status": "paid",
    "amount": "247.50",
    "date": "2026-07-16",
    "gateway": "bank",
    "transaction_id": null,
    "notes": null,
    "invoice": { "id": 295, "formatted_id": "INV-000295" },
    "client": { "id": 12, "name": "Acme Inc" },
    "project_id": null,
    "dates": {
      "date": "2026-07-16",
      "created": "2026-07-16T08:20:00.000000Z"
    },
    "refund": { "has_refund": false, "id": null, "amount": null, "date": null },
    "tags": []
  }
}
```

***

## `payment.updated`

Fires when a significant change is made to a payment. Read `data.change` to determine what changed; `data.payment` contains the full payment object reflecting its state after the change.

| `data.change`    | Fires when                                                                                |
| ---------------- | ----------------------------------------------------------------------------------------- |
| `edited`         | The payment's amount, date, gateway, transaction id, or notes are edited.                 |
| `refunded`       | The payment is refunded — `data.payment.refund.has_refund` is `true`.                     |
| `refund_removed` | A refund is removed from the payment — `data.payment.refund.has_refund` is `false` again. |

<Tip>
  When `change` is `refunded`, a companion `refund.created` event also fires. See [Refunds](/webhooks/refunds) for the refund record's own payload shape.
</Tip>

```json theme={null}
{
  "event": "payment.updated",
  "id": 610,
  "created": "2026-07-30T18:05:47+00:00",
  "data": {
    "change": "refunded",
    "payment": {
      "id": 610,
      "status": "refunded",
      "amount": "247.50",
      "date": "2026-07-16",
      "gateway": "bank",
      "transaction_id": null,
      "notes": null,
      "invoice": { "id": 295, "formatted_id": "INV-000295" },
      "client": { "id": 12, "name": "Acme Inc" },
      "project_id": null,
      "dates": {
        "date": "2026-07-16",
        "created": "2026-07-16T08:20:00.000000Z"
      },
      "refund": { "has_refund": true, "id": 11, "amount": "247.50", "date": "2026-07-30" },
      "tags": []
    }
  }
}
```

***

## `payment.sundry`

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

| `data.field` | Fires when                     |
| ------------ | ------------------------------ |
| `tags`       | The payment's tags are edited. |

```json theme={null}
{
  "event": "payment.sundry",
  "id": 610,
  "created": "2026-07-30T18:06:10+00:00",
  "data": {
    "field": "tags",
    "payment": {
      "id": 610,
      "tags": ["bank"],
      "...": "..."
    }
  }
}
```

***

## `payment.deleted`

Fires after the payment is permanently deleted. Because the record no longer exists, `data` contains only the payment `id`. Payments are deleted through a single route regardless of whether one or several are selected, so this event can fire for a single payment even though the underlying action supports deleting multiple at once.

```json theme={null}
{
  "event": "payment.deleted",
  "id": 610,
  "created": "2026-07-30T18:05:32+00:00",
  "data": { "id": 610 }
}
```
