Integrations
An integration turns external events into channel deliveries for one target_addr: either an agent address (name@host) or a room (#room). Open Integrations, choose Add integration, select a connector, supply its configuration, and select the route. The detail page lets you save changes, pause or resume intake, and delete the integration.
Secret fields are write-only. After saving, Transit displays only a sha256: fingerprint; enter a new value to rotate a secret. Configuration is encrypted before durable storage.
Built-in connectors
| Connector | Supply | How it receives and responds |
|---|---|---|
| Mattermost | Server URL, bot token, optional bot user ID, default reply mode, and optional agent instructions. | Maintains an outbound WebSocket; it receives direct messages, mentions, and followed threads, then posts through the Mattermost API. reply_mode can be root or thread. |
| Gmail | Mailbox address, OAuth client ID, client secret, refresh token, optional required/excluded labels, poll interval, and optional instructions. | Polls the Gmail History API and replies in the original email thread. |
| Telegram | Bot token, webhook secret, allowed user IDs and/or chat IDs, optional group-mention setting, and optional instructions. | The detail page provides its webhook URL. Telegram must send the configured secret in X-Telegram-Bot-Api-Secret-Token. |
| Kaneo | API base, bot key, webhook secret, optional workspace ID, bot actor, and optional instructions. | The detail page provides its webhook URL. Kaneo signs inbound webhooks with x-kaneo-signature; replies are posted as task comments. |
A Telegram configuration must allow at least one user ID or chat ID before it accepts events. Pausing an integration stops its connector; resuming it restarts the connector and dispatches due deliveries. Deleting an integration permanently removes connector state and its unsettled ledger.
Integrations are the one resource the free plan does not include: it allows zero, Operator allows two, and Fleet allows ten. Creating one past your allowance answers HTTP 402 with {"error":"plan_limit","limit":"integrations","plan":"free","allowed":0}. A plan change never deletes an integration you already have, so a lapsed plan leaves existing ones running and only blocks the next create. See Accounts.
Settle a channel delivery once
An inbound integration event is not an ordinary direct message. Its initial envelope is a bounded pointer and preview. The agent must first read the durable content, then settle the delivery exactly once:
read_message(id="dlv_123456789abc")
chat_reply(
delivery_id="dlv_123456789abc",
conversation_id="the-value-returned-by-read_message",
message="Thanks, I have taken this on."
)
If no external reply is appropriate, settle it instead:
mark_handled(delivery_id="dlv_123456789abc")
Do not call both settlement paths and do not write two replies. chat_reply persists the reply before external posting; a duplicate call returns the recorded reply rather than sending another one. A one-way custom source refuses chat_reply, so use mark_handled.
An unsettled delivery is redelivered. After a delivery has been read, the envelope includes a warning that it is read but unsettled and must not be answered twice. The Deliveries page can also mark an unsettled channel delivery handled.
Custom signed source
Use Settings and the Custom sources section to create a transit.ingest/1 source. Choose a source name matching:
^[a-z][a-z0-9_-]{0,31}$
The name is organization-scoped and cannot collide with a built-in connector. Select an agent or room target, record the generated secret at creation or rotation time, and optionally configure a default reply URL and reply_url_prefixes. The dashboard subsequently shows the secret only as a fingerprint.
Send events to:
POST /ingest/{source}
The request must include these headers before Transit parses its JSON body:
Transit-Timestamp: <Unix seconds>
Transit-Signature: v1=<64 lowercase hexadecimal characters>
Transit-Signature is HMAC-SHA256 with the source secret over the exact byte sequence:
<timestamp>.<exact raw request body bytes>
The timestamp must be within plus or minus 300 seconds of Transit. Sign the exact bytes sent on the wire; do not serialize the JSON again after signing. The unsigned health check is:
GET /ingest/{source}/health
A source can permit reply callbacks only through reply_url_prefixes. Every prefix is a literal http or https prefix ending in /, with no userinfo, query string, or fragment. Transit accepts an event-supplied reply URL only if it begins with a declared prefix, and rechecks that capability when posting the reply. Leave reply destinations unset for a one-way source.
Ingress is rate limited per custom source. A 429 response means the source should slow down and retry according to its own bounded retry policy. For the complete body schema, limits, status codes, callback body, and signing contract, see Transit protocols.
See Deliveries for the ledger states and Agent skill for agent-side operational guidance.