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

# Invoice Webhook Events: Full Payload Reference Guide

> Reference for invoice webhook events—created, updated, deleted, sundry, and activity—with payload shapes, field tables, and discriminator values.

Grow CRM emits webhook events across the full invoice lifecycle. Your endpoint may receive any of five event keys: `invoice.created`, `invoice.updated`, `invoice.deleted`, `invoice.sundry`, and `invoice.activity`. Use `invoice.updated` to track significant state transitions such as publishing, payment, or cancellation; use `invoice.sundry` for lower-significance field edits such as category or tag changes; and use `invoice.activity` to react to file attachments. Note that recording a payment that fully settles an invoice fires both a `payment.created` event **and** an `invoice.updated` event 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>

***

## The invoice object

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

| Field        | Type             | Notes                                                                                                                                             |
| ------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`         | integer          | Unique invoice identifier.                                                                                                                        |
| `status`     | object           | `{ id, title, color }` — the resolved status label and colour.                                                                                    |
| `client`     | object           | `{ id, name }`.                                                                                                                                   |
| `project_id` | integer \| null  |                                                                                                                                                   |
| `category`   | object           | `{ id, name }`.                                                                                                                                   |
| `dates`      | object           | `date` and `due_date` are date-only strings; `created` is ISO 8601 with microseconds.                                                             |
| `notes`      | string \| null   |                                                                                                                                                   |
| `tax_type`   | string           | `summary`, `inline`, or `none`.                                                                                                                   |
| `totals`     | object           | `subtotal`, `discount_type` (`amount`, `percentage`, or `none`), `discount_amount`, `tax_total_amount`, `final_amount` — all decimals as strings. |
| `line_items` | array            | One object per line item — see the field breakdown below.                                                                                         |
| `taxes`      | array            | `[{ name, rate }]`.                                                                                                                               |
| `tags`       | array of strings |                                                                                                                                                   |

**Line item fields**

| Field         | Type    | Notes                             |
| ------------- | ------- | --------------------------------- |
| `id`          | integer |                                   |
| `description` | string  |                                   |
| `unit`        | string  |                                   |
| `quantity`    | string  | Decimal as string.                |
| `rate`        | string  | Decimal as string.                |
| `total`       | string  | Decimal as string.                |
| `type`        | string  | `plain` or other configured type. |
| `tax_status`  | string  | `taxable` or `not_taxable`.       |
| `discount`    | object  | `{ type, value, amount }`.        |

```json theme={null}
{
  "id": 295,
  "status": { "id": 1, "title": "Draft", "color": "default" },
  "client": { "id": 12, "name": "Acme Inc" },
  "project_id": null,
  "category": { "id": 4, "name": "Default" },
  "dates": {
    "date": "2026-07-13",
    "due_date": "2026-08-12",
    "created": "2026-07-13T10:15:00.000000Z"
  },
  "notes": null,
  "tax_type": "summary",
  "totals": {
    "subtotal": "250.00",
    "discount_type": "amount",
    "discount_amount": "25.00",
    "tax_total_amount": "22.50",
    "final_amount": "247.50"
  },
  "line_items": [
    {
      "id": 1,
      "description": "Item A",
      "unit": "hours",
      "quantity": "2.00",
      "rate": "100.00",
      "total": "200.00",
      "type": "plain",
      "tax_status": "taxable",
      "discount": { "type": "none", "value": "0.00", "amount": "0.00" }
    }
  ],
  "taxes": [{ "name": "VAT", "rate": "10.00" }],
  "tags": ["priority"]
}
```

***

## `invoice.created`

Fires when an invoice is created, **including when an existing invoice is cloned**. `data` is the full invoice object.

```json theme={null}
{
  "event": "invoice.created",
  "id": 295,
  "created": "2026-07-13T10:15:00+00:00",
  "data": {
    "id": 295,
    "status": { "id": 1, "title": "Draft", "color": "default" },
    "client": { "id": 12, "name": "Acme Inc" },
    "project_id": null,
    "category": { "id": 4, "name": "Default" },
    "dates": {
      "date": "2026-07-13",
      "due_date": "2026-08-12",
      "created": "2026-07-13T10:15:00.000000Z"
    },
    "notes": null,
    "tax_type": "summary",
    "totals": {
      "subtotal": "250.00",
      "discount_type": "amount",
      "discount_amount": "25.00",
      "tax_total_amount": "22.50",
      "final_amount": "247.50"
    },
    "line_items": [
      {
        "id": 1,
        "description": "Item A",
        "unit": "hours",
        "quantity": "2.00",
        "rate": "100.00",
        "total": "200.00",
        "type": "plain",
        "tax_status": "taxable",
        "discount": { "type": "none", "value": "0.00", "amount": "0.00" }
      }
    ],
    "taxes": [{ "name": "VAT", "rate": "10.00" }],
    "tags": ["priority"]
  }
}
```

***

## `invoice.updated`

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

| `data.change` | Fires when                                                               |
| ------------- | ------------------------------------------------------------------------ |
| `edited`      | The main invoice edit form is saved.                                     |
| `published`   | The invoice is published.                                                |
| `paid`        | A payment is recorded that brings the invoice balance to fully **Paid**. |
| `sent`        | The invoice email is sent or resent.                                     |
| `status`      | The invoice's status is changed manually from the status dropdown.       |
| `cancelled`   | The invoice is cancelled.                                                |
| `restored`    | A cancelled invoice is restored.                                         |
| `client`      | The invoice's client is reassigned.                                      |
| `tax_type`    | The tax type (`summary` / `inline` / `none`) is changed.                 |
| `recurring`   | The invoice's recurring settings are updated or stopped.                 |
| `project`     | The invoice is attached to or detached from a project.                   |

<Tip>
  The `paid` change is co-fired by the payment recording action. Subscribe to [Payments](/webhooks/payments) as well if you also need the payment amount and gateway details.
</Tip>

```json theme={null}
{
  "event": "invoice.updated",
  "id": 295,
  "created": "2026-07-13T10:20:00+00:00",
  "data": {
    "change": "paid",
    "invoice": {
      "id": 295,
      "status": { "id": 4, "title": "Paid", "color": "success" },
      "...": "..."
    }
  }
}
```

***

## `invoice.sundry`

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

| `data.field` | Fires when                         |
| ------------ | ---------------------------------- |
| `category`   | The invoice's category is changed. |
| `tags`       | The invoice's tags are edited.     |

```json theme={null}
{
  "event": "invoice.sundry",
  "id": 295,
  "created": "2026-07-16T08:07:00+00:00",
  "data": {
    "field": "category",
    "invoice": {
      "id": 295,
      "category": { "id": 4, "name": "Default" },
      "...": "..."
    }
  }
}
```

***

## `invoice.activity`

Fires when a child record on the invoice changes. Invoices produce only `type: "attachment"` — invoices are not part of the core comment system. Read `data.action` to distinguish additions from deletions.

| `data.type`  | `data.action` | `data.item` shape                                                                               |
| ------------ | ------------- | ----------------------------------------------------------------------------------------------- |
| `attachment` | `added`       | `{ id, uniqueid, filename }`                                                                    |
| `attachment` | `deleted`     | `{ id, uniqueid, filename }` when the file record is still found; otherwise no event is queued. |

<Warning>
  Unlike estimates, the invoice file-deletion event has no pre-delete hook. By the time the webhook listener runs, the file row may already be gone. The lookup is **best-effort**: if the record is still found the full item shape is delivered; if not, no `invoice.activity` delivery is queued for that deletion at all — not even a minimal `{ id }`.
</Warning>

```json theme={null}
{
  "event": "invoice.activity",
  "id": 295,
  "created": "2026-07-16T08:10:00+00:00",
  "data": {
    "type": "attachment",
    "action": "added",
    "item": {
      "id": 51,
      "uniqueid": "7yfhe47487",
      "filename": "invoice-attachment.pdf"
    }
  }
}
```

***

## `invoice.deleted`

Fires after the invoice is permanently deleted. Because the record no longer exists, `data` contains only the invoice `id`.

```json theme={null}
{
  "event": "invoice.deleted",
  "id": 295,
  "created": "2026-07-16T08:15:00+00:00",
  "data": { "id": 295 }
}
```
