Webhook Events
Every webhook event, when it fires, and the exact payload it sends.
For advanced users
This page is a technical reference for developers building against ITB webhooks. If you just want to set up a webhook endpoint, start with the Webhooks guide.
The event envelope
Every webhook delivery is an HTTP POST with a JSON body. All events share the same top-level envelope:
| Field | Type | Description |
|---|---|---|
id | string | Unique event ID, prefixed evt_ (32 hex characters). Use it as an idempotency key — the same event may be delivered more than once |
type | string | The event name, e.g. order.approved |
apiVersion | string | Date-based payload version. Currently 2026-07-01 |
createdAt | string | When the event occurred (ISO 8601) |
account.uid | string | The account (owner) ID the event belongs to |
account.companyName | string | Your company name, if set |
data | object | Snapshot of the resource the event is about (see per-event sections below) |
changes | object | Only on some events — previous and current snapshots of the fields that changed |
{
"id": "evt_9f2c4b7a1d3e5f60718293a4b5c6d7e8", // idempotency key
"type": "order.approved", // event name
"apiVersion": "2026-07-01",
"createdAt": "2026-07-28T14:30:00.000Z",
"account": {
"uid": "abc123",
"companyName": "Acme Home Services"
},
"data": { /* resource snapshot — see below */ },
"changes": { // only on *.approved, *.completed,
"previous": { "status": "new" }, // *.status_changed, *.rescheduled
"current": { "status": "approved" }
}
}Each delivery also carries the event name in the webhook-event request header, alongside the signature headers (webhook-id, webhook-timestamp, webhook-signature) described in the Webhooks guide.
Event index
| Event | Fires when | changes field |
|---|---|---|
order.created | A new Order is created — from the dashboard, the mobile app, or the online scheduling page | — |
order.approved | A Order's status becomes Approved (including one created as approved) | status |
order.completed | A Order's status becomes Complete | status |
order.rescheduled | The appointment date/time changes on an Approved Order | appointmentDateTime |
order.status_changed | Fires alongside order.approved and order.completed, and also when an Approved Order moves back to an earlier status | status |
invoice.paid | A Order is marked paid (its paid flag turns true for the first time) | — |
report.published | A Order first becomes both paid and agreement-signed — the point where its Report is released | — |
Status values in payloads are the raw stored values (draft, new, read, approved, complete, archived) — see Order Statuses.
Field names never change per industry
Payload field names are identical across all industries. For example, the Inspection Type is always sent in a field named inspectionType, whatever your industry calls it on screen.
Order events — data payload
order.created, order.approved, order.completed, order.rescheduled, and order.status_changed all send the same Order snapshot in data:
{
"id": "req_abc123", // order ID
"status": "approved", // see Order Statuses reference
"appointmentDateTime": "2026-08-01T13:00:00.000Z",
"inspectionType": "Buyer Inspection", // your service category name
"streetAddress": "123 Main St",
"city": "Springfield",
"region": "IL",
"postalCode": "62701",
"country": "US",
"timezone": "America/Chicago",
"contactName": "Jane Buyer",
"contactEmail": "jane@example.com",
"contactPhone": "(555) 123-4567",
"contactType": "client",
"totalPrice": 450,
"totalTime": 120, // duration in minutes
"paid": false,
"agreementSigned": true,
"assignedInspectors": ["uid1", "uid2"], // assigned team member IDs
"requestDateTime": "2026-07-20T09:15:00.000Z", // when the order was created
"approvedDateTime": "2026-07-21T10:00:00.000Z",
"completedDateTime": "2026-08-01T16:30:00.000Z"
}Date fields are ISO 8601 strings. Any field with no value is omitted from the payload rather than sent as null.
changes per order event
order.approved—changes.previous.status/changes.current.status(current is always"approved")order.completed—changes.previous.status/changes.current.status(current is always"complete")order.status_changed—changes.previous.status/changes.current.statusorder.rescheduled—changes.previous.appointmentDateTime/changes.current.appointmentDateTime(ISO 8601 strings)order.created— nochangesfield
Approval fires two events
Approving a Order dispatches both order.approved and order.status_changed; completing one dispatches both order.completed and order.status_changed. Subscribe to one or the other unless you want both deliveries.
invoice.paid — data payload
Fires the first time a Order's paid flag becomes true. The data payload is the same Order snapshot shown above — not an invoice object. There are no invoice-specific fields (no invoice number, amount paid, or payment method); use totalPrice and the paid: true flag, or fetch invoice details from the API. No changes field is sent.
report.published — data payload
Fires when a Order first becomes both paid and agreement-signed — the point where its published Report is released to the client. The data payload is the Order snapshot shown above, plus one extra field:
{
"orderId": "req_abc123", // same as data.id — the order this report belongs to
"id": "req_abc123",
"status": "complete"
// …all other order snapshot fields
}No changes field is sent. The payload does not include report URLs.
Events you can subscribe to but that don't fire yet
The endpoint editor also lists order.updated, invoice.created, contact.created, and contact.updated. These event names are reserved and can be selected, but no account activity currently produces them — endpoints subscribed to only these events will not receive deliveries. If they are emitted in the future they will use the standard envelope; their data fields are not yet defined.
Test events — webhook.test
Clicking Test on an endpoint sends a webhook.test event:
{
"id": "evt_test_5f0e…", // prefixed evt_test_
"type": "webhook.test",
"apiVersion": "2026-07-01",
"createdAt": "2026-07-28T14:30:00.000Z",
"account": { "uid": "abc123" },
"data": {
"message": "This is a test webhook event.",
"timestamp": "2026-07-28T14:30:00.000Z"
}
}Test events are not signed — they carry an X-Webhook-Test: true header instead of the signature headers. Your receiver should accept them without signature verification (or recognize the header and skip verification for tests only).
Responding to deliveries
- Respond with any 2xx status within 10 seconds to acknowledge a delivery.
- 5xx responses and timeouts are treated as temporary — the delivery is retried.
- Other 4xx responses are treated as permanent — that delivery is not retried.
- Responding 410 Gone tells ITB to stop sending: the endpoint is disabled immediately.
Endpoint limits, automatic disabling after repeated failures, delivery history, and signature verification are covered in the Webhooks guide.
Related
- Webhooks — set up endpoints, secrets, and delivery history
- Connect Apps to the API — API keys and OAuth apps like Zapier
- Integrations — everything on the Integrations tab
- Order Statuses — the status values that appear in payloads