Advanced

Channel API

Connect your own messaging product to chat.dev with inbound messages and outbound webhooks.

The Channel API lets any messaging service — Slack, Discord, Telegram, or your own — act as a frontend for chat.dev. Users on your platform can create agents, send tasks, attach files, and receive responses through your interface.

Overview#

A channel is a connection between your messaging platform and chat.dev. When you create a channel, you get:

  • An API key for authenticating inbound messages
  • A webhook secret for verifying outbound message signatures
  • A callback URL where chat.dev delivers agent responses

There are two directions of traffic:

  • Inbound: your app calls POST /api/channels/:channelId/inbound when one of your users sends a message, clicks a command button, or uploads an attachment.
  • Outbound: chat.dev calls your callbackUrl when it needs to send a message back later, such as agent progress, task output, or asynchronous status updates.

The callbackUrl is your HTTPS endpoint for outbound delivery. It should accept a JSON POST, verify the X-Webhook-Signature, then render or deliver the message to the user or group identified by externalUserId and groupExternalId.

Authentication#

Management endpoints#

Channel CRUD operations require a session cookie (same auth as the web dashboard).

Inbound messages#

Pass the API key in the Authorization: Bearer <key> header.

The API key authenticates your integration to chat.dev. It is not a user token and should never be shown to end users.

Outbound webhooks#

chat.dev signs every outbound payload with HMAC-SHA256 using your webhook secret. Verify the X-Webhook-Signature header:

const crypto = require("crypto");

function verifySignature(body, signature, secret) {
  const expected = crypto.createHmac("sha256", secret).update(body).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

Endpoints#

Endpoint index#

MethodEndpointAuthWhat it does
GET/api/channelsSession cookieList channels owned by the logged-in chat.dev user.
POST/api/channelsSession cookieCreate a channel owned by the logged-in chat.dev user.
DELETE/api/channels/:idSession cookieDelete one of the logged-in user's channels.
POST/api/channels/:id/rotate-keySession cookieRotate a channel API key and return the new key once.
POST/api/channels/registerRegistration key in JSON bodyCreate a text-only channel without a browser session.
POST/api/channels/:channelId/inboundAuthorization: Bearer <apiKey>Send a user message, command text, group message, or attachment into chat.dev.
POST/api/channels/:channelId/commands/getlinkAuthorization: Bearer <apiKey>Get a one-click authenticated link to the loaded agent's live terminal page.
POST/api/channels/:channelId/commands/getwalletAuthorization: Bearer <apiKey>Get the wallet public key for a named accessible agent.
POST/api/channels/:channelId/commands/helpAuthorization: Bearer <apiKey>Run /help.
POST/api/channels/:channelId/commands/statusAuthorization: Bearer <apiKey>Run /status.
POST/api/channels/:channelId/commands/yolo-modeAuthorization: Bearer <apiKey>Run /yolo-mode.
POST/api/channels/:channelId/commands/yolo-mode-offAuthorization: Bearer <apiKey>Run /yolo-mode-off.
POST/api/channels/:channelId/commands/muteAuthorization: Bearer <apiKey>Run /mute.
POST/api/channels/:channelId/commands/listAuthorization: Bearer <apiKey>Run /list.
POST/api/channels/:channelId/commands/balanceAuthorization: Bearer <apiKey>Run /balance.
POST/api/channels/:channelId/commands/fundAuthorization: Bearer <apiKey>Run /fund.
POST/api/channels/:channelId/commands/loginAuthorization: Bearer <apiKey>Run /login.
POST/api/channels/:channelId/commands/logoutAuthorization: Bearer <apiKey>Run /logout.
POST/api/channels/:channelId/commands/deloadAuthorization: Bearer <apiKey>Run /deload.
POST/api/channels/:channelId/commands/reposAuthorization: Bearer <apiKey>Run /repos.
POST/api/channels/:channelId/commands/createAuthorization: Bearer <apiKey>Run /create NAME.
POST/api/channels/:channelId/commands/spawnAuthorization: Bearer <apiKey>Run /spawn REPO.
POST/api/channels/:channelId/commands/loadAuthorization: Bearer <apiKey>Run /load NAME.
POST/api/channels/:channelId/commands/shareAuthorization: Bearer <apiKey>Run /share NAME.
POST/api/channels/:channelId/commands/share-agentAuthorization: Bearer <apiKey>Run /share-agent NAME.
POST/api/channels/:channelId/commands/create-sharedAuthorization: Bearer <apiKey>Run /create-shared NAME.
POST/api/channels/:channelId/commands/unshare-agentAuthorization: Bearer <apiKey>Run /unshare-agent NAME.
POST/api/channels/:channelId/commands/startAuthorization: Bearer <apiKey>Run /start or /start NAME.
POST/api/channels/:channelId/commands/start-agentAuthorization: Bearer <apiKey>Run /start_agent or /start_agent NAME.
POST/api/channels/:channelId/commands/stopAuthorization: Bearer <apiKey>Run /stop or /stop NAME.
POST/api/channels/:channelId/commands/stop-agentAuthorization: Bearer <apiKey>Run /stop_agent or /stop_agent NAME.
POST/api/channels/:channelId/commands/restartAuthorization: Bearer <apiKey>Run /restart or /restart NAME.
POST/api/channels/:channelId/commands/deleteAuthorization: Bearer <apiKey>Run /delete NAME.
POST/api/channels/:channelId/commands/fund-agentAuthorization: Bearer <apiKey>Run /fund_agent AGENT AMOUNT.
POST/api/channels/:channelId/commands/fund_agentAuthorization: Bearer <apiKey>Alias for /api/channels/:channelId/commands/fund-agent.
POST/api/channels/:channelId/commands/forkAuthorization: Bearer <apiKey>Run /fork NAME REPO.
POST/api/channels/:channelId/commands/yoloAuthorization: Bearer <apiKey>Run /yolo META-COMMAND.
POST/api/channels/:channelId/commands/promptAuthorization: Bearer <apiKey>Run /prompt MESSAGE.
POST/api/channels/:channelId/actions/get-linkAuthorization: Bearer <apiKey>Compatibility alias for POST /api/channels/:channelId/commands/getlink.
POST/api/channels/:channelId/actions/get-walletAuthorization: Bearer <apiKey>Compatibility alias for POST /api/channels/:channelId/commands/getwallet.

chat.dev also sends outbound webhook requests to your channel's callbackUrl. That is not a chat.dev API endpoint; it is your HTTPS endpoint that receives POST requests from chat.dev.

Create a channel#

Use this endpoint from an authenticated chat.dev web session. It creates a channel owned by the logged-in chat.dev user.

POST /api/channels
Content-Type: application/json
Cookie: <session>

{
  "name": "My Slack Bot",
  "platform": "slack",
  "callbackUrl": "https://your-server.com/chat-dev-webhook"
}

Fields:

FieldRequiredDescription
nameYesHuman-readable name for this integration, shown in the owner's channel list.
platformYesShort platform label such as slack, discord, telegram, or custom.
callbackUrlYesYour HTTPS webhook endpoint. chat.dev POSTs outbound messages to this URL.

Response (201):

{
  "id": "ch_abc123",
  "name": "My Slack Bot",
  "platform": "slack",
  "callbackUrl": "https://your-server.com/chat-dev-webhook",
  "apiKey": "chk_...",
  "webhookSecret": "whsec_..."
}

Save the apiKey and webhookSecret immediately — the API key is only shown once.

List channels#

GET /api/channels
Cookie: <session>

Delete a channel#

DELETE /api/channels/:id
Cookie: <session>

Rotate API key#

POST /api/channels/:id/rotate-key
Cookie: <session>

Returns a new apiKey.

Send an inbound message#

The main endpoint your integration calls when a user sends a message.

POST /api/channels/:channelId/inbound
Authorization: Bearer <apiKey>
Content-Type: application/json

{
  "externalUserId": "U12345",
  "displayName": "Alice",
  "message": "/create my-agent",
  "messageId": "msg_unique_id",
  "isGroup": false,
  "groupExternalId": "G67890",
  "groupName": "Engineering",
  "participants": ["U12345", "U67890"],
  "attachments": [
    {
      "url": "https://your-cdn.example.com/uploads/screenshot.png",
      "contentType": "image/png",
      "filename": "screenshot.png"
    }
  ]
}
FieldRequiredDescription
externalUserIdYesUnique user ID on your platform
messageYes unless attachments are presentMessage text, command text, or button payload. Send /getlink to request an authenticated terminal link for the loaded agent, or call the command endpoint below.
displayNameNoUser's display name
messageIdNoUnique message ID for deduplication
isGroupNoWhether this is a group conversation
groupExternalIdNoExternal group/channel ID
groupNameNoGroup display name
participantsNoList of participant IDs for group sync
attachmentsNoFiles or media to save into the loaded agent workspace. Each attachment accepts url, fileUrl, mediaUrl, or attachmentUrl, plus optional contentType/mimeType and filename/name.

Identity rules:

  • externalUserId is scoped to this channel. Use the stable user ID from your platform, not a display name.
  • For DMs, omit isGroup or set it to false.
  • For group conversations, set isGroup: true and include a stable groupExternalId. Group members can write @chatdev message to use their own chat.dev account tools in the shared group, or @agentname message to talk to one of their own agents or an agent shared into that group. Follow-up messages from the same sender stick to the last @chatdev or @agentname target until they mention a different target.
  • participants is optional. If supplied, chat.dev can sync known group members, but channel users are only auto-created when they send their first message.

Response:

{
  "ok": true,
  "replies": [
    "Agent 'my-agent' created and starting..."
  ]
}

Synchronous replies appear in the replies array. Async agent output (task results, status updates) is delivered to your callback URL via webhook.

Your integration should display every normal string in replies to the user. A reply prefixed with __structured: contains machine-readable JSON for your backend and usually should not be shown raw in the user interface.

If chat.dev returns a continue-setup link, show it to the user. Channel users can start without browser setup, but once they hit the free agent or prompt/API limits they need to finish setup before continuing.

Channel command endpoints#

All command endpoints use the same Authorization: Bearer <apiKey> header as inbound messages. They expose the slash commands as structured API calls so clients do not have to send command text through /inbound.

Common request body fields for every command endpoint:

FieldTypeRequiredDescription
externalUserIdstringYesStable user ID from your platform. This scopes the chat.dev user identity inside the channel.
displayNamestringNoUser display name to store or update for this channel identity.
messageIdstringNoClient-generated idempotency/deduplication ID for this action.
isGroupbooleanNoSet to true when the command came from a group conversation.
groupExternalIdstringRequired for group-scoped commandsStable group/channel/conversation ID from your platform.
groupNamestringNoHuman-readable group name.
participantsarrayNoGroup participant IDs or participant objects. Used for group member sync.

For group commands, include:

{
  "externalUserId": "U12345",
  "isGroup": true,
  "groupExternalId": "G67890",
  "groupName": "Engineering"
}

Command endpoints return the same shape as inbound messages unless noted:

{
  "ok": true,
  "replies": ["..."]
}
Slash commandAPI endpointExtra body fields
/getlinkPOST /api/channels/:channelId/commands/getlinkNone. Returns { agent, url, message }.
/getwallet AGENTPOST /api/channels/:channelId/commands/getwalletOptional agentName or name. If omitted, uses the loaded agent. Returns { agent, publicKey, message }.
/helpPOST /api/channels/:channelId/commands/helpNone
/statusPOST /api/channels/:channelId/commands/statusNone
/yolo-modePOST /api/channels/:channelId/commands/yolo-modeNone
/yolo-mode-offPOST /api/channels/:channelId/commands/yolo-mode-offNone
/mutePOST /api/channels/:channelId/commands/muteNone
/listPOST /api/channels/:channelId/commands/listNone
/balancePOST /api/channels/:channelId/commands/balanceNone
/fundPOST /api/channels/:channelId/commands/fundNone
/loginPOST /api/channels/:channelId/commands/loginNone
/logoutPOST /api/channels/:channelId/commands/logoutNone
/deloadPOST /api/channels/:channelId/commands/deloadNone
/reposPOST /api/channels/:channelId/commands/reposNone
/create NAMEPOST /api/channels/:channelId/commands/createRequired name or agentName
/spawn REPOPOST /api/channels/:channelId/commands/spawnRequired repo, repoName, or fullName
/load NAMEPOST /api/channels/:channelId/commands/loadRequired name or agentName
/share NAMEPOST /api/channels/:channelId/commands/shareRequired name or agentName; use with group fields
/share-agent NAMEPOST /api/channels/:channelId/commands/share-agentRequired name or agentName; use with group fields
/create-shared NAMEPOST /api/channels/:channelId/commands/create-sharedRequired name or agentName; use with group fields
/unshare-agent NAMEPOST /api/channels/:channelId/commands/unshare-agentRequired name or agentName; use with group fields
/start [NAME]POST /api/channels/:channelId/commands/startOptional name or agentName
/start_agent [NAME]POST /api/channels/:channelId/commands/start-agentOptional name or agentName
/stop [NAME]POST /api/channels/:channelId/commands/stopOptional name or agentName
/stop_agent [NAME]POST /api/channels/:channelId/commands/stop-agentOptional name or agentName
/restart [NAME]POST /api/channels/:channelId/commands/restartOptional name or agentName
/delete NAMEPOST /api/channels/:channelId/commands/deleteRequired name or agentName
/fund_agent AGENT AMOUNTPOST /api/channels/:channelId/commands/fund-agentRequired agentName or name; required amountUsd or amount
/fund_agent AGENT AMOUNTPOST /api/channels/:channelId/commands/fund_agentAlias for /commands/fund-agent
/fork NAME REPOPOST /api/channels/:channelId/commands/forkRequired name or agentName; required repo, repoUrl, or fullName
/yolo META-COMMANDPOST /api/channels/:channelId/commands/yoloRequired prompt, text, or command
/prompt MESSAGEPOST /api/channels/:channelId/commands/promptRequired prompt, text, or task; legacy loaded-agent path

Command endpoint argument reference

EndpointRequest body argumentsBehavior
POST /api/channels/:channelId/commands/helpCommon fields only.Returns the available command list for the user or group.
POST /api/channels/:channelId/commands/statusCommon fields only.Returns the currently loaded agent and status.
POST /api/channels/:channelId/commands/yolo-modeCommon fields only.Enables YOLO mode for this user in direct conversations.
POST /api/channels/:channelId/commands/yolo-mode-offCommon fields only.Disables YOLO mode for this user.
POST /api/channels/:channelId/commands/muteCommon fields only.Mutes currently active task notifications until completion.
POST /api/channels/:channelId/commands/listCommon fields only. Include isGroup and groupExternalId to list shared agents in a group.Lists the user's agents in DMs or the group's shared agents in groups.
POST /api/channels/:channelId/commands/balanceCommon fields only.Returns account balance, free credits/hours, and deposit address when available.
POST /api/channels/:channelId/commands/fundCommon fields only.Returns funding instructions.
POST /api/channels/:channelId/commands/loginCommon fields only.Returns a one-click sign-in link for the channel user.
POST /api/channels/:channelId/commands/logoutCommon fields only.Logs the channel user out of message-based access and unloads their agent.
POST /api/channels/:channelId/commands/deloadCommon fields only.Unloads the current direct-conversation agent for the user.
POST /api/channels/:channelId/commands/reposCommon fields only.Lists repositories connected to the user's chat.dev account.
POST /api/channels/:channelId/commands/getlinkCommon fields only. Include groupExternalId to use the group's loaded agent.Returns { agent, url, message }; url opens the live agent page after signing the user in.
POST /api/channels/:channelId/commands/getwalletOptional agentName or name. If omitted, uses the loaded agent. Include groupExternalId to search group-shared agents.Returns { agent, publicKey, message }.
POST /api/channels/:channelId/commands/createRequired name or agentName.Creates a new direct-conversation agent and loads it for the user.
POST /api/channels/:channelId/commands/spawnRequired repo, repoName, or fullName.Creates and loads an agent from a connected repository.
POST /api/channels/:channelId/commands/loadRequired name or agentName. Include group fields to load a shared agent in a group.Loads an existing agent for future messages.
POST /api/channels/:channelId/commands/shareRequired name or agentName; also include isGroup: true and groupExternalId.Shares an owned agent into a group so other group members can talk to it. Owners can talk to their own agents in group chats without sharing first.
POST /api/channels/:channelId/commands/share-agentRequired name or agentName; also include isGroup: true and groupExternalId.Alias behavior for /share-agent NAME.
POST /api/channels/:channelId/commands/create-sharedRequired name or agentName; also include isGroup: true and groupExternalId.Creates a new agent, shares it into the group, and loads it there.
POST /api/channels/:channelId/commands/unshare-agentRequired name or agentName; also include isGroup: true and groupExternalId.Removes an owned shared agent from the group.
POST /api/channels/:channelId/commands/startOptional name or agentName. If omitted, uses the loaded agent.Starts the named or loaded agent.
POST /api/channels/:channelId/commands/start-agentOptional name or agentName. If omitted, uses the loaded agent.Alias behavior for /start_agent.
POST /api/channels/:channelId/commands/stopOptional name or agentName. If omitted, uses the loaded agent.Stops the named or loaded agent.
POST /api/channels/:channelId/commands/stop-agentOptional name or agentName. If omitted, uses the loaded agent.Alias behavior for /stop_agent.
POST /api/channels/:channelId/commands/restartOptional name or agentName. If omitted, uses the loaded agent.Restarts the named or loaded agent.
POST /api/channels/:channelId/commands/deleteRequired name or agentName.Deletes the named agent if the channel user has permission.
POST /api/channels/:channelId/commands/fund-agentRequired agentName or name; required amountUsd or amount.Returns instructions to fund the agent wallet with the requested USD amount.
POST /api/channels/:channelId/commands/fund_agentRequired agentName or name; required amountUsd or amount.Alias for /commands/fund-agent.
POST /api/channels/:channelId/commands/forkRequired name or agentName; required repo, repoUrl, or fullName.Creates a new agent attached to a connected repository.
POST /api/channels/:channelId/commands/yoloRequired prompt, text, or command.Runs the meta-command through chat.dev's AI router.
POST /api/channels/:channelId/commands/promptRequired prompt, text, or task.Sends a task to the currently loaded agent. In group chats, prefer @agentname message or @chatdev message; /prompt remains for legacy loaded-agent integrations.

Command request examples

Create an agent:

{
  "externalUserId": "U12345",
  "displayName": "Alice",
  "name": "my-agent"
}

Load or start an agent:

{
  "externalUserId": "U12345",
  "agentName": "my-agent"
}

Send a task to the loaded agent:

{
  "externalUserId": "U12345",
  "prompt": "Fix the failing checkout test and open a PR."
}

Run a group command:

{
  "externalUserId": "U12345",
  "displayName": "Alice",
  "isGroup": true,
  "groupExternalId": "G67890",
  "groupName": "Engineering",
  "agentName": "team-agent"
}

Fund an agent:

{
  "externalUserId": "U12345",
  "agentName": "my-agent",
  "amountUsd": 25
}

Fork an agent from a connected repo:

{
  "externalUserId": "U12345",
  "name": "bugfix-agent",
  "repo": "owner/repo"
}

Get loaded agent terminal link

POST /api/channels/:channelId/commands/getlink
Authorization: Bearer <apiKey>
Content-Type: application/json

{
  "externalUserId": "U12345",
  "displayName": "Alice",
  "groupExternalId": "G67890"
}

groupExternalId is optional. Include it when the button was clicked in a group conversation so chat.dev can use the group's loaded shared agent.

Response:

{
  "agent": { "name": "my-agent", "status": "running" },
  "url": "https://chat.dev/api/auth/session-login?sid=...",
  "message": "Open \"my-agent\" in chat.dev: https://chat.dev/api/auth/session-login?sid=..."
}

Opening url signs the user into chat.dev and shows the real agent page with the live terminal. This is intentionally different from the public sanitized history page.

Get agent wallet public key

POST /api/channels/:channelId/commands/getwallet
Authorization: Bearer <apiKey>
Content-Type: application/json

{
  "externalUserId": "U12345",
  "displayName": "Alice",
  "agentName": "my-agent",
  "groupExternalId": "G67890"
}

agentName is optional. If omitted, chat.dev uses the loaded agent for the user or group. groupExternalId is optional; include it to look up an agent shared into that group before falling back to the user's own agents.

Response:

{
  "agent": { "name": "my-agent", "status": "running" },
  "publicKey": "7xK...",
  "message": "my-agent wallet public key: 7xK..."
}

Text command shortcuts#

Channel UIs can also expose text shortcuts. When your app sends:

{
  "externalUserId": "U12345",
  "message": "/getlink"
}

chat.dev replies with a one-click login URL for the currently loaded agent.

When your app sends:

{
  "externalUserId": "U12345",
  "message": "/getwallet my-agent"
}

chat.dev replies with that agent's wallet public key.

Outbound webhook format#

When an agent sends a response, chat.dev POSTs to your callback URL:

{
  "event": "message.send",
  "channelId": "ch_abc123",
  "externalUserId": "U12345",
  "groupExternalId": "G67890",
  "message": "I've created the Express server. Here's what I did..."
}

Headers:

  • Content-Type: application/json
  • X-Webhook-Signature: <HMAC-SHA256 hex digest>
  • X-Channel-Id: ch_abc123

Delivery expectations:

  • Respond with any 2xx status after you accept the message.
  • Use externalUserId to route DMs.
  • Use groupExternalId when present to route group messages.
  • Validate the signature against the raw request body using the channel's webhookSecret.
  • Treat duplicate payloads idempotently; future retry behavior may redeliver the same logical message.

Text-only channel registration#

For integrations that operate purely via messaging (no browser onboarding), register a text-only channel using a registration key. This bypasses the session-cookie requirement entirely.

POST /api/channels/register
Content-Type: application/json

{
  "registrationKey": "<secret>",
  "name": "My Telegram Bot",
  "callbackUrl": "https://your-server.com/chat-dev-webhook",
  "platform": "telegram",
  "ownerEmail": "you@example.com"
}
FieldRequiredDescription
registrationKeyYesSecret registration key (contact us to obtain)
nameYesChannel display name
callbackUrlYesYour HTTPS webhook endpoint for outbound messages from chat.dev
platformNoPlatform identifier (default: custom)
ownerEmailNoEmail for the channel owner account. If omitted, a new account is auto-created.

Response (201):

{
  "id": "ch_abc123",
  "name": "My Telegram Bot",
  "platform": "telegram",
  "callbackUrl": "https://your-server.com/chat-dev-webhook",
  "apiKey": "chk_...",
  "webhookSecret": "whsec_...",
  "textOnly": true
}

How text-only channels differ#

  • No browser required to start. Users can create and use agents from the channel immediately.
  • Freemium account setup. Channel-created users receive the same free agent/runtime/API allowance as lightweight web signups. They only receive a continue-setup link after they hit the free agent or prompt/API usage limits.
  • Auto-onboarding. On a user's first message, they receive a welcome message with an explanation of chat.dev, available commands, links to the Terms of Service and Privacy Policy, and their auto-generated SOL wallet address.
  • Implicit consent. The welcome message states: "By continuing to communicate with this channel you agree to these terms."
  • SOL wallet. Each new user automatically gets a Solana deposit address for funding agents. The address is included in the welcome text and in a structured JSON reply:
{
  "type": "welcome",
  "solAddress": "7xK...",
  "tosUrl": "https://chat.dev/terms",
  "privacyUrl": "https://chat.dev/privacy"
}

Structured replies are prefixed with __structured: in the replies array. Parse the JSON after that prefix to extract wallet addresses programmatically.

User accounts#

Channel users get auto-created chat.dev accounts on first message. Each user is identified by channelId + externalUserId. Users can link their channel identity to an existing chat.dev account via the /login command.

All commands#

Channel users have access to the same commands as SMS users. See the Commands page.

Every slash command exposed to channel users can be called as a dedicated API endpoint under POST /api/channels/:channelId/commands/.... The complete endpoint list and request fields are in the Channel command endpoints section above.