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

# Ticket events

> Platform events related to ticket lifecycle and operations

Ticket events are published whenever tickets are created, updated, or undergo state changes. These events are delivered through the platform events system.

## Developer quickstart

### Minimal handler (tickets only)

```javascript theme={null}
app.post("/webhook/platform-events", async (req, res) => {
  const event = req.body;
  if (!event?.eventId || !event?.eventType?.startsWith("ticket:")) {
    return res.status(200).send("OK"); // ignore non-ticket events
  }
  res.status(200).send("OK"); // ack early

  switch (event.eventType) {
    case "ticket:created":
      await onTicketCreated(event.payload);
      break;
    case "ticket:status:changed":
      await onTicketStatusChanged(event.payload);
      break;
    default:
      break;
  }
});
```

### Checklist

* Use `eventId` for idempotency; store processed IDs for 24–48h.
* Fetch full ticket via API if you detect truncated fields.
* Treat `ticket:updated` as a meta-event and listen for the derived specific events.
* Process asynchronously; do not block the HTTP response.

## Event types

### Core lifecycle events

#### `ticket:created`

Triggered when a new ticket is created.

**Payload structure:**

```typescript theme={null}
interface TicketCreatedPayload {
  ticket: {
    id: string;
    ticketId: string;
    title: string;
    description: string;
    customerContactFirstName: string;
    customerContactLastName: string;
    customerContactEmail: string;
    priorityId: string;
    statusId: string;
    statusName: string;
    priorityName: string;
    sentimentId: string;
    sentimentName: string;
    source: string;
    createdAt: Date;
    teamId: string;
    teamName: string;
    teamIdentifier: string;
    subTeamId?: string;
    subTeamName?: string;
    subTeamIdentifier?: string;
    isEscalated: boolean;
    customer: {
      id: string;
      email: string;
      name: string;
    };
    assignedTo: string | null;
    assignedAgent: {
      id: string;
      email: string;
      name: string;
    } | null;
    tags?: string[];
    isArchived: boolean;
    customFields?: Record<string, string>;
    metadata?: Record<string, string>;
    aiGeneratedTitle?: string;
    aiGeneratedSummary?: string;
    lastCustomerComment?: Date;
    lastVendorComment?: Date;
    proactiveChannels?: string[];
    isProactive?: boolean;
  };
  comment?: {
    id: string;
    content: string;
    contentHtml: string;
    contentJson: string;
    customerContactId: string;
    createdAt: Date;
  };
}
```

#### `ticket:updated`

Triggered when a ticket is updated. This is a general update event that may trigger additional specific events.

**Payload structure:**
Same as `ticket:created`, but includes:

```typescript theme={null}
{
  ticket: TicketPayload;
  previousTicket: TicketPayload; // Previous state of the ticket
}
```

#### `ticket:deleted`

Triggered when a ticket is deleted.

**Payload structure:**

```typescript theme={null}
{
  previousTicket: TicketPayload; // The deleted ticket data
}
```

#### `ticket:archived`

Triggered when a ticket is archived.

#### `ticket:unarchived`

Triggered when a ticket is unarchived.

### State change events

These events are automatically triggered when specific fields change during a `ticket:updated` event:

#### `ticket:status:changed`

Triggered when the ticket status changes.

#### `ticket:priority:changed`

Triggered when the ticket priority changes.

#### `ticket:assigned`

Triggered when the ticket is assigned to a different agent.

#### `ticket:type:changed`

Triggered when the ticket type changes.

#### `ticket:sentiment:changed`

Triggered when the ticket sentiment changes.

#### `ticket:escalated`

Triggered when a ticket is escalated.

### Custom field events

#### `ticket:custom_field_value:added`

Triggered when a custom field value is added to a ticket.

**Additional payload:**

```typescript theme={null}
{
  changedCustomFields: Array<{
    fieldUid: string;
    newValues: string[];
    changeType: "added";
  }>;
}
```

#### `ticket:custom_field_value:removed`

Triggered when a custom field value is removed from a ticket.

**Additional payload:**

```typescript theme={null}
{
  changedCustomFields: Array<{
    fieldUid: string;
    previousValues: string[];
    changeType: "removed";
  }>;
}
```

#### `ticket:custom_field_value:changed`

Triggered when a custom field value is changed on a ticket.

**Additional payload:**

```typescript theme={null}
{
  changedCustomFields: Array<{
    fieldUid: string;
    previousValues: string[];
    newValues: string[];
    addedValues?: string[];
    removedValues?: string[];
    changeType: "updated";
  }>;
}
```

### Tag events

#### `ticket:tag:updated`

Triggered when tags are added to or removed from a ticket.

### Migration events

#### `ticket:migrated`

Triggered when a ticket is migrated to a different team.

**Additional payload:**

```typescript theme={null}
{
  migration: {
    source: string;
    sourceId: string;
    [key: string]: unknown;
  };
}
```

### Comment events

#### `ticket:comment:added`

Triggered when a comment is added to a ticket.

#### `ticket:comment:updated`

Triggered when a comment on a ticket is updated.

#### `ticket:comment:deleted`

Triggered when a comment is deleted from a ticket.

#### `ticket:comment:reaction:added`

Triggered when a reaction is added to a ticket comment.

#### `ticket:comment:reaction:removed`

Triggered when a reaction is removed from a ticket comment.

### CSAT events

#### `ticket:csat:sent`

Triggered when a CSAT survey is sent for a ticket.

**Additional payload:**

```typescript theme={null}
{
  csat: {
    id: string;
    feedbackType: string;
    surveyConfig?: any;
    deliveryChannel?: string;
    ruleName: string;
    sentAt?: Date;
    requestorEmail: string;
  };
}
```

#### `ticket:csat:received`

Triggered when a CSAT survey response is received.

**Additional payload:**

```typescript theme={null}
{
  csat: {
    id: string;
    feedbackType: string;
    deliveryChannel?: string;
    ruleName: string;
    completedAt?: Date;
    requestorEmail: string;
    ratingValue?: number;
    hasComment?: boolean;
    commentText?: string;
  };
}
```

### SLA events

#### `ticket:sla:breached`

Triggered when an SLA breach is detected on a ticket.

#### `ticket:sla:breach_warning`

Triggered when an SLA breach warning is detected on a ticket.

## Event processing

### Automatic event generation

When a `ticket:updated` event is processed, the system automatically analyzes the changes and generates appropriate specific events:

1. **Status change detection**: Compares `ticket.status.uid` with `previousTicket.status.uid`
2. **Priority change detection**: Compares `ticket.priority.uid` with `previousTicket.priority.uid`
3. **Assignment change detection**: Compares `ticket.assignedAgent.uid` with `previousTicket.assignedAgent.uid`
4. **Custom field change detection**: Analyzes custom field values for additions, removals, and changes
5. **Tag change detection**: Compares tag sets between current and previous ticket states

### Message size management

Ticket events can contain large amounts of data. The system automatically:

* Monitors payload size (256KB limit)
* Truncates large content fields when necessary
* Replaces truncated content with "Payload too large. Use API instead"
* Logs truncation events for monitoring

## Integration examples

### Handling ticket creation

```javascript theme={null}
function handleTicketCreated(payload) {
  const { ticket } = payload;

  // Send welcome email to customer
  if (ticket.source === "EMAIL") {
    sendWelcomeEmail(ticket.customer.email, ticket.ticketId);
  }

  // Notify assigned agent
  if (ticket.assignedAgent) {
    notifyAgent(ticket.assignedAgent.id, ticket);
  }

  // Log in CRM
  updateCRM({
    customerId: ticket.customer.id,
    ticketId: ticket.id,
    priority: ticket.priorityName,
  });
}
```

### Handling status changes

```javascript theme={null}
function handleStatusChange(payload) {
  const { ticket, previousTicket } = payload;

  if (
    ticket.statusName === "Closed" &&
    previousTicket.statusName !== "Closed"
  ) {
    // Ticket was closed
    triggerCSATSurvey(ticket);
    updateMetrics("ticket_closed", ticket.teamId);
  }
}
```

### Custom field monitoring

```javascript theme={null}
function handleCustomFieldChange(payload) {
  const { changedCustomFields } = payload;

  changedCustomFields.forEach((change) => {
    if (change.fieldUid === "severity-field-uid") {
      if (change.newValues.includes("Critical")) {
        escalateToManagement(payload.ticket);
      }
    }
  });
}
```

## Best practices

1. **Event filtering**: Use platform message attributes to filter for specific event types
2. **Idempotency**: Use `eventId` to ensure idempotent processing
3. **Error handling**: Implement proper retry logic for failed event processing
4. **Large payloads**: For truncated payloads, use the API to fetch complete data
5. **Performance**: Process events asynchronously to avoid blocking ticket operations

## Event frequency

Ticket events are high-frequency events, especially in active organizations. Consider:

* Implementing rate limiting for downstream systems
* Using batch processing for non-critical integrations
* Filtering events at the platform subscription level to reduce unnecessary processing
