# Ticket events

> ticket.created, ticket.updated and ticket.solved.

Source: https://www.hey.support/docs/webhooks/events/ticket

---

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; `ticket.updated` adds a `change` field saying what happened.

This is the **same object** `/v1/tickets` returns, so a receiver integrating against these events and a script polling the API can never disagree about what a ticket is.

## The ticket object

```json
{
  "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": "ada@example.com",
    "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, and it is unique per **workspace** rather than per agent.

`category_name` is snapshotted, so a ticket stays readable after its category is deleted. `summary` and `sentiment` come from the triage pass and are null until it has run.

**Internal notes never appear in any of these events.** A note is your team talking to itself, and it does not leave the building.

## `ticket.created`

A problem the agent could not solve, now held with a number.

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

`opening_message` is the customer's own first words. `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:

| `change`           | What happened                                                        |
| ------------------ | -------------------------------------------------------------------- |
| `replied`          | Your team wrote to the customer. `message` carries the reply.        |
| `customer_replied` | The customer wrote back. `message` carries it.                       |
| `reopened`         | The customer replied to a solved or closed ticket, which reopens it. |
| `assigned`         | The assignee changed.                                                |
| `closed`           | It closed — by hand, or by the auto-close job.                       |
| `rated`            | The customer rated it. `ticket.rating` is 1–5.                       |

```json
{
  "event": "ticket.updated",
  "data": {
    "ticket": { "...": "as above" },
    "change": "customer_replied",
    "message": "Still nothing in the post — any update?"
  }
}
```

Adding an internal note is deliberately **not** one of these.

## `ticket.solved`

Its own event rather than an `updated` change, because it is the one a report counts.

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

A ticket can be solved more than once: a customer reply reopens it, and solving it again fires this again.
