Skip to main content

Two token types

TokenUsed byUsed on
af_bot_<32hex>bot dev’s serverevery /api/v1/* call from the bot
af_session=<jwt>AgentFlow web userprovisioning endpoint POST /api/v1/bots

Bot token header

Every API call from your bot’s server includes:
X-AgentFlow-Bot-Token: af_bot_d1c2b3a4...
The token grants access to one bot identity (@bot_<slug>:agentflow.website). The platform looks up the bot, finds the stored Matrix access_token, and proxies the call upstream — your code never sees the Matrix token directly.

Why this design

  • One leaked Matrix access_token = full account compromise. With the wrapper, a leaked bot token still only grants access to one bot, and you can rotate it without re-registering a Matrix user.
  • Same shape as Telegram bot tokens — devs know what to do.
  • Lets the platform enforce rate limits, billing, and webhook delivery before reaching Matrix.

Token format

af_bot_<64 hex chars>
Tokens are issued only at creation time (POST /api/v1/bots). They’re stored hashed (sha256) — the platform itself cannot recover a token after issue.

Lifecycle

ActionEndpoint
Create bot + first tokenPOST /api/v1/bots
Show token to devresponse body of create (one time)
Rotate tokenPOST /api/v1/bots/:slug/rotate (v0.2 — planned)
Revoke / deleteDELETE /api/v1/bots/:slug (v0.2 — planned)
WhoamiGET /api/v1/bots/me
The provisioning endpoint POST /api/v1/bots accepts a session cookie because creating a bot is a user-level action — a person owns the bot, not a bot. The cookie is the same af_session JWT that authenticates the AgentFlow web app, set on the .agentflow.website parent domain. For curl / CI:
curl -X POST https://bots.agentflow.website/api/v1/bots \
  -H "Cookie: af_session=<jwt>" \
  -H "Content-Type: application/json" \
  -d '...'
Or pass the JWT as bearer:
curl -X POST https://bots.agentflow.website/api/v1/bots \
  -H "Authorization: Bearer <jwt>" \
  -H "Content-Type: application/json" \
  -d '...'

Errors

StatusBody errorMeaning
401missing_bot_tokenX-AgentFlow-Bot-Token header absent
401invalid_bot_token_shapenot af_bot_<64hex>
401unknown_bot_tokenhash doesn’t match any row
401unauthenticatedprovisioning endpoint hit without session
401invalid_sessionsession JWT malformed
403reserved_slugtried to claim af-* slug as non-admin
429rate_limitedexceeded rate_limit_qps for your tier

Rate limits

Per-bot limits, refreshed every second:
Tierqps
free (default)30
pro (planned)200
enterpriseunlimited
When throttled, the response has Retry-After: 1 and error: rate_limited. Back off and retry.

Security best practices

  1. Never log the bot token (af_bot_*) in plaintext. CI secrets / vaults only.
  2. Use HMAC-signed webhooks. Verify X-AgentFlow-Signature (HMAC-SHA256 of body using the secret you supplied at setWebhook).
  3. Don’t expose your af_session JWT — it grants user-level access to all your bots.
  4. Rotate tokens if a teammate leaves or a leak is suspected.