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

# Estimate Webhooks — Payload Reference | Grow CRM

> Full payload reference for Grow CRM estimate webhooks — created, updated, sundry, activity, and deleted — including line item shapes and JSON examples.

Grow CRM fires five distinct event keys for estimate records: `estimate.created`, `estimate.updated`, `estimate.deleted`, `estimate.sundry`, and `estimate.activity`. Use these events to automate approval workflows, sync billing data to external accounting systems, and react to client acceptance or decline in real time.

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

***

## The estimate object

Every event key except `estimate.deleted` carries the full estimate object. For `estimate.created` it appears flat directly inside `data`; for `estimate.updated` and `estimate.sundry` it is nested under `data.estimate`.

```json theme={null}
{
  "id": 118,
  "status": "draft",
  "client": { "id": 12, "name": "Acme Inc" },
  "project_id": null,
  "category": { "id": 4, "name": "Default" },
  "dates": {
    "date": "2026-07-16",
    "expiry_date": "2026-08-15",
    "created": "2026-07-16T08:00: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"]
}
```

<ResponseField name="id" type="integer">
  The estimate's numeric primary key.
</ResponseField>

<ResponseField name="status" type="string">
  One of `draft`, `new`, `accepted`, `revised`, `declined`, or `expired` — the raw status value. Unlike invoices and tickets, there is no `{ title, color }` wrapper object around this value.
</ResponseField>

<ResponseField name="client" type="object">
  `{ id, name }` — the client this estimate belongs to.
</ResponseField>

<ResponseField name="project_id" type="integer | null">
  Set when the estimate is attached to a project; otherwise `null`.
</ResponseField>

<ResponseField name="category" type="object">
  `{ id, name }` — the estimate category.
</ResponseField>

<ResponseField name="dates" type="object">
  `date` and `expiry_date` are date-only strings; `created` is an ISO 8601 timestamp with microseconds.
</ResponseField>

<ResponseField name="notes" type="string | null">
  Free-text notes on the estimate; `null` when not set.
</ResponseField>

<ResponseField name="tax_type" type="string">
  One of `summary`, `inline`, or `none`.
</ResponseField>

<ResponseField name="totals" type="object">
  `subtotal`, `discount_type` (`amount`, `percentage`, or `none`), `discount_amount`, `tax_total_amount`, and `final_amount` — all decimals expressed as strings.
</ResponseField>

<ResponseField name="line_items" type="array">
  Array of line item objects. See the [line item shape](#the-line-item-shape) below.
</ResponseField>

<ResponseField name="taxes" type="array">
  `[{ name, rate }]` — applied tax rates.
</ResponseField>

<ResponseField name="tags" type="array of strings">
  Tag titles attached to the estimate.
</ResponseField>

### The line item shape

<Expandable title="Line item field reference">
  | Field         | Type           | Notes                                                                   |
  | ------------- | -------------- | ----------------------------------------------------------------------- |
  | `id`          | integer        | The line item's numeric primary key.                                    |
  | `description` | string         | Line item description text.                                             |
  | `unit`        | string \| null | Unit label (e.g. `hours`).                                              |
  | `quantity`    | string         | Decimal as string.                                                      |
  | `rate`        | string         | Decimal as string.                                                      |
  | `total`       | string         | Decimal as string.                                                      |
  | `type`        | string         | `plain`, `time`, or `dimensions`.                                       |
  | `tax_status`  | string         | `taxable` or `exempt`.                                                  |
  | `discount`    | object         | `{ type, value, amount }` — `type` is `none`, `fixed`, or `percentage`. |
</Expandable>

***

## `estimate.created`

Grow CRM fires `estimate.created` immediately after a new estimate is saved, **including when an estimate is cloned**. `data` is the full estimate object shown above.

```json theme={null}
{
  "event": "estimate.created",
  "id": 118,
  "created": "2026-07-16T08:00:00+00:00",
  "data": { "id": 118, "status": "draft", "client": { "id": 12, "name": "Acme Inc" }, "...": "..." }
}
```

***

## `estimate.updated`

Grow CRM fires `estimate.updated` whenever a significant field or lifecycle state on the estimate changes. Inspect `data.change` to determine what changed; `data.estimate` always carries the complete, up-to-date estimate object.

| `data.change` | Fires when                                                                                                                                        |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `edited`      | The main estimate edit form is saved.                                                                                                             |
| `status`      | The estimate's status changes.                                                                                                                    |
| `accepted`    | The client accepts the estimate.                                                                                                                  |
| `declined`    | The client declines the estimate.                                                                                                                 |
| `published`   | The estimate is published.                                                                                                                        |
| `sent`        | The estimate email is sent or resent.                                                                                                             |
| `converted`   | The estimate is converted to an invoice. `data.estimate` still describes the estimate — listen on invoice webhooks for the resulting new invoice. |
| `tax_type`    | The tax type (summary, inline, or none) is changed.                                                                                               |
| `automation`  | The estimate's automation settings are updated.                                                                                                   |
| `project`     | The estimate is attached to or detached from a project.                                                                                           |

```json theme={null}
{
  "event": "estimate.updated",
  "id": 118,
  "created": "2026-07-16T08:05:00+00:00",
  "data": {
    "change": "accepted",
    "estimate": { "id": 118, "status": "accepted", "...": "..." }
  }
}
```

***

## `estimate.sundry`

Grow CRM fires `estimate.sundry` for minor field edits that don't warrant a full `estimate.updated` signal. Inspect `data.field` to identify which field changed; `data.estimate` carries the full estimate object — it is not a partial diff.

| `data.field` | Fires when                          |
| ------------ | ----------------------------------- |
| `category`   | The estimate's category is changed. |

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

***

## `estimate.activity`

Grow CRM fires `estimate.activity` whenever an attachment on the estimate is added or removed. Estimates have no comments or logs, so this event only ever carries `type: "attachment"`.

<Note>
  The estimate attachment shape does **not** include a `created` timestamp.
</Note>

| `data.type`  | `data.action` | `data.item` shape                                                                                                         |
| ------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `attachment` | `added`       | `{ id, uniqueid, filename }` — no `created` field on this shape.                                                          |
| `attachment` | `deleted`     | `{ id, uniqueid, filename }` — the file record is looked up **before** removal, so the full shape is available on delete. |

```json theme={null}
{
  "event": "estimate.activity",
  "id": 118,
  "created": "2026-07-16T08:10:00+00:00",
  "data": {
    "type": "attachment",
    "action": "added",
    "item": { "id": 44, "uniqueid": "dg746287", "filename": "scope.pdf" }
  }
}
```

***

## `estimate.deleted`

Grow CRM fires `estimate.deleted` after the estimate record is permanently removed. Because the record no longer exists, `data` contains only the estimate's `id`.

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