Overview
The AllternitBus API provides the runtime surface agents use to send and receive messages, store encrypted secrets, resolve connector credentials, and manage identity channels such as email, phone, and wallet addresses. All authenticated routes are mounted under/api/v1 and require a valid bearer token via the platform auth middleware. The public inbound webhook is mounted at /webhooks/photon and is called server-to-server by Photon.codes.
This namespace is served by the Allternit API data-plane node (
http://127.0.0.1:8013 on the same machine, or your paired or provisioned node). The hosted Cloud API at https://api.allternit.com does not route it; it relays only agent sessions, canvases, office and beta research/sessions. See Cloud API.Base URL
Authenticated surface:Authentication
All authenticated routes require a valid bearer token in theAuthorization header. The inbound Photon webhook is authenticated server-to-server by Photon.codes and does not carry a Clerk session. See Authentication for details.
Endpoints
Message inbox
Send a message
Request body
Example request
Example response
List inbox messages
Query parameters
Example request
Example response
Inbound webhook
Receive an inbound message
to phone number. No bearer token is required.
Request body
Example request
Example response
Secrets
Set a secret
token_crypto. If a secret with the same key already exists, it is overwritten.
Request body
Example request
Example response
Resolve secrets
missing and errors.
Request body
Each reference:
Example request
Example response
Connectors
Resolve connector credentials
connector_connections row for the caller, then falls back to legacy allternit_vault_credentials that belong to the agent and user.
Request body
Each binding:
Example request
Example response
Identity channels
Get identity channels
null.
Example request
Example response
Provision email
ALLTERNIT_BOT_EMAIL_DOMAIN (default bots.allternit.com): through Allternit’s cloud on a signed-in computer, or directly when the runtime has Allternit Mail’s admin key. See Agent email rail.
When the mailflare agent-email rail is configured (ALLTERNIT_MAILFLARE_URL + ALLTERNIT_MAILFLARE_ADMIN_KEY), this creates a real mailbox on the mailflare worker, mints a mailbox-scoped send/read API key, seals it server-side, and stores the channel with provider "mailflare". The agent can then genuinely receive and (subject to approval) send internet email. When mailflare is not configured, the endpoint falls back to minting an address record only (provider "commrails", a stored value) with no send/receive transport.
Provisioning is idempotent: re-provisioning an agent returns its existing channel. A platform address (provider mailflare) is owned by the server: a PATCH /api/v1/agents/:id that sends a different identityChannels.email.address keeps the stored one. To change it, release it and provision again (below). Switching the bot to its own mail account (provider other than mailflare / commrails) still saves the new address.
To put the bot on a verified company domain, send { "localPart": "support", "domain": "acme.com" } (see Company domains). A domain whose records haven’t all checked returns 409 domain_not_verified; a bot that already has an address elsewhere returns 409 email_address_exists (release it first).
The part before the @ comes from the optional body { "localPart": "ledger-bot" }: 3-40 lowercase letters, numbers and single hyphens (invalid values return 400 invalid_local_part; role names such as postmaster return 400 reserved_local_part). A requested name that is already taken returns 409 email_local_part_taken. Without localPart, the address is a slug of the bot’s name (ledger-bot), with -2, -3 and so on added only when that address is taken. The mailbox’s display name, which becomes the From name on outbound mail, is the bot’s name.
Example request
Example response
Change an agent’s address
replyMode, replyAllowlist) stay. Mail sent to the old address stops arriving. Follow it with POST …/identity/email {"localPart": "<new name>"}.
If the mailbox can’t be removed, the call returns 502 mailbox_not_removed and the agent keeps its address. The app’s email wizard and the bot’s Identity settings do both steps; when the new name is taken they provision the default address again and say which address the bot is on.
Agent email rail
Real inbound/outbound email for agents, backed by a per-installation mailflare worker (seeservices/mailflare/). Inbound mail arrives as an HMAC-signed webhook and is bridged into the agent’s Factory mail threads; outbound mail is held for human approval before it is sent.
Two ways a runtime gets bot email
Inbound mail is verified with the receiving mailbox’s own secret (cloud-provisioned) or the runtime-wide one (admin), before anything in the body is trusted; the bot is found by the event’s
mailboxId, then the delivered-to address, then to. A cloud-provisioned bot’s direct replies (auto, auto_known) are sent with its own key and approved by the runtime itself once its review and autonomy rules allow them. A mailbox’s mail is never delivered to another runtime: each webhook is scoped to one mailbox. ALLTERNIT_BOT_EMAIL_BROKERED=0 turns the cloud mode off. cloud-api answers 503 bot_email_not_configured until ALLTERNIT_MAILFLARE_URL and ALLTERNIT_MAILFLARE_ADMIN_KEY are set on it.
Company domains
Bots can use a customer’s own domain ([email protected]) instead of bots.allternit.com. The domain’s mail runs through Allternit’s mail host, mx.allternit.com (Postfix plus services/mail-relay), not through Cloudflare: the customer’s domain never needs to be in Allternit’s Cloudflare account.
The records (each comes back with
ok: true | false after a check):
Pointing a domain’s MX at
mx.allternit.com sends all of that domain’s mail to the bots, so use a domain or subdomain (bots.acme.com) that doesn’t already receive mail elsewhere. A domain belongs to one Allternit account (409 domain_taken for anyone else); allternit.com and its subdomains are refused.
On a signed-in computer the runtime calls cloud-api (PUT/GET/DELETE /api/v1/runtime-devices/me/bot-email/domains[/:domain], device credential), which records ownership in bot_email_domains (migration 062, applied by hand to prod) and calls Allternit Mail’s /api/v1/relay/domains/:host with the admin key. A runtime with the admin key calls that route itself. Allternit Mail (D1 migration 0012_relay_domains.sql, column domains.transport = 'relay') asks the relay to make the domain’s DKIM key and check DNS, marks the domain active once it verifies, and from then on:
- Inbound: Postfix on
mx.allternit.comaccepts mail only for verified domains and existing bot mailboxes (live socketmap lookups to the relay, which asks the worker’sGET /api/v1/relay/recipient), and the relay posts it to the worker’sPOST /api/v1/relay/inbound. From there it is the same path as any bot mail. - Outbound: mail from a relay domain goes to the relay’s
POST /relay/send, which signs it with the domain’s DKIM key and queues it in Postfix (retries for up to two days).
MAIL_RELAY_URL (https://mx.allternit.com/relay) and MAIL_RELAY_SECRET (32+ characters, the same value as the relay’s RELAY_SECRET). Without them, adding a domain answers 503 custom_domains_unavailable. The relay’s install script is services/mail-relay/deploy/install.sh.
Send email (approval-gated)
The message is not sent immediately. It is recorded as
pending_approval and a review is requested on a Factory mail thread (mail:email-out-<id>). A human approves or rejects via POST /api/factory/mail/decide with { "thread": "<thread_id>", "approve": true|false }; approving triggers the actual send and writes a receipt with the provider message id. The decide response includes an email object for email threads.
Email rail status
Inbound webhook (server-to-server)
X-Email-Platform-Signature HMAC-SHA256 header against ALLTERNIT_MAILFLARE_WEBHOOK_SECRET. message.inbound events are stored and bridged into the receiving agent’s Factory mail thread (mail:email-in-<agent>). Unknown recipients return 202 and are logged.
Provision phone
ALLTERNIT_BOT_PHONE_POOL. The first number not already assigned to another agent is chosen.
Example request
Example response
Cross-surface bridge
Bridge a session
bridged status.