> ## 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.

# Comment events

> Platform events related to comments and reactions across different entities

Comment events are published when comments are created, updated, or deleted on various entities throughout the platform. Comments can be attached to tickets, account tasks, account activities, and account notes. These events are delivered through the platform events system.

## Developer quickstart

### Minimal handler (comments only)

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

  switch (event.eventType) {
    case "ticket:comment:created":
      await onTicketCommentCreated(event.payload);
      break;
    case "account-task:comment:updated":
      await onAccountTaskCommentUpdated(event.payload);
      break;
    default:
      break;
  }
});
```

### Checklist

* For public email-sourced comments, expect selective content fields (privacy).
* For large payloads, detect truncation markers and fetch full content via API.
* Handle mentions downstream; see `user:mentioned` events for notifications.

## Event types by entity

Comments can be associated with different entity types, and the event names reflect this:

### Ticket comments

#### `ticket:comment:created`

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.

### Account task comments

#### `account-task:comment:created`

Triggered when a comment is added to an account task.

#### `account-task:comment:updated`

Triggered when a comment on an account task is updated.

#### `account-task:comment:deleted`

Triggered when a comment is deleted from an account task.

### Account activity comments

#### `account-activity:comment:created`

Triggered when a comment is added to an account activity.

#### `account-activity:comment:updated`

Triggered when a comment on an account activity is updated.

#### `account-activity:comment:deleted`

Triggered when a comment is deleted from an account activity.

### Account note comments

#### `account-note:comment:created`

Triggered when a comment is added to an account note.

#### `account-note:comment:updated`

Triggered when a comment on an account note is updated.

#### `account-note:comment:deleted`

Triggered when a comment is deleted from an account note.

## Comment event structure

### Standard comment events (created/deleted)

```typescript theme={null}
interface CommentEventPayload {
  comment: {
    id: string;
    content?: string; // May be omitted for certain visibility rules
    contentHtml?: string;
    contentMarkdown?: string;
    contentJson?: string;
    commentType: string;
    parentCommentId?: string;
    teamId?: string; // For ticket comments
    accountId?: string; // For account-related comments
    metadata: Record<string, unknown>;
    customerContact?: {
      id: string;
      email: string;
      avatarUrl: string;
    };
    author: {
      id: string;
      name: string;
      email: string;
      avatarUrl: string;
    };
    attachments: Array<{
      id: string;
      name: string;
      url: string;
      size: number;
      contentType: string;
      createdAt: Date;
      updatedAt: Date;
      deletedAt?: Date;
    }>;
    commentVisibility: string;
    createdAt: Date;
    updatedAt: Date;
    deletedAt?: Date;
    shouldSendEmail?: boolean; // Only for created events
    createdWithTicket?: boolean; // Only for created events
  };
  // Entity-specific payload additions
  ticket?: {
    id: string;
    title: string;
    description?: string;
    requestorEmail?: string;
    submitterEmail?: string;
    source: string;
    isProactive?: boolean;
    proactiveChannels?: string[];
  };
  accountTask?: {
    id: string;
    title: string;
  };
  accountActivity?: {
    id: string;
  };
  accountNote?: {
    id: string;
  };
}
```

### Comment update events

For update events, the payload structure includes both previous and updated states:

```typescript theme={null}
interface CommentUpdateEventPayload {
  comment: {
    previous: CommentData; // Previous state of the comment
    updated: CommentData; // Updated state of the comment
  };
  // Same entity-specific additions as above
}
```

## Reaction events

Comments can have reactions (emoji responses) which generate their own events:

### `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.

**Reaction event payload:**

```typescript theme={null}
interface ReactionEventPayload {
  reaction: {
    name: string; // Emoji name (e.g., "thumbs_up", "heart")
    author: {
      id: string;
      name: string;
      avatarUrl: string;
      email: string;
    };
    metadata: Record<string, any>;
  };
  comment: {
    id: string;
  };
}
```

## Content filtering and privacy

### Email source content protection

For comments on tickets with email source and public visibility, certain content fields may be omitted from the platform payload for privacy reasons:

* `content`
* `contentMarkdown`
* `contentJson`

Only `contentHtml` is included in these cases.

### Large content truncation

Comments with large content (approaching the 256KB platform limit) will have their content fields truncated and replaced with "Payload too large. Use API instead".

## Event structure

All comment events follow the standard platform event structure:

```typescript theme={null}
interface CommentEventEnvelope {
  eventId: string;
  eventType: string; // e.g., "ticket:comment:created"
  timestamp: string;
  orgId: string;
  actor: {
    id: string;
    type: string;
    email: string;
  };
  payload:
    | CommentEventPayload
    | CommentUpdateEventPayload
    | ReactionEventPayload;
}
```

## Special metadata

### Mention metadata

When a comment contains user mentions, the metadata may include:

```typescript theme={null}
{
  mentions: {
    users: Array<{
      id: string;
      email: string;
      name: string;
    }>;
  }
  ignoreSelf: boolean; // Indicates if the author should be excluded from notifications
}
```

### Integration metadata

Comments created through integrations may include additional metadata:

```typescript theme={null}
{
  source: "slack" | "email" | "api" | "web";
  integrationId?: string;
  externalId?: string;
  syncStatus?: string;
}
```

## Integration examples

### Comment notification system

```javascript theme={null}
function handleCommentCreated(payload) {
  const { comment, ticket, accountTask } = payload;

  // Determine notification recipients
  const recipients = [];

  if (ticket) {
    // Notify ticket participants
    recipients.push(ticket.assignedAgent);
    recipients.push(ticket.customer);
  } else if (accountTask) {
    // Notify task assignee and watchers
    recipients.push(accountTask.assignedUser);
    recipients.push(...accountTask.watchers);
  }

  // Send notifications
  recipients.forEach((recipient) => {
    if (comment.shouldSendEmail) {
      sendEmailNotification(recipient, comment, { ticket, accountTask });
    }
    sendInAppNotification(recipient, comment);
  });
}
```

### Comment synchronization

```javascript theme={null}
function handleCommentUpdate(payload) {
  const { comment } = payload;
  const { previous, updated } = comment;

  // Sync to external systems
  if (previous.content !== updated.content) {
    // Content changed
    syncContentToExternalSystems(updated);

    // Log edit history
    logCommentEdit({
      commentId: updated.id,
      previousContent: previous.content,
      newContent: updated.content,
      editedBy: payload.actor.id,
      editedAt: updated.updatedAt,
    });
  }

  // Update search index
  updateSearchIndex(updated);
}
```

### Reaction aggregation

```javascript theme={null}
function handleReactionEvent(payload) {
  const { reaction, comment } = payload;

  // Update reaction counts
  updateReactionCounts(comment.id, reaction.name, payload.eventType);

  // Notify comment author (if not self-reaction)
  if (reaction.author.id !== comment.author.id) {
    notifyCommentAuthor(comment.author.id, {
      type: "reaction",
      reaction: reaction.name,
      reactorName: reaction.author.name,
      commentId: comment.id,
    });
  }

  // Track engagement metrics
  trackEngagement({
    type: "reaction",
    reactionType: reaction.name,
    commentId: comment.id,
    userId: reaction.author.id,
  });
}
```

### Mention processing

```javascript theme={null}
function handleCommentWithMentions(payload) {
  const { comment, metadata } = payload;

  if (metadata?.mentions?.users) {
    metadata.mentions.users.forEach((mentionedUser) => {
      // Skip self-mentions if ignoreSelf is true
      if (metadata.ignoreSelf && mentionedUser.id === comment.author.id) {
        return;
      }

      // Send mention notification
      sendMentionNotification(mentionedUser, {
        comment,
        mentionedBy: comment.author,
        context:
          payload.ticket || payload.accountTask || payload.accountActivity,
      });

      // Track mention metrics
      trackMention({
        mentionedUserId: mentionedUser.id,
        mentionedByUserId: comment.author.id,
        commentId: comment.id,
      });
    });
  }
}
```

## Comment threading

Comments support threading through the `parentCommentId` field:

```javascript theme={null}
function handleThreadedComment(payload) {
  const { comment } = payload;

  if (comment.parentCommentId) {
    // This is a reply to another comment
    const parentComment = getCommentById(comment.parentCommentId);

    // Notify parent comment author
    notifyCommentAuthor(parentComment.author.id, {
      type: "reply",
      replyId: comment.id,
      replyContent: comment.content,
      repliedBy: comment.author,
    });

    // Update thread metrics
    updateThreadMetrics(comment.parentCommentId);
  }
}
```

## Attachment handling

Comments can include file attachments:

```javascript theme={null}
function handleCommentAttachments(payload) {
  const { comment } = payload;

  comment.attachments?.forEach((attachment) => {
    // Process attachment
    processAttachment({
      id: attachment.id,
      name: attachment.name,
      size: attachment.size,
      contentType: attachment.contentType,
      url: attachment.url,
      commentId: comment.id,
    });

    // Virus scan for new attachments
    if (payload.eventType.includes("created")) {
      scheduleVirusScan(attachment.id);
    }

    // Update storage metrics
    updateStorageMetrics(attachment.size);
  });
}
```

## Best practices

1. **Content safety**: Always sanitize comment content before displaying
2. **Mention handling**: Respect user notification preferences for mentions
3. **Threading**: Maintain proper parent-child relationships for threaded comments
4. **Privacy**: Be aware of content filtering for email sources
5. **Performance**: Consider comment volume for high-traffic tickets/entities
6. **Attachments**: Implement proper security scanning for file attachments

## Event frequency

Comment events can be high-frequency, especially for:

* Active support tickets
* Collaborative account management tasks
* Popular discussion threads

Consider implementing:

* Rate limiting for notification systems
* Batching for non-critical integrations
* Proper indexing for search systems
* Efficient storage for comment history
