Skip to main content
Channels connect an agent to a messaging provider. Polpo stores provider credentials in a project Connection, verifies inbound webhooks through the official Chat SDK adapter, resolves one agent route, and keeps a stable Session for the external conversation. Supported providers are Slack, Telegram, Discord, and WhatsApp Cloud API.

Runtime contract

The same provider-neutral pipeline handles every supported channel:
  1. An opaque webhook URL resolves exactly one project Channel.
  2. The official provider adapter verifies the untouched request.
  3. Polpo normalizes the message, identity, thread, reply context, and media.
  4. The Channel route selects an enabled agent.
  5. A stable Session preserves conversation history for that external user and thread.
  6. The agent response is delivered through the same official adapter.
Provider tokens, signing secrets, app secrets, and verification tokens never enter the prompt. Disabling a route prevents that route from invoking its agent; disabling the Channel stops the installation.

Tool access

An agent can define channels.allowedTools for every messaging Channel using that agent. Each Channel Route can narrow access further with its own optional allowedTools list. Omitting either policy inherits the upper-level policy; an explicit empty list denies every tool at that level. For an inbound Channel turn, effective access is:
The identity resolver may return allowedTools with disposition: "dispatch" to apply a tenant-, site-, entitlement-, or grant-specific restriction. A server-side client-tool handler may return allowedTools for the continuation. Both are trusted, immutable restrictions and can never expand access. If a Channel preflight starts a Project Loop, Polpo preserves the Session, canonical history, user, scope, metadata, and trusted grants, then recalculates the tool policy for Loop mode. The Channel and Route restrictions do not carry into the Loop.

Trusted application identity

A provider user ID identifies a Slack, Telegram, Discord, or WhatsApp account; it does not prove which user, tenant, or resource that person can access in your application. Configure an optional server-side identity resolver when Channel turns need application-scoped authorization. Polpo calls the resolver after webhook verification and before route selection, Session creation, or model execution. Store the resolver bearer secret in an active project Connection, then update the Channel:
The same configuration is available from the CLI:
The Connection must belong to the same project. Polpo sends its credential as Authorization: Bearer ...; the token is never stored in Channel config. Production resolver endpoints must be public HTTPS URLs. Redirects, private network destinations, oversized responses, invalid JSON, and timeouts fail closed. Resolver request:
Attachment descriptors contain no provider file ID, URL, credential, or bytes. They let the resolver consume or deny unsupported media before Polpo downloads it, creates a Session, or calls a model. channelId is the provider-neutral Chat SDK channel identifier. installationId is the Polpo Channel resource UUID. Use installationId in management and outbound paths such as POST /v1/channels/:installationId/send; do not use the provider channel identifier in that URL. Dispatch an authorized turn:
user is the stable application user. Optional scope.key and scope.version partition the provider thread into an application context such as Personal, Family, or Work. Changing either value creates or resumes a different Session; returning to a previous pair resumes that pair’s Session without leaking history across contexts. Or consume a pairing/setup message before it reaches an agent:
Omit reply to consume the event silently. A consumed event does not select a route, create or resume a Session, invoke Memory, call a model, or run tools. Dispatch metadata is available only through immutable custom-tool invocation context and hidden bindings. Scope is available as invocation.scope.key and invocation.scope.version; metadata remains under invocation.metadata. These trusted values are not copied into model arguments. Private metadata is not copied into Session metadata, Channel events, or loop checkpoints. A durable loop resume calls the resolver again and verifies that the application user and scope still match. Exact provider retries are deduplicated. A completed consume response is not resolved or sent twice; a previously failed event can be reclaimed and re-authorized.

Create a Channel

  1. Open an agent and select Channels.
  2. Select a provider and create or reuse its project Connection.
  3. Enter the provider channel, chat, application, or phone-number identifier.
  4. Configure message coordination, response delivery, typing, and audio behavior.
  5. Complete the provider webhook setup shown in the dashboard.
  6. Send a test message and inspect the Channel events.
Connections hold credentials once at project scope. Agent routes grant a specific agent access to one Channel without copying provider secrets. The agent-native CLI uses the same rollout-controlled management contract as the dashboard and MCP:

Conversation behavior

Incoming messages can run concurrently, queue, debounce, burst, or drop according to the Channel policy. Burst mode combines rapid messages into one turn before agent execution. Queue and drop policies are bounded so one thread cannot consume unbounded memory. Response delivery is independent from inbound coordination:
  • Single keeps one logical response and splits only at provider hard limits.
  • Conversational splits long output at semantic boundaries using the target length and maximum-message preference configured for the Channel.
Segmentation preserves the full response. The delivery record stores all normalized provider message IDs returned by the transport.

Read and typing lifecycle

Read acknowledgement and typing are independent Channel policies:
readReceipt is off or immediate. typing is off, immediate, or before-delivery. The last mode emits typing immediately before each progress or terminal delivery, which avoids presenting a short-lived typing indicator during a long Project Loop. Providers without the corresponding capability ignore the signal. Signal failures are observable but never change execution or delivery results. Existing Channels without activity retain their legacy typingEnabled behavior.

Acknowledge a long continuation

A server-side Channel client-tool handler can return an acknowledgement together with the tool result. Polpo delivers it before starting the configured Project Loop, records it in the canonical Session, and deduplicates provider delivery across retries and reconnects.
acknowledgement accepts non-empty text and up to ten provider-neutral actions. An acknowledgement is sent only after the handler succeeds. If its delivery fails, Polpo does not start the Loop.

Present a Project Loop result

Project Loops can keep structured output for subsequent steps and expose a separate terminal presentation without an extra Agent step:
data is persisted with the Loop run and remains available for inspection. presentation.text is the only terminal text delivered by a Channel. Missing bindings, an empty/non-string presentation, malformed actions, or an unsafe URL fail the Loop deterministically instead of leaking serialized JSON to the user. Supported actions are:
open_url opens an HTTPS URL. postback re-enters the Channel as a typed action event in the same provider thread. Adapters use native controls when available and preserve an intelligible fallback on providers with fewer capabilities.

Reply while a Loop is active

For a fail-fast conversational policy, configure the Channel to process inbound turns concurrently and reject a new turn when the canonical Session already has a non-terminal Project Loop:
The check runs after trusted identity and canonical Session resolution, but before history loading, Memory, model execution, or tools. It is therefore scoped by the resolver’s scope.key and scope.version. Polpo handles the conversational response; the application should retain its own domain lock for the protected resource or working copy.

Media and audio

Official adapters normalize text, reply context, images, audio, video, and files. Polpo downloads media with scoped provider credentials, enforces per-file and per-turn limits, and passes supported content to the model. Unsupported or failed attachments are recorded without silently changing tenant routing. For application-managed assets, configure a trusted attachment handler. Polpo runs it after trusted identity resolution but before Session creation and model execution:
The handler receives multipart/form-data with a binary file part and a JSON-encoded context part. context contains the stable idempotency key, Channel/message descriptor, attachment metadata, and trusted invocation user, metadata, and scope. Polpo authenticates the call with the selected same-project Connection and sends the same key in the Idempotency-Key header. The response contract is intentionally small and strict:
The reference must be an opaque identifier containing only letters, digits, ., _, :, /, or -. Only this reference enters model input. Bytes, provider identifiers, bearer credentials, and trusted grants remain outside the prompt. Count, MIME, declared and downloaded size, timeout, redirect, endpoint, response-size, and schema violations fail closed before model execution. Without an attachment handler, Polpo preserves its normal image, audio-transcription, and workspace-file behavior. With Deepgram configured, audio can be transcribed before agent execution. Voice responses can use Deepgram or ElevenLabs. Response modality is explicit: text or audio, never an accidental duplicate of both. Provider capabilities and selected fallbacks are visible in the Channel configuration.

Outbound delivery

Send proactive text through the data API:
Use a stable idempotencyKey to deduplicate one logical send. Polpo returns the prior delivery for a completed duplicate. If delivery fails, inspect the stored outcome before retrying with a new key; the original key is never replayed automatically because one or more provider messages may already have arrived. Provider-specific targeting: POST /v1/channels/management/{channelId}/test uses the same verified installation and delivery path with a default test message. WhatsApp direct message tests require a recipient:
Send an approved WhatsApp template outside the customer-service window with an explicit, retry-safe operation:
The equivalent API is POST /v1/channels/management/{channelId}/templates:
Template names, language codes, components, and recipients are validated before the provider call. The idempotency key prevents a completed logical delivery from being sent twice, and the provider result is recorded in Channel events and deliveries. Polpo does not silently downgrade a template to a text message.

WhatsApp Cloud API

Create a Meta app with the WhatsApp product. Polpo needs: Save these values through the WhatsApp Connection flow. Register the exact opaque callback URL shown by Polpo in Meta, subscribe the app to WhatsApp message webhooks, and use the same verify token. The GET challenge and signed POST body are verified before project routing or agent execution. The Channel remains pending while this provider action is incomplete. Polpo marks it active only after the opaque callback returns the exact Meta challenge using the configured verify token. Inbound routing is scoped by the opaque installation URL, project, Connection, Channel, route, external user, and provider thread. Duplicate provider events are deduplicated using shared transport state. Media downloads use the scoped Cloud API token. Outbound sends go through the configured phone number ID and are idempotently recorded in Channel events and deliveries.
delivery.completed currently means Meta accepted the outbound API request. The official Chat SDK WhatsApp adapter pinned by Polpo does not yet expose Meta statuses callbacks as normalized delivered, read, or failed receipts. Do not interpret the stored status as proof that the recipient read the message.
WhatsApp’s customer service window, template approval, and recipient eligibility rules still apply.

Events and troubleshooting

Channel events include verified inbound acceptance, transport queue/burst/drop decisions, agent execution, media policy, typing failures, and outbound delivery. Routine coordination events contain bounded metadata only; credentials, raw media bytes, and secret-bearing provider payloads are not stored in prompts or event details. When a provider retries a webhook, the same provider event ID is deduplicated. When outbound delivery fails, the event and delivery record retain the error and whether any message was already delivered. An explicit retry uses a new idempotency key. For WhatsApp failures, verify the opaque callback URL, app subscription, app secret, verify token, phone number ID, token scopes, recipient eligibility, and the customer service window.