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

# Messaging Channel Integration Guide

> For users who integrate external IM platforms through the Forward Channel API, this guide covers channel authorization, fixed/pairing execution context modes, and how to create the app/bot, configure permissions, and obtain credentials for each channel.

<Warning>
  **We currently recommend using QR-code binding to authorize channels — do not configure credentials directly unless necessary.**

  DingTalk, Feishu, WeCom, and personal WeChat all support QR-code binding: you can omit `channel_config.credentials` when creating a Channel, then complete the binding by scanning a QR code through a QR Session. This avoids storing sensitive credentials like App Secret on your side, and is both more secure and easier to maintain.

  Only consider the "direct credential" flow below for each channel when QR-code binding cannot meet your needs (for example, unattended server-side automation).
</Warning>

## Distinguish channel authorization from Channel Pairing

Forward Channel has two independent configuration dimensions:

| Dimension             | Problem it solves                                                      | Options                                             |
| --------------------- | ---------------------------------------------------------------------- | --------------------------------------------------- |
| Channel authorization | How Forward obtains IM bot connection and send/receive permissions     | QR Session scan (recommended) or direct credentials |
| Identity resolution   | Which Identity and Template should be used for a given inbound message | `fixed` or `pairing`                                |

The "QR-code binding" in a QR Session is channel credential authorization — it is not the same as Channel Pairing. A `pairing` Channel still needs to complete channel authorization first so `binding_status=bound`; afterwards, when a real IM conversation is triggered for the first time, Forward generates a Pairing Code to bind the execution context for that message scope.

## QR-code binding flow (recommended)

QR-code binding works for all channels — `dingtalk`, `feishu`, `wecom`, `wechat`. The steps are:

1. **Create the Channel**: call [Create Channel](/cloud-agents/api/forward/channels/create) with `name`, `channel_type`, and the desired identity resolution mode, **omitting `channel_config.credentials`**. For `fixed` mode, also pass `identity_id` and `template_id`; for `pairing` mode, pass `identity_resolution.mode=pairing` without `identity_id` or `template_id`.
2. **Create a QR Session**: call [Create Channel QR Session](/cloud-agents/api/forward/channels/create-qr-session) to obtain `qr_code_image_base64` (the QR code image) or `qr_code_content` (the authorization URL). `poll_interval_seconds` is an optional compatibility field and should not be relied upon as a stable return value.
3. **Show the QR code and authorize**: display the QR code to the user, then use the corresponding channel client to scan and confirm authorization.
4. **Poll the authorization status**: call [Get Channel QR Session](/cloud-agents/api/forward/channels/get-qr-session) to poll `status`. Use `poll_interval_seconds` if present; otherwise default to a 3-second interval. Poll until `confirmed` (other states: `waiting`, `scanned`, `expired`, `denied`, `error`).
5. **Complete channel authorization**: after `status=confirmed`, refresh the Channel detail; `binding_status` will become `bound`. A `fixed` Channel can now process inbound messages with its fixed execution context; a `pairing` Channel will return a Pairing Code for unpaired messages — complete Channel Pairing (below) before messages enter the Agent.

<Note>
  QR codes have a short validity. If a session becomes `expired` or `denied`, create a new QR Session and scan again.
</Note>

## Identity resolution modes

### fixed mode

`fixed` is the default. You must specify `identity_id` and `template_id` when creating the Channel; all inbound messages use this fixed execution context:

```json theme={null}
{
  "identity_id": "idn_019eabc123",
  "identity_resolution": {
    "mode": "fixed"
  },
  "template_id": "tmpl_support",
  "channel_type": "feishu",
  "name": "Support Feishu channel"
}
```

### pairing mode

In `pairing` mode, the Channel only represents an IM transport connection — no Identity or Template is specified at creation:

```json theme={null}
{
  "identity_resolution": {
    "mode": "pairing"
  },
  "channel_type": "feishu",
  "name": "Support Feishu channel"
}
```

After channel authorization is complete, the pairing flow is:

1. A user sends a message from a real IM private chat or group chat to the bot.
2. Forward creates or reuses a 6-digit Pairing Code for the unpaired direct/room scope, replies only with a pairing prompt, and does not create a Session.
3. The admin calls [Pair a channel](/cloud-agents/api/forward/channels/pair-channel) with `code + identity_id + template_id`.
4. Subsequent messages resolve Identity and Template via the Pairing, then create or reuse a Session.
5. To revoke the binding, use the `pairing_id` from the Pair response to call [Unpair a channel](/cloud-agents/api/forward/channels/unpair-channel).

Direct scope uses the remote user as the pairing boundary; room scope uses the stable group/channel ID as the pairing boundary. Different members and threads within the same room share a Pairing, but Sessions and replies are still isolated per conversation/thread. Original messages that triggered pairing are not replayed after pairing succeeds — users need to send their request again.

<Warning>
  `identity_resolution.mode` cannot be changed after creation. To switch between `fixed` and `pairing`, you must delete and recreate the Channel.
</Warning>

## Direct credential integration (as needed)

If you must use direct credentials, create an app/bot on the corresponding open platform, configure the required permissions, obtain the credentials, and then pass them to [Create Channel](/cloud-agents/api/forward/channels/create) through `channel_config.credentials`. Mapping of `channel_type` and credential fields per channel:

| Channel         | `channel_type` | `channel_config.credentials` fields | Supports QR binding |
| --------------- | -------------- | ----------------------------------- | ------------------- |
| DingTalk        | `dingtalk`     | `client_id`, `client_secret`        | Yes (recommended)   |
| Feishu          | `feishu`       | `app_id`, `app_secret`              | Yes (recommended)   |
| WeCom           | `wecom`        | `bot_id`, `secret`                  | Yes (recommended)   |
| Personal WeChat | `wechat`       | No credentials required             | QR binding only     |

<Note>
  Credentials are only written when creating/updating a Channel; they are never returned in plaintext.
</Note>

## DingTalk

### Create a DingTalk app

1. Go to the [DingTalk Open Platform](https://open-dev.dingtalk.com/). Choose an organization that has developer permissions, or acquire developer permissions on a given organization. If no suitable organization exists, use the DingTalk mobile app to quickly create one by scanning a QR code.
2. In the top navigation, click **App Development**, then click **Create App** on the DingTalk App page.

### Create a DingTalk bot

1. Once the app is created, select **Add App Capability** in the left navigation, then click **Add** on the bot card.
2. On the bot configuration page, enable bot configuration.
3. For **Message Reception Mode**, choose **Stream mode**, then click **Publish** to finish configuring the bot.

### Configure permissions

In the app's **Permission Management**, enable the following permissions:

| Permission             | Description                      |
| ---------------------- | -------------------------------- |
| `Card.Streaming.Write` | Streaming write to card messages |
| `Card.Instance.Write`  | Create / update card instances   |
| `qyapi_robot_sendmsg`  | Bot sends messages               |

### Publish the app

1. Select **Version Management and Release** in the left navigation, then click **Create New Version**.
2. Fill in the app version number and description, choose the app's availability scope based on your business needs, and click **Save** to publish.

<Note>
  If the availability scope is set to all employees, the app will be visible to every employee of the current enterprise after publishing.
</Note>

### Get the credentials

On the **Credentials & Basic Info** page in the left navigation, record the **Client ID** and **Client Secret** — they correspond to the API's `client_id` and `client_secret`.

## Feishu

### Create a Feishu app

1. Visit the [Feishu Open Platform](https://open.feishu.cn/) and click **Developer Console** in the top-right corner.
2. Click **Create Custom App for Enterprise**, fill in the required info, and click **Create**.

### Add and configure the bot

1. Select **Add App Capability** in the left navigation, and click **Add** on the bot card.
2. Click the edit icon next to "How to get started" on the bot configuration card.
3. Under **Message Card Callback Request Method**, click **Configure**, choose **Receive callbacks via long connection**, and save.
4. Click **Event Configuration**, choose the same **Receive callbacks via long connection** subscription mode, and save.
5. On the Event Configuration page, add the following four events and save:
   * Bot joined chat
   * Bot removed from chat
   * Message read
   * Receive message

### Configure permissions

In **Permission Management > Enable Permissions**, click **Batch Import / Export Permissions**, paste the JSON below to import the required permissions in one click, confirm, and click **Apply for Approval**:

```json theme={null}
{
  "scopes": {
    "tenant": [
      "contact:contact.base:readonly",
      "docx:document:readonly",
      "im:chat:read",
      "im:chat:update",
      "im:message.group_at_msg:readonly",
      "im:message.p2p_msg:readonly",
      "im:message.pins:read",
      "im:message.pins:write_only",
      "im:message.reactions:read",
      "im:message.reactions:write_only",
      "im:message:readonly",
      "im:message:recall",
      "im:message:send_as_bot",
      "im:message:send_multi_users",
      "im:message:send_sys_msg",
      "im:message:update",
      "im:resource",
      "application:application:self_manage",
      "cardkit:card:write",
      "cardkit:card:read"
    ],
    "user": [
      "contact:user.employee_id:readonly",
      "offline_access",
      "base:app:copy",
      "base:field:create",
      "base:field:delete",
      "base:field:read",
      "base:field:update",
      "base:record:create",
      "base:record:delete",
      "base:record:retrieve",
      "base:record:update",
      "base:table:create",
      "base:table:delete",
      "base:table:read",
      "base:table:update",
      "base:view:read",
      "base:view:write_only",
      "base:app:create",
      "base:app:update",
      "base:app:read",
      "board:whiteboard:node:create",
      "board:whiteboard:node:read",
      "calendar:calendar:read",
      "calendar:calendar.event:create",
      "calendar:calendar.event:delete",
      "calendar:calendar.event:read",
      "calendar:calendar.event:reply",
      "calendar:calendar.event:update",
      "calendar:calendar.free_busy:read",
      "contact:contact.base:readonly",
      "contact:user.base:readonly",
      "contact:user:search",
      "docs:document.comment:create",
      "docs:document.comment:read",
      "docs:document.comment:update",
      "docs:document.media:download",
      "docs:document:copy",
      "docx:document:create",
      "docx:document:readonly",
      "docx:document:write_only",
      "drive:drive.metadata:readonly",
      "drive:file:download",
      "drive:file:upload",
      "im:chat.members:read",
      "im:chat:read",
      "im:message",
      "im:message.group_msg:get_as_user",
      "im:message.p2p_msg:get_as_user",
      "im:message:readonly",
      "search:docs:read",
      "search:message",
      "space:document:delete",
      "space:document:move",
      "space:document:retrieve",
      "task:comment:read",
      "task:comment:write",
      "task:task:read",
      "task:task:write",
      "task:task:writeonly",
      "task:tasklist:read",
      "task:tasklist:write",
      "wiki:node:copy",
      "wiki:node:create",
      "wiki:node:move",
      "wiki:node:read",
      "wiki:node:retrieve",
      "wiki:space:read",
      "wiki:space:retrieve",
      "wiki:space:write_only"
    ]
  }
}
```

### Publish the app

1. Select **Version Management and Release** in the left navigation.
2. Click **Create Version**, fill in the required info, and click **Save**.

### Get the credentials

On the app's **Credentials & Basic Info** page, copy the **App ID** (format like `cli_xxx`) and **App Secret** — they correspond to the API's `app_id` and `app_secret`.

## WeCom

### Create a smart bot

1. Visit the [WeCom Admin Console](https://work.weixin.qq.com/). In the left navigation, click **Security & Management > Management Tools**, click **Create Bot**, and then click **Manually Create**.
2. Configure the bot's visibility scope.
3. Scroll to the bottom and click **API Mode Creation**, and choose **Use long connection** as the connection method.

### Get the credentials

In the **Secret** area of the configuration method, click **Get** and record the **Bot ID** and **Secret** — they correspond to the API's `bot_id` and `secret`.

## Personal WeChat

Personal WeChat only supports **QR-code binding** — no need to create an app on any open platform, and no direct credentials are required. When creating a Channel, pass `wechat` as `channel_type` and complete the authorization following the [QR-code binding flow (recommended)](#qr-code-binding-flow-recommended) above.

## Related

<CardGroup cols={2}>
  <Card title="Create Channel" icon="plus" href="/cloud-agents/api/forward/channels/create" />

  <Card title="Create Channel QR Session" icon="qrcode" href="/cloud-agents/api/forward/channels/create-qr-session" />

  <Card title="Pair a channel" icon="link" href="/cloud-agents/api/forward/channels/pair-channel" />

  <Card title="Unpair a channel" icon="link-slash" href="/cloud-agents/api/forward/channels/unpair-channel" />

  <Card title="List Channels" icon="list" href="/cloud-agents/api/forward/channels/list" />
</CardGroup>
