WebhooksEvents

Ticket events

ticket.created, ticket.updated and ticket.solved

A ticket is a problem your agent could not solve on its own, held as a record with a number until your team can. All three events carry the same ticket object, which is the same object /v1/tickets returns; ticket.updated adds a change field saying what happened.

The ticket object

{
  "ticket": {
    "id": "9c1f7e42-3b6a-4d18-8f52-2a0e7c4b9d31",
    "chatbot_id": 17,
    "conversation_id": 8214,
    "customer_id": 42,
    "number": 1042,
    "status": "open",
    "priority": "high",
    "sentiment": "frustrated",
    "category_id": 4,
    "category_name": "Damaged or wrong item",
    "subject": null,
    "summary": "Rear wheel arrived buckled",
    "name": "Ada Lovelace",
    "email": "[email protected]",
    "phone": null,
    "answers": { "order_number": "A-1042" },
    "source": "card",
    "channel": "web",
    "language": "en",
    "assignee_user_id": 9,
    "rating": null,
    "first_reply_at": null,
    "last_customer_message_at": "2026-09-22T09:00:00.000Z",
    "last_agent_message_at": null,
    "solved_at": null,
    "closed_at": null,
    "reopened_count": 0,
    "created_at": "2026-09-22T09:00:00.000Z",
    "updated_at": "2026-09-22T09:00:00.000Z"
  }
}

number is what the customer quotes, unique per workspace rather than per agent. category_name is snapshotted, so a ticket stays readable after its category is deleted, and summary and sentiment are null until the triage pass has run. Internal notes never appear in any of these events.

ticket.created

A problem the agent could not solve, now held with a number. opening_message is the customer's own first words.

{
  "event": "ticket.created",
  "data": {
    "ticket": { "...": "as above" },
    "opening_message": "The rear wheel arrived buckled and the box was torn open."
  }
}

source says where it came from: card (the widget), agent (the agent opened it on a call or a channel), handoff (nobody took a request for a person), manual (your team), api, or channel.

ticket.updated

One event for every change to a live ticket. change says which; adding an internal note is deliberately not one of them.

changeWhat happened
repliedYour team wrote to the customer. message carries the reply.
customer_repliedThe customer wrote back. message carries it.
reopenedThe customer replied to a solved or closed ticket, which reopens it.
assignedThe assignee changed.
closedIt closed, by hand or by the auto-close job.
ratedThe customer rated it. ticket.rating is 1 to 5.
{
  "event": "ticket.updated",
  "data": {
    "ticket": { "...": "as above" },
    "change": "customer_replied",
    "message": "Still nothing in the post, any update?"
  }
}

ticket.solved

Its own event rather than an updated change, because it is the one a report counts. A ticket can be solved more than once: a customer reply reopens it, and solving it again fires this again.

{
  "event": "ticket.solved",
  "data": { "ticket": { "...": "as above", "status": "solved", "solved_at": "2026-09-23T11:04:00.000Z" } }
}

Next steps