# Channels API

Channels are the core communication containers in LVNG. They hold messages, members, and digital twin assignments. Every message belongs to a channel, and channels belong to workspaces. All endpoints require JWT authentication and are rate-limited to 300 requests per minute.

Base path: `/api/v2/channels`

---

## Channel CRUD

Create, read, update, and delete channels within a workspace.

### GET /api/v2/channels

List channels in a workspace. Includes aggregate counts for messages and members.

**Query Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `workspace_id` | string | Yes | UUID of the workspace to list channels from. |
| `type` | string | No | Filter by channel_type (e.g. text, voice, thread). |
| `is_archived` | boolean | No | Filter by archived status. |
| `limit` | integer | No | Maximum channels to return. |
| `offset` | integer | No | Number of channels to skip. |

**Example Request**

```bash
curl -X GET "https://api.lvng.ai/api/v2/channels?workspace_id=550e8400-e29b-41d4-a716-446655440000&limit=25" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

**Response -- 200**

```json
{
  "success": true,
  "channels": [
    {
      "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
      "workspace_id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "general",
      "display_name": "General",
      "description": "Main workspace channel",
      "channel_type": "text",
      "topic": null,
      "is_archived": false,
      "message_count": 1423,
      "member_count": 8,
      "created_at": "2026-01-15T10:00:00.000Z",
      "updated_at": "2026-03-19T12:00:00.000Z"
    }
  ],
  "pagination": {
    "limit": 25,
    "offset": 0,
    "total": 2,
    "hasMore": false
  }
}
```

---

### POST /api/v2/channels

Create a new channel. Creator is auto-added as member for private channels.

**Body Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `workspace_id` | string | Yes | UUID of the workspace. |
| `name` | string | Yes | URL-safe channel name (lowercase, hyphens). |
| `display_name` | string | No | Human-readable display name. |
| `description` | string | No | Channel description. |
| `channel_type` | string | Yes | Channel type: text, voice, thread, or dm. |
| `topic` | string | No | Current topic displayed in the channel header. |
| `parent_channel_id` | string | No | UUID of parent channel (for sub-channels). |

**Example Request**

```bash
curl -X POST https://api.lvng.ai/api/v2/channels \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "product-launches",
    "display_name": "Product Launches",
    "description": "Coordinate product launch activities",
    "channel_type": "text"
  }'
```

**Response -- 201**

```json
{
  "success": true,
  "channel": {
    "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "workspace_id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "product-launches",
    "display_name": "Product Launches",
    "description": "Coordinate product launch activities",
    "channel_type": "text",
    "topic": null,
    "is_archived": false,
    "parent_channel_id": null,
    "created_by": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
    "created_at": "2026-03-19T15:30:00.000Z",
    "updated_at": "2026-03-19T15:30:00.000Z"
  }
}
```

---

### GET /api/v2/channels/:id

Get a channel with member count and message count. Checks access permissions.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |

**Example Request**

```bash
curl -X GET https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8 \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

**Response -- 200**

```json
{
  "success": true,
  "channel": {
    "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "workspace_id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "general",
    "display_name": "General",
    "description": "Main workspace channel",
    "channel_type": "text",
    "topic": null,
    "is_archived": false,
    "member_count": 8,
    "message_count": 1423,
    "created_by": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
    "created_at": "2026-01-15T10:00:00.000Z",
    "updated_at": "2026-03-19T12:00:00.000Z"
  }
}
```

---

### PATCH /api/v2/channels/:id

Update channel properties. Requires owner, admin, or creator role.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |

**Body Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `display_name` | string | No | Updated display name. |
| `description` | string | No | Updated description. |
| `topic` | string | No | Updated channel topic. |
| `is_archived` | boolean | No | Set to true to archive the channel. |

**Example Request**

```bash
curl -X PATCH https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8 \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "display_name": "General Discussion",
    "topic": "Weekly standup notes and general chat"
  }'
```

**Response -- 200**

```json
{
  "success": true,
  "channel": {
    "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "workspace_id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "general",
    "display_name": "General Discussion",
    "description": "Main workspace channel",
    "channel_type": "text",
    "topic": "Weekly standup notes and general chat",
    "is_archived": false,
    "created_at": "2026-01-15T10:00:00.000Z",
    "updated_at": "2026-03-19T15:35:00.000Z"
  }
}
```

---

### DELETE /api/v2/channels/:id

Delete a channel. CASCADE deletes all related data (messages, members, pins). Broadcasts socket event.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel to delete. |

**Example Request**

```bash
curl -X DELETE https://api.lvng.ai/api/v2/channels/f47ac10b-58cc-4372-a567-0e02b2c3d479 \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

**Response -- 200**

```json
{
  "success": true,
  "message": "Channel deleted successfully"
}
```

---

## Channel Members

Manage channel membership. Members are validated against workspace membership before being added. Supports individual adds, bulk adds, role updates, and email-based invites.

### GET /api/v2/channels/:id/members

List all members of a channel. LEFT JOINs user profiles for display details.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |

**Example Request**

```bash
curl -X GET https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8/members \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

**Response -- 200**

```json
{
  "success": true,
  "members": [
    {
      "user_id": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
      "display_name": "Matty Squarzoni",
      "email": "matty@lvng.ai",
      "avatar_url": "https://storage.lvng.ai/avatars/a0eebc99.jpg",
      "role": "admin",
      "joined_at": "2026-01-15T10:00:00.000Z"
    }
  ],
  "count": 2
}
```

---

### POST /api/v2/channels/:id/members

Add a user to the channel. Validates workspace membership first.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |

**Body Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `user_id` | string | Yes | UUID of the user to add. |

**Example Request**

```bash
curl -X POST https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8/members \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "c2aad00b-1e2d-6gb0-dd8f-8dd1df502c33"
  }'
```

**Response -- 201**

```json
{
  "success": true,
  "member": {
    "user_id": "c2aad00b-1e2d-6gb0-dd8f-8dd1df502c33",
    "channel_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "role": "member",
    "joined_at": "2026-03-19T15:40:00.000Z"
  }
}
```

---

### PATCH /api/v2/channels/:id/members/:userId

Update a member's role within the channel.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |
| `userId` | string | Yes | UUID of the user to update. |

**Body Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `role` | string | Yes | New role: admin or member. |

**Example Request**

```bash
curl -X PATCH https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8/members/b1ffc99a-0d1c-5fa9-cc7e-7cc0ce491b22 \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "admin"
  }'
```

**Response -- 200**

```json
{
  "success": true,
  "member": {
    "user_id": "b1ffc99a-0d1c-5fa9-cc7e-7cc0ce491b22",
    "channel_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "role": "admin",
    "joined_at": "2026-01-16T09:30:00.000Z"
  }
}
```

---

### DELETE /api/v2/channels/:id/members/:userId

Remove a member from the channel.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |
| `userId` | string | Yes | UUID of the user to remove. |

**Example Request**

```bash
curl -X DELETE https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8/members/c2aad00b-1e2d-6gb0-dd8f-8dd1df502c33 \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

**Response -- 200**

```json
{
  "success": true,
  "message": "Member removed successfully"
}
```

---

### POST /api/v2/channels/:id/invite

Invite a user by email. Looks up the user and adds them if found.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |

**Body Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `email` | string | Yes | Email address to invite. |

**Example Request**

```bash
curl -X POST https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8/invite \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "alex@example.com"
  }'
```

**Response -- 200**

```json
{
  "success": true,
  "status": "added",
  "member": {
    "user_id": "d3bbe11c-2f3e-7hc1-ee9g-9ee2eg613d44",
    "channel_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "role": "member",
    "joined_at": "2026-03-19T15:45:00.000Z"
  }
}
```

---

### POST /api/v2/channels/:id/members/bulk

Add up to 50 members in a single request. Uses UPSERT to avoid duplicates.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |

**Body Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `user_ids` | string[] | Yes | Array of user UUIDs to add. Maximum 50. |

**Example Request**

```bash
curl -X POST https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8/members/bulk \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "user_ids": [
      "d3bbe11c-2f3e-7hc1-ee9g-9ee2eg613d44",
      "e4ccf22d-3g4f-8id2-ff0h-0ff3fh724e55",
      "f5ddg33e-4h5g-9je3-gg1i-1gg4gi835f66"
    ]
  }'
```

**Response -- 201**

```json
{
  "success": true,
  "members": [
    { "user_id": "d3bbe11c-2f3e-7hc1-ee9g-9ee2eg613d44", "role": "member", "joined_at": "2026-03-19T15:50:00.000Z" },
    { "user_id": "e4ccf22d-3g4f-8id2-ff0h-0ff3fh724e55", "role": "member", "joined_at": "2026-03-19T15:50:00.000Z" },
    { "user_id": "f5ddg33e-4h5g-9je3-gg1i-1gg4gi835f66", "role": "member", "joined_at": "2026-03-19T15:50:00.000Z" }
  ],
  "added": 3
}
```

---

## Digital Twins

Assign digital twins to channels. Twins process incoming messages and can respond based on their configuration and knowledge base.

### GET /api/v2/channels/:id/twins

List all digital twins assigned to a channel.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |

**Example Request**

```bash
curl -X GET https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8/twins \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

**Response -- 200**

```json
{
  "success": true,
  "twins": [
    {
      "id": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed",
      "name": "Research Assistant",
      "participation_mode": "active",
      "assigned_at": "2026-02-10T14:00:00.000Z"
    }
  ]
}
```

---

### POST /api/v2/channels/:id/twins

Assign a digital twin to the channel.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |

**Body Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `ai_twin_id` | string | Yes | UUID of the digital twin to assign. |
| `participation_mode` | string | No | How the twin participates: active, passive, or on-demand. |

**Example Request**

```bash
curl -X POST https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8/twins \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "ai_twin_id": "2c0e7dce-ccge-5c3e-0c6e-bc9egcce5cfe",
    "participation_mode": "active"
  }'
```

**Response -- 201**

```json
{
  "success": true,
  "twin": {
    "ai_twin_id": "2c0e7dce-ccge-5c3e-0c6e-bc9egcce5cfe",
    "channel_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "participation_mode": "active",
    "assigned_at": "2026-03-19T16:00:00.000Z"
  }
}
```

---

### DELETE /api/v2/channels/:id/twins/:twinId

Remove a digital twin from the channel.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |
| `twinId` | string | Yes | UUID of the twin to remove. |

**Example Request**

```bash
curl -X DELETE https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8/twins/2c0e7dce-ccge-5c3e-0c6e-bc9egcce5cfe \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

**Response -- 200**

```json
{
  "success": true
}
```

---

## Pinned Messages

Pin and unpin messages within a channel. Pinned state is stored in the message's `metadata` column as `pinned: true`.

### POST /api/v2/channels/:id/messages/:messageId/pin

Pin a message. Sets metadata.pinned=true on the message.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |
| `messageId` | string | Yes | UUID of the message to pin. |

**Example Request**

```bash
curl -X POST https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8/messages/7c9e6679-7425-40de-944b-e07fc1f90ae7/pin \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

**Response -- 200**

```json
{
  "success": true,
  "message": {
    "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "channel_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "content": "Q2 roadmap finalized. All features listed below are confirmed.",
    "metadata": {
      "pinned": true,
      "pinned_by": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
      "pinned_at": "2026-03-19T16:10:00.000Z"
    },
    "updated_at": "2026-03-19T16:10:00.000Z"
  }
}
```

---

### DELETE /api/v2/channels/:id/messages/:messageId/pin

Unpin a message. Strips pinned fields from metadata.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |
| `messageId` | string | Yes | UUID of the message to unpin. |

**Example Request**

```bash
curl -X DELETE https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8/messages/7c9e6679-7425-40de-944b-e07fc1f90ae7/pin \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

**Response -- 200**

```json
{
  "success": true,
  "message": {
    "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "channel_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "content": "Q2 roadmap finalized. All features listed below are confirmed.",
    "metadata": {},
    "updated_at": "2026-03-19T16:12:00.000Z"
  }
}
```

---

### GET /api/v2/channels/:id/pins

List all pinned messages in a channel. Filters by metadata->>pinned='true'.

**Path Parameters**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `id` | string | Yes | UUID of the channel. |

**Example Request**

```bash
curl -X GET https://api.lvng.ai/api/v2/channels/6ba7b810-9dad-11d1-80b4-00c04fd430c8/pins \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
```

**Response -- 200**

```json
{
  "success": true,
  "pins": [
    {
      "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "channel_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
      "content": "Q2 roadmap finalized. All features listed below are confirmed.",
      "user_id": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
      "metadata": {
        "pinned": true,
        "pinned_by": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
        "pinned_at": "2026-03-19T16:10:00.000Z"
      },
      "created_at": "2026-03-19T14:30:00.000Z"
    }
  ],
  "count": 1
}
```
