---
title: "ThreadParticipant"
description: "A participant in a thread. Exactly one identity field is populated per row
(enforced by a CHECK constraint). The populated field determines the
participant's kind:

  - `userId`           → Aeontel user
  - `agentId`          → agent
  - `swarmId`          → swarm
  - `externalIdentity` → external visitor on a deployed app

`displayName` is required for visitors (they have no other human-readable
identity) and optional as a cache for the rest."
section: "Reference"
group: "Types"
order: 234
---

## Definition

```ts
interface ThreadParticipant {
  id: string;
  threadId: string;
  userId: string | null;
  agentId: string | null;
  swarmId: string | null;
  externalIdentity: string | null;
  displayName: string | null;
  joinedAt: string;
  lastReadMessageId: string | null;
  lastReadAt: string | null;
}
```

## Fields

| Field               | Type             | Notes                                                                                                              |
| ------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------ |
| `id`                | `string`         | `readonly` `required`                                                                                              |
| `threadId`          | `string`         | `required` — Thread this participant belongs to.                                                                   |
| `userId`            | `string \| null` | `required` — Set when the participant is an Aeontel user.                                                          |
| `agentId`           | `string \| null` | `required` — Set when the participant is an agent.                                                                 |
| `swarmId`           | `string \| null` | `required` — Set when the participant is a swarm.                                                                  |
| `externalIdentity`  | `string \| null` | `required` — Opaque identity string supplied by a deployed app for non-Aeontel visitors.                           |
| `displayName`       | `string \| null` | `required` — Human-readable name; required for visitors, optional cache for others.                                |
| `joinedAt`          | `string`         | `required` — ISO-8601 timestamp of when this participant joined.                                                   |
| `lastReadMessageId` | `string \| null` | `required` — Most recent message this participant has read. Messages with a later `createdAt` are unread for them. |
| `lastReadAt`        | `string \| null` | `required` — ISO-8601 timestamp of when `lastReadMessageId` was set. Useful for 'read 5m ago' UI.                  |
