For developers building on Allternit’s messaging channels. User docs: Messaging channels, Calls and texts in threads.

Thread events

A channel conversation is an ordinary bot thread whose event log carries channel.* events. The app folds them with foldChannelEvents (src/lib/gateway/channel.ts) into ChannelMessage[]; the thread’s ChannelConversationBinding says which provider and whether the bot may reply. Events carry ts, optional author (human, allternit_bot, vendor_agent), replyToId, mentions, files, and for email subject, from, to, cc.

Bot channel routes

Call events

Frozen contract between the voice engine and messaging (HANDOFF-realtime-voice-2026-10-02.md §4.1). Events use camelCase, a call.* prefix, a callId in every payload, and the idempotency key call:<callId>:<type>:<n>. foldCallEvents (src/lib/gateway/call.ts) turns them into CallModel[]. Tool use during a call reuses the agent.tool.* events.

Call controls

POST /api/v1/voice/calls/{callId}/control with { action, target?, digits?, to?, mode? }, where action is hangup, mute, unmute, hold, resume, dtmf, transfer, takeover, listen or release. The UI renders the state from call.state.changed, never from the request. listen and takeover return a LiveKit { token, url, room } (receive-only and publish-capable respectively) for joinCallAudio.

Components

CallScreen, CallCard and SmsThread (src/components/gateway/phone/) take plain data and injected callbacks so a phone connector’s MCP App can mount them. Props: src/components/gateway/phone/README.md. In the phone shell, phone.css makes the call screen and connect wizards full-screen sheets, keyed on .phone-root and the data-call-screen, data-connect-wizard, data-coming-soon, data-wizard-footer, data-call-card, data-sms-composer and data-off-bot attributes; do not rename those without updating phone.css.

Connect API

src/lib/gateway/connect-api.ts is the typed client for the wizards. createConnectApi(http, cloud, runtimeId) takes the runtime HttpLike, a cloud fetch (cloudApiFetch, the signed-in token) and the current runtime id; connectApi is the default instance. Each wizard calls the route that implements it: A 404 or 503 on a read means the provider’s backend isn’t there: availability calls resolve to “not available” and the wizard shows its Coming soon panel. Company domains for bot email are not built yet; the wizard says so instead of failing. There is no test-message button: a test needs a conversation to send to, so the done step tells people to message the bot on that channel. The email wizard has no test button: it tells people to email the address from their own inbox. Wizards live in src/components/gateway/connect/. ConnectWizard is the shared step engine (intro, action, form, waiting, code, done); each provider supplies its steps. ConnectWizardDialog maps a provider to its wizard and is mounted by MessagingConnectorsSection and BotMessagingToggles.

Sender allowlist

Who may make a bot act by messaging one of its channels (channel_auth.rs, migration V244). Every inbound binding has senderPolicy (owner or anyone) and allowedSenders (a list of platform user ids, phone numbers or email addresses; compared case-insensitively, @ and phone formatting ignored). New bindings default to owner; bindings that existed when V244 ran were set to anyone with a backfilled_open audit row. A refused sender gets no bot turn and an audit row in channel_sender_audit (rejected). On a messaging connection they also get one reply naming their id (once per sender per account while the runtime runs). A refused email is acknowledged (202 {"delivered": false, "senderNotAllowed": true}) without a reply, and a refused inbound call gets 403 from POST /api/v1/voice/calls. A phone number registered without a channel account has no setting and stays open (logged). Policy changes are audited as policy_changed. Unknown policy values fail closed.

Phone device tools

Desktop-only. A paired Android phone is exposed to bots through the allternit-phone MCP server: phone.screenshot, phone.tap, phone.type, phone.swipe, phone.open_app, phone.task, phone.sms.send and phone.call.dial. phone.sms.send and phone.call.dial always require a confirmation on the computer. The device manager, adb handling and gateway are described in A phone for your bot. The renderer reaches Desktop through window.allternit.phones (src/lib/phones-bridge.ts); outside Desktop that bridge is absent and the Phones section shows “Connect a phone from Allternit Desktop.”