Event reference
All events share the envelope described in Getting started:{ event, id, created, data }. id is always the id of the resource the event is about.
This page explains the shape every resource follows. For a specific resource’s exact fields, its
list of change/field/activity values, and full example payloads, go to its own page — linked
in the table below.
The five keys per resource
Every resource exposes up to five subscribable keys. Instead of a long list of narrow keys, related changes are grouped and a discriminator insidedata tells you exactly what happened:
Subscribe once to
<resource>.updated and branch on data.change — you do not need a separate
subscription per change type. The same is true for .sundry (branch on data.field) and
.activity (branch on data.type + data.action).
.updated/.sundryalways carry the complete, current resource object — not a diff. Whatever single thing changed,data.<resource>reflects the record’s full state afterwards..activity’sdata.itemshape depends ondata.type(comment,attachment,note,checklist,checklist_comment,milestone,task,log, orreply) — see the resource’s own page for which types it produces and their exact fields, including which delete actions carry a full item vs. just{ "id": ... }.data.actionis normallyadded,updatedordeleted. Checklists add one more,status_changed, for ticking an item off — see Projects.
Deletion events (*.deleted) fire after the record is gone, sodatais just{ "id": <deleted id> }.
Dates
The envelope’s top-levelcreated field is ISO 8601 with a UTC offset
(2026-07-13T10:15:00+00:00). Inside data, it depends on the field: any created/updated
timestamp that names a record’s own creation/update — the resource’s dates.created/dates.updated,
and the created field on .activity items (comment/attachment/log/reply) — is ISO 8601 with
microseconds and a literal Z (2026-07-13T10:15:00.000000Z). Every one of these models (Client,
Lead, Comment, Attachment, LeadLog, TicketReply, etc.) recasts its create/update columns to
Carbon instances via Eloquent’s CREATED_AT/UPDATED_AT constants, which is what produces this
format instead of a plain string. Every other date/time field (due dates, sent dates, expiry dates,
a ticket’s last_updated, etc.) is a raw database value — Y-m-d H:i:s for timestamps, Y-m-d for
date-only fields — not reformatted at all. Check each resource’s own page for exactly which fields
are which; don’t assume from the field name alone.
Resources
Proposals, Contracts, Payments and Refunds have no
.activity key — none of them has comments,
attachments, or logs in core. Timesheets and Team are lifecycle-only: a time entry has no minor
fields and no child records, and a team member’s changes all arrive as team.updated.
Imports
Records created by a bulk import do not fire<resource>.created. Importers write rows
directly rather than going through the normal create path, so a 5,000-row import would otherwise
produce 5,000 separate deliveries. Instead, the four importable resources — Clients, Leads, Projects
and Products — fire a single <resource>.imported event carrying the batch:
Batching. Large imports are split across several deliveries of up to 1,000 records each, so a
single request never grows large enough to be rejected by a receiver (nginx, for example, refuses
request bodies over 1 MB by default). Every batch of one import shares the same
import_ref, and
batch/batch_count tell you how to reassemble them. Batches are queued in id order and delivered
independently, so treat them as a set that has arrived only once you have seen batch_count of them.
Records are deliberately compact — enough to identify each row and match it to your own data.
If you need the full record, read it back from the API using its id.
Checklist imports do not fire an import event; they create child records rather than resources.