> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flowapt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Ticket Events

> Receive a POST from FlowIQ whenever a ticket is raised, changed, assigned, resolved, reopened or deleted.

A ticket is raised when the AI hands a conversation to your team (an escalation) or when your team opens one. Register a URL with [Create Webhook](https://docs.flowapt.com/flowiq-api-reference/endpoint/create-webhook.md) using `"platform": "tickets"`, and FlowIQ POSTs every matching ticket event to it, with the ticket as it is after the change.

```bash theme={null}
curl -X POST "https://api.flowiq.live/set-webhooks" \
  -H "Authorization: Bearer fiq_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-system.example.com/flowiq/tickets",
    "platform": "tickets",
    "type": "ticket.created",
    "secret": "a-long-random-string"
  }'
```

Register one webhook per event with `type` set to the event name, or one with `"type": "all"` for every event. The same authentication options as messaging webhooks apply (`auth_type`: bearer, basic, api\_key, oauth2\_client\_credentials), and with a `secret` every request carries an `X-Flowiq-Signature: sha256=<hex>` HMAC of the raw body ([how to verify](https://docs.flowapt.com/flowiq-api-reference/webhooks.md#verifying-signatures)).

## Events

| `event_type` | When |
| - | - |
| `ticket.created` | A ticket was raised: the AI handed the conversation to your team, or someone on the team opened one |
| `ticket.updated` | Anything on the ticket changed: status, team status, assignee, team, labels, follow-up, reply times, the AI's notes on the case. `changes` says what |
| `ticket.status_changed` | The status or the team status changed |
| `ticket.assigned` | The assignee or the team changed. `to: null` means it was unassigned |
| `ticket.resolved` | An open or in-progress ticket was resolved or closed |
| `ticket.reopened` | A resolved or closed ticket was opened again, for example because the customer wrote back |
| `ticket.deleted` | The ticket was deleted. `ticket` is its last state |

One change can fire several events. Resolving a ticket sends `ticket.updated`, `ticket.status_changed` and `ticket.resolved`, each with its own `event_id`. So a webhook on `all` receives all three. Most systems want either:

* **A copy of every ticket** (a database or data warehouse): `ticket.created`, `ticket.updated` and `ticket.deleted`. Store the `ticket` object by its `id`.
* **Escalation alerts**: `ticket.created`, and `ticket.resolved` / `ticket.reopened` if you track outcomes.

## Payload

```json theme={null}
{
  "event_type": "ticket.resolved",
  "event_id": "5f0c2a8e-9d41-4b7e-a3c2-1e8f6b7d9a10",
  "occurred_at": "2026-10-28T12:41:07.513Z",
  "organization_id": "a4234f32-…",
  "ticket_id": "3c1d9e7a-2b4f-4a8e-9f60-7d5e1c2b3a48",
  "changes": {
    "status": { "from": "in_progress", "to": "resolved" },
    "team_status": { "from": { "id": "8ee5ccae-…", "name": "Waiting on Production", "base_status": "in_progress" }, "to": null },
    "resolved_at": { "from": null, "to": "2026-10-28T12:41:07.402Z" },
    "status_history": { "added": [{ "from": "in_progress", "to": "resolved", "at": "2026-10-28T14:41:07.402+02:00", "by": "Sam", "member_id": "88b2fcbc-…" }] }
  },
  "ticket": {
    "id": "3c1d9e7a-2b4f-4a8e-9f60-7d5e1c2b3a48",
    "ticket_number": "FLW-261027-018",
    "status": "resolved",
    "team_status": null,
    "channel": "whatsapp",
    "summary": "Couch delivered with a cracked frame, customer wants a repair",
    "customer": "Jane Mokoena",
    "customer_number": "27821234567",
    "customer_email": "jane@example.com",
    "contact_id": "9a7e3b1c-…",
    "team": { "id": "d392994c-…", "name": "Aftersales" },
    "assignee": { "member_id": "88b2fcbc-…", "name": "Sam" },
    "labels": [{ "id": "2b1c…", "name": "Repair" }],
    "follow_up": null,
    "needs_reply": false,
    "raised_at": "2026-10-27T09:14:22.118+02:00",
    "updated_at": "2026-10-28T14:41:07.513+02:00",
    "resolved_at": "2026-10-28T12:41:07.402Z",
    "status_history": [ … ],
    "ai_updates": [{ "at": "2026-10-27T07:16:40.221Z", "by": "ai_agent", "summary": "Customer sent photos of the crack; asks for a repair, not a refund" }]
  }
}
```

| Field | Notes |
| - | - |
| `event_id` | Unique per event (also in the `X-Flowiq-Event-Id` header). A retry resends the same id: use it to ignore a repeat |
| `changes` | Each field that changed, as `{ "from": …, "to": … }`, using the field names of `ticket`. `status_history` and `ai_updates` only grow, so they give `{ "added": [the new entries] }`. `null` on `ticket.created` and `ticket.deleted` |
| `ticket` | The whole ticket after the change: the same object [`get_ticket`](https://docs.flowapt.com/flowiq-api-reference/reporting-api#syncing-your-tickets) returns, with its number, status and team status, channel, customer, team, assignee, labels, follow-up, reply times, status history and the AI's notes on the case |

Headers: `X-Flowiq-Event` (the event type), `X-Flowiq-Event-Id`, `X-Flowiq-Delivery-Id`, `X-Flowiq-Attempt`, `X-Flowiq-Timestamp`, and `X-Flowiq-Signature` when a secret is set.

> [!NOTE]
>
> Events are recorded in the same save as the ticket change, so none is lost while your endpoint is down. Answer with a `2xx` within 10 seconds and do the work afterwards. A failed delivery is retried for about 33 hours ([how](https://docs.flowapt.com/flowiq-api-reference/webhooks.md#delivery-behaviour)), and every attempt is in the [delivery log](https://docs.flowapt.com/flowiq-api-reference/endpoint/list-webhook-deliveries.md). Deliveries can arrive out of order after a retry: compare `ticket.updated_at` and keep the newest. To fill a gap or start a copy, page through [`list_tickets`](https://docs.flowapt.com/flowiq-api-reference/reporting-api#syncing-your-tickets) with `updated_since`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.