Channel routing
A binding routes a connection — or one thread of it — to a destination: an AgentSky session, or your webhook endpoint. Which agent handles a conversation is a binding you control; with webhook destinations it's entirely your code.
Bindings
# route the whole connection to a session (or {"webhook": "whk_..."})
curl -s -X PUT https://api.agentsky.dev/v1/channels/connections/{id}/binding \
-H "Authorization: Bearer $AST_TOKEN" -H 'content-type: application/json' \
-d '{"destination": {"session": "sess-..."}}'
# route one thread to your webhook endpoint instead
curl -s -X POST https://api.agentsky.dev/v1/channels/bindings \
-H "Authorization: Bearer $AST_TOKEN" -H 'content-type: application/json' \
-d '{"connection_id": "...", "thread_id": "telegram:app_...:12345", "destination": {"webhook": "whk_..."}}'A destination names exactly one of session or webhook. Connection-level routing is a single slot: PUT .../binding replaces whatever the connection routed to before, so there is never a second competing default. POST /bindings creates thread-scoped rules only, and thread-scoped bindings win over the connection default. route_key is a free label for organizing multiple binding rows. An inbound message on a connected surface with no active binding emits channel.unmapped_conversation instead of dropping.
Session mode
Session-bound inbound becomes agent turns automatically: the platform shows a working marker while the agent runs, the reply posts back into the thread as rendered markdown, and turn.refused reaches your endpoints when a turn is rejected.
Re-point a surface with one call — the connection keeps a single active session:
curl -s -X PUT https://api.agentsky.dev/v1/channels/connections/{id}/binding \
-H "Authorization: Bearer $AST_TOKEN" -H 'content-type: application/json' \
-d '{"destination": {"session": "sess-other"}}'
# posts "You're now talking to ..." into the surface and emits channel.reboundWebhook mode
Bind to a webhook endpoint and the service delivers message.received for every inbound; you reply through POST /v1/channels/threads/{thread_id}/messages. Mapping threads to agents — yours or AgentSky sessions you drive via the sessions API — is your code: look the thread up, create what's missing, send the turn.
Proactive deliveries
# fan out to every thread bound to a destination
curl -s -X POST https://api.agentsky.dev/v1/channels/deliveries \
-H "Authorization: Bearer $AST_TOKEN" -H 'content-type: application/json' \
-d '{"destination": {"session": "sess-..."}, "parts": [{"type": "text", "text": "nightly report ready"}]}'The response carries per-thread results; failures also emit delivery.failed.
The connect flow
POST /v1/channels/connections on a link-flow platform (telegram, imessage, whatsapp) returns a PENDING connection with a connect ceremony — a deep link, and for code flows a phone number + LINK: code. Links expire after 15 minutes.
- Hosted connect page —
https://connect.agentsky.dev/connect/{token}renders the ceremony for you; agents can hand the link to an end user mid-conversation (no credentials transit the page). callback_url— pass it on the connect call and the hosted page pollsGET /connect/{token}/status, then redirects the end user to your URL withconnection_id,status, and yourmetadataechoed as query params once the claim lands.- Claim — the end user taps Start (Telegram) or texts the
LINK:code (iMessage, WhatsApp). The connection flipsCONNECTED, the pre-bounddestinationbecomes the default binding, andchannel.connectedfires with yourmetadata.
Slack and Discord connect synchronously instead: the call creates a per-agent channel under your app's identity and returns CONNECTED directly — no pending ceremony, so callback_url doesn't apply there.
AgentSky