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

# Channels API

> Connect Shannon to external messaging platforms like Slack and LINE

## Overview

The Channels API lets you integrate Shannon with external messaging platforms. Create channels to connect Slack workspaces or LINE accounts, and Shannon will automatically process incoming messages through its agent system.

## Features

* **Slack integration** with event subscription and bot messaging
* **LINE integration** with webhook-based messaging
* **HMAC signature verification** for secure inbound webhooks
* **Agent routing** via `agent_name` config to direct messages to specific agents
* **Per-user isolation** with unique constraint on type + name per user
* **Credential security** — credentials are never exposed in API responses

## Create Channel

Create a new messaging channel.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST http://localhost:8080/api/v1/channels \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer <token>" \
    -d '{
      "type": "slack",
      "name": "My Slack Channel",
      "credentials": {
        "signing_secret": "your-slack-signing-secret",
        "bot_token": "xoxb-your-bot-token",
        "app_id": "A0123456789"
      },
      "config": {
        "agent_name": "research-agent"
      }
    }'
  ```

  ```python Python SDK theme={null}
  from shannon import ShannonClient

  client = ShannonClient()
  channel = client.create_channel(
      type="slack",
      name="My Slack Channel",
      credentials={
          "signing_secret": "your-slack-signing-secret",
          "bot_token": "xoxb-your-bot-token",
          "app_id": "A0123456789",
      },
      config={"agent_name": "research-agent"},
  )
  print(f"Channel created: {channel.id}")
  ```
</CodeGroup>

### Request Body

| Field         | Type   | Required | Description                                 |
| ------------- | ------ | -------- | ------------------------------------------- |
| `type`        | string | Yes      | Channel type: `"slack"` or `"line"`         |
| `name`        | string | Yes      | Channel display name                        |
| `credentials` | object | Yes      | Platform-specific credentials (see below)   |
| `config`      | object | No       | Optional configuration (e.g., `agent_name`) |

### Response

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "user_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "type": "slack",
  "name": "My Slack Channel",
  "config": {
    "agent_name": "research-agent"
  },
  "enabled": true,
  "created_at": "2026-03-10T10:00:00Z",
  "updated_at": "2026-03-10T10:00:00Z"
}
```

<Note>
  The `credentials` field is **never** returned in API responses for security. Store your credentials securely on your side.
</Note>

## List Channels

List all channels for the authenticated user.

<CodeGroup>
  ```bash curl theme={null}
  curl http://localhost:8080/api/v1/channels \
    -H "Authorization: Bearer <token>"
  ```

  ```python Python SDK theme={null}
  from shannon import ShannonClient

  client = ShannonClient()
  channels = client.list_channels()
  for ch in channels:
      print(f"{ch.name} ({ch.type}) — enabled: {ch.enabled}")
  ```
</CodeGroup>

### Response

```json theme={null}
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "user_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "type": "slack",
    "name": "My Slack Channel",
    "config": {
      "agent_name": "research-agent"
    },
    "enabled": true,
    "created_at": "2026-03-10T10:00:00Z",
    "updated_at": "2026-03-10T10:00:00Z"
  }
]
```

## Get Channel

Get details of a specific channel.

<CodeGroup>
  ```bash curl theme={null}
  curl http://localhost:8080/api/v1/channels/{id} \
    -H "Authorization: Bearer <token>"
  ```

  ```python Python SDK theme={null}
  from shannon import ShannonClient

  client = ShannonClient()
  channel = client.get_channel("550e8400-e29b-41d4-a716-446655440000")
  print(f"{channel.name} — type: {channel.type}")
  ```
</CodeGroup>

### Response

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "user_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "type": "slack",
  "name": "My Slack Channel",
  "config": {
    "agent_name": "research-agent"
  },
  "enabled": true,
  "created_at": "2026-03-10T10:00:00Z",
  "updated_at": "2026-03-10T10:00:00Z"
}
```

## Update Channel

Update an existing channel. All fields are optional — only provided fields will be updated.

<CodeGroup>
  ```bash curl theme={null}
  curl -X PUT http://localhost:8080/api/v1/channels/{id} \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer <token>" \
    -d '{
      "name": "Renamed Slack Channel",
      "config": {
        "agent_name": "financial-agent"
      },
      "enabled": false
    }'
  ```

  ```python Python SDK theme={null}
  from shannon import ShannonClient

  client = ShannonClient()
  channel = client.update_channel(
      "550e8400-e29b-41d4-a716-446655440000",
      name="Renamed Slack Channel",
      config={"agent_name": "financial-agent"},
      enabled=False,
  )
  print(f"Updated: {channel.name}, enabled: {channel.enabled}")
  ```
</CodeGroup>

### Request Body

| Field         | Type    | Required | Description                   |
| ------------- | ------- | -------- | ----------------------------- |
| `name`        | string  | No       | New channel name              |
| `credentials` | object  | No       | New platform credentials      |
| `config`      | object  | No       | New configuration             |
| `enabled`     | boolean | No       | Enable or disable the channel |

### Response

Returns the updated channel object (same schema as [Get Channel](#get-channel)).

## Delete Channel

Delete a channel permanently.

<CodeGroup>
  ```bash curl theme={null}
  curl -X DELETE http://localhost:8080/api/v1/channels/{id} \
    -H "Authorization: Bearer <token>"
  ```

  ```python Python SDK theme={null}
  from shannon import ShannonClient

  client = ShannonClient()
  client.delete_channel("550e8400-e29b-41d4-a716-446655440000")
  print("Channel deleted")
  ```
</CodeGroup>

### Response

```json Response theme={null}
{
  "message": "Channel deleted"
}
```

(HTTP 200 OK with JSON body)

## Inbound Webhook

Receive messages from external platforms. This endpoint is called by Slack or LINE when a user sends a message.

```bash theme={null}
POST /api/v1/channels/{channel_id}/webhook
```

<Warning>
  This endpoint requires **no authentication**. Instead, each platform uses its own HMAC signature verification to ensure requests are genuine.
</Warning>

### Response

```json theme={null}
{
  "status": "dispatched"
}
```

The webhook validates the inbound request, extracts the message, and dispatches it to Shannon's agent system asynchronously. The response is returned immediately.

## Credential Formats

### Slack Credentials

```json theme={null}
{
  "signing_secret": "your-slack-signing-secret",
  "bot_token": "xoxb-your-bot-token",
  "app_id": "A0123456789"
}
```

| Field            | Description                                          |
| ---------------- | ---------------------------------------------------- |
| `signing_secret` | Found in your Slack app's **Basic Information** page |
| `bot_token`      | Bot user OAuth token (starts with `xoxb-`)           |
| `app_id`         | Your Slack app ID                                    |

### LINE Credentials

```json theme={null}
{
  "channel_secret": "your-line-channel-secret",
  "channel_access_token": "your-line-channel-access-token"
}
```

| Field                  | Description                                                 |
| ---------------------- | ----------------------------------------------------------- |
| `channel_secret`       | Found in your LINE Developer Console channel settings       |
| `channel_access_token` | Long-lived channel access token from LINE Developer Console |

## Webhook Behavior

### Slack

* **Signature verification**: Validates `X-Slack-Request-Timestamp` and `X-Slack-Signature` headers using HMAC-SHA256 with the channel's `signing_secret`
* **Clock skew**: Requests older than 5 minutes are rejected
* **URL verification**: Automatically responds to Slack's `url_verification` challenge during app setup
* **Bot filtering**: Messages from bots are ignored to prevent loops
* **Supported events**: `message` and `app_mention`

### LINE

* **Signature verification**: Validates `X-Line-Signature` header using HMAC-SHA256 (base64-encoded) with the channel's `channel_secret`
* **Reply behavior**: Sends a "Thinking..." reply immediately using the reply token
* **Message handling**: Processes the first text message from the event payload

### Agent Routing

Set the `agent_name` field in the channel's `config` to route incoming messages to a specific agent:

```json theme={null}
{
  "config": {
    "agent_name": "research-agent"
  }
}
```

If `agent_name` is not set, messages are handled by Shannon's default agent routing.

## Channel Response Object

| Field        | Type              | Description                         |
| ------------ | ----------------- | ----------------------------------- |
| `id`         | string (UUID)     | Unique channel identifier           |
| `user_id`    | string (UUID)     | Owner user ID (optional)            |
| `type`       | string            | Channel type: `"slack"` or `"line"` |
| `name`       | string            | Channel display name                |
| `config`     | object            | Channel configuration               |
| `enabled`    | boolean           | Whether the channel is active       |
| `created_at` | string (ISO 8601) | Creation timestamp                  |
| `updated_at` | string (ISO 8601) | Last update timestamp               |

## Error Responses

| Status | Error                 | Description                                     |
| ------ | --------------------- | ----------------------------------------------- |
| 400    | Invalid request       | Missing required fields or invalid channel type |
| 401    | Unauthorized          | Missing or invalid authentication               |
| 403    | Forbidden             | Cannot access another user's channel            |
| 404    | Channel not found     | Invalid channel ID                              |
| 409    | Conflict              | Duplicate channel (same user + type + name)     |
| 500    | Internal server error | Server-side failure                             |

All errors follow the standard format:

```json theme={null}
{
  "error": "error message here"
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Submit Tasks" icon="paper-plane" href="/en/api/rest/submit-task">
    Submit tasks directly via API
  </Card>

  <Card title="Agents" icon="robot" href="/en/api/rest/agents">
    Configure agents for channel routing
  </Card>
</CardGroup>
