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

# Contract Webhooks — Payload Reference | Grow CRM

> Full payload reference for Grow CRM contract webhooks — created, updated, sundry, and deleted — covering dual signing, publication, and status events.

Grow CRM fires four distinct event keys for contract records: `contract.created`, `contract.updated`, `contract.deleted`, and `contract.sundry`. Use these events to trigger onboarding workflows when a contract is signed, enforce expiry policies when status changes, and keep external document management systems in sync. There is **no `contract.activity`** event — contracts have no comments, attachments, or logs.

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

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

```json theme={null}
{
  "id": 33,
  "title": "Website Redesign Contract",
  "status": "draft",
  "value": "5000.00",
  "client": { "id": 12, "name": "Acme Inc" },
  "category": { "id": 1, "name": "Default" },
  "project_id": null,
  "dates": {
    "start": "2026-07-16",
    "end": "2027-07-16",
    "created": "2026-07-16T08:00:00.000000Z",
    "published": null
  },
  "signing": { "client_status": "unsigned", "provider_status": "unsigned" },
  "tags": []
}
```

<ResponseField name="id" type="integer">
  The contract's primary key (`doc_id`).
</ResponseField>

<ResponseField name="title" type="string">
  The contract title.
</ResponseField>

<ResponseField name="status" type="string">
  One of `draft`, `awaiting_signatures`, `active`, or `expired` — the raw status value. There is no `{ title, color }` wrapper object around this value.
</ResponseField>

<ResponseField name="value" type="string">
  The monetary value of the contract, expressed as a decimal string.
</ResponseField>

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

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

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

<ResponseField name="dates" type="object">
  `start`, `end`, and `published` are date-only strings (or `null`); `created` is an ISO 8601 timestamp with microseconds.
</ResponseField>

<ResponseField name="signing" type="object">
  `client_status` and `provider_status` — each holds the raw signature status string for that party.
</ResponseField>

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

***

## `contract.created`

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

```json theme={null}
{
  "event": "contract.created",
  "id": 33,
  "created": "2026-07-16T08:00:00+00:00",
  "data": {
    "id": 33,
    "title": "Website Redesign Contract",
    "status": "draft",
    "...": "..."
  }
}
```

***

## `contract.updated`

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

<Note>
  There is no `edited` change value for contracts. Grow CRM has no `ContractUpdated` event for general edits because contracts are modified through the builder interface, not a standard form.
</Note>

| `data.change`       | Fires when                                              |
| ------------------- | ------------------------------------------------------- |
| `status`            | The contract's status changes.                          |
| `published`         | The contract is published.                              |
| `sent`              | The contract email is sent or resent.                   |
| `signed`            | The client signs the contract.                          |
| `team_signed`       | The provider/team side signs the contract.              |
| `signature_removed` | A signature is removed from the contract.               |
| `automation`        | The contract's automation settings are updated.         |
| `project`           | The contract is attached to or detached from a project. |

```json theme={null}
{
  "event": "contract.updated",
  "id": 33,
  "created": "2026-07-16T08:05:00+00:00",
  "data": {
    "change": "signed",
    "contract": {
      "id": 33,
      "signing": { "client_status": "signed", "provider_status": "unsigned" },
      "...": "..."
    }
  }
}
```

<Tip>
  To detect a fully countersigned contract, listen for `change: "team_signed"` and confirm that both `signing.client_status` and `signing.provider_status` are `"signed"` in the delivered `data.contract`.
</Tip>

***

## `contract.sundry`

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

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

```json theme={null}
{
  "event": "contract.sundry",
  "id": 33,
  "created": "2026-07-16T08:07:00+00:00",
  "data": {
    "field": "category",
    "contract": { "id": 33, "category": { "id": 2, "name": "Legal" }, "...": "..." }
  }
}
```

***

## `contract.deleted`

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

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