Skip to main content

Documentation Index

Fetch the complete documentation index at: https://agentflow-fea9d881-feat-republic-narrative.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

API keys let you call AgentFlow from servers, CI runners, scripts, and webhook integrations without juggling SIWE / Telegram sessions. They sit alongside cookies and JWTs as a third auth path — same routes, same permissions, just a different header. Each key carries its own metering: a requests-per-minute cap, an optional FLOW spend cap per period (day / week / month / forever), and a usage log every call lands in. Think of it as the OpenRouter Activity page — same shape, FLOW instead of USD.

Wire format

Keys are 72 characters: af_live_ followed by 64 hex chars (32 bytes of CSPRNG randomness, 256 bits of entropy). The server stores only an HMAC-SHA256 hash plus a 12-character display prefix; the raw value is shown to you exactly once.
af_live_3f9a82b1c4e6d77a5b2c1d8e6f4a3b9c2d1e8f7a6b5c4d3e2f1a09b8c7d6e5f

When to use an API key

  • A backend that needs to mint receipts, list marketplace agents, or call /me/* on behalf of its owner.
  • A CI pipeline that publishes agents or runs build-stream tests.
  • A long-lived bot script where keeping a SIWE session alive is awkward.
For browser flows prefer the af_session cookie issued by POST /auth/verify — it is HttpOnly and rotates automatically.

POST /me/api-keys — mint a key

Auth: cookie / bearer / x-api-key.
name
string
required
Human label, 1–64 chars. Surface it in your secret manager so future-you knows what this key is for.
rate_limit_rpm
integer
Per-key requests-per-minute cap. Default 60. Set 0 to disable the cap.
spend_limit_flow
string | number
Optional FLOW spend cap per period. Decimal string preferred ("100.5"); numbers are accepted but lose precision past 6 decimals. Omit for no cap.
spend_period
string
Period bucket — day, week, month, or forever. Default month.
curl -X POST https://api.agentflow.website/me/api-keys \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $JWT" \
  -d '{
    "name": "ci-runner",
    "rate_limit_rpm": 120,
    "spend_limit_flow": "50",
    "spend_period": "month"
  }'
The response shape:
{
  "ok": true,
  "id": 42,
  "name": "ci-runner",
  "prefix": "af_live_3f9a",
  "key": "af_live_3f9a82b1...",
  "created_at": "2026-04-26T10:00:00Z",
  "warning": "Save this key now — it will not be shown again."
}

GET /me/api-keys — list active keys

Returns the public shape only — never the hash. Each entry carries its current limits and spend_period_used so you can render budget bars without a second roundtrip.
{
  "ok": true,
  "items": [
    {
      "id": 42,
      "name": "ci-runner",
      "prefix": "af_live_3f9a",
      "created_at": "2026-04-26T10:00:00Z",
      "last_used_at": "2026-04-26T11:23:45Z",
      "rate_limit_rpm": 120,
      "spend_limit_flow": "50.000000",
      "spend_period": "month",
      "spend_period_used": "12.345678",
      "spend_period_start": "2026-04-01T00:00:00Z"
    }
  ]
}

PATCH /me/api-keys/:id — adjust limits

All fields are optional — pass only what you want to change. Switching spend_period resets spend_period_used to 0 so the new bucket starts clean.
curl -X PATCH https://api.agentflow.website/me/api-keys/42 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $JWT" \
  -d '{ "rate_limit_rpm": 200, "spend_limit_flow": "100" }'

DELETE /me/api-keys/:id — revoke

Soft-revoke. The row sticks around so audit trails (who created what, when it was last used) stay readable. Subsequent x-api-key calls with the revoked key get 401.

Authentication header

Send the raw key in x-api-key on any request that would otherwise need a session:
curl https://api.agentflow.website/me \
  -H "x-api-key: af_live_3f9a82b1..."
Mixing creds is rejected — if you set both x-api-key and Authorization: Bearer … and the key is invalid, you get 401 even though the bearer would have worked.

Rate limits

Every successful response carries:
HeaderMeaning
X-RateLimit-LimitConfigured rate_limit_rpm.
X-RateLimit-RemainingSlots left in the current 1-minute window.
X-RateLimit-ResetISO timestamp when the window rolls over.
When you exceed the cap the API returns 429 Too Many Requests with a Retry-After header (in seconds) and:
{ "ok": false, "error": "rate_limited", "retry_after_ms": 23456 }
The window is sliding 1-minute per key, evaluated atomically against the api_keys row so it stays consistent across all replicas. Setting rate_limit_rpm to 0 disables the cap entirely.

Spend limits

Each request also gets:
HeaderMeaning
X-FLOW-CostFLOW charged for this request (0 for free endpoints).
X-FLOW-Period-UsedFLOW spent so far in the current period.
X-FLOW-Period-LimitConfigured cap (omitted if no cap).
X-FLOW-Period-ResetISO timestamp when the period rolls over.
Once period_used >= spend_limit_flow the API returns 402 Payment Required:
{
  "ok": false,
  "error": "spend_limit_exceeded",
  "period_used": "100.000000",
  "period_limit": "100.000000",
  "period_reset_at": "2026-05-01T00:00:00Z"
}
Recovery is automatic at the next period boundary — no manual reset, no cron. The accumulator clears lazily on the next billed call after the period rolls over.

Usage tracking

Every authenticated request that arrived with x-api-key is logged to api_key_usage (best-effort, non-blocking). Two endpoints expose the data:

GET /me/api-keys/:id/usage?since=day|week|month|all

{
  "ok": true,
  "since": "2026-03-26T10:00:00Z",
  "total_calls": 1421,
  "total_flow_charged": "12.345678",
  "total_tokens_in": 123456,
  "total_tokens_out": 78901,
  "by_endpoint": [
    { "endpoint": "POST /agents/foo/call", "count": 800, "flow": "10.000000" },
    { "endpoint": "GET /me", "count": 600, "flow": "0.000000" }
  ],
  "by_model": [
    { "model": "claude-haiku-4-5", "count": 800, "tokens_in": 100000, "tokens_out": 60000, "flow": "10.000000" }
  ],
  "by_day": [
    { "day": "2026-04-25", "count": 120, "flow": "1.234567" }
  ]
}

GET /me/api-keys/:id/recent?limit=50

{
  "ok": true,
  "items": [
    {
      "id": 9001,
      "endpoint": "GET /me",
      "status_code": 200,
      "flow_charged": "0",
      "tokens_in": 0,
      "tokens_out": 0,
      "model": null,
      "duration_ms": 24,
      "created_at": "2026-04-26T11:23:45Z"
    }
  ]
}
limit is clamped to 200. Use it for live tail / debug. The cabinet’s API key detail page polls this for the “Recent calls” panel.

Comparison with OpenRouter

If you’re already running on OpenRouter, the model is identical — only the unit changes:
OpenRouterAgentFlow
API key with USD spend capAPI key with FLOW spend cap
Activity page (calls + cost)/me/api-keys/:id/usage + cabinet UI
X-RateLimit-* headersX-RateLimit-* headers (same names)
Per-model breakdownby_model in /usage
The cabinet page at agentflow.website/account/api-keys renders the full activity surface — limits panel + stat cards + period progress + daily chart + recent calls — without extra API calls for you to make.

Cabinet UI

A self-service “API Keys” tab in the cabinet lets you create, list, and revoke keys; the per-key detail page at /account/api-keys/:id exposes the limits editor + activity surface described above.

Rotation

Keys are immutable from a credential standpoint. To rotate:
  1. apiKeys.create({ name: 'ci-runner-v2', … }).
  2. Swap your service config to the new key. Both keys keep working in parallel.
  3. apiKeys.revoke(<old-id>).
The window between steps 1–3 is your safety margin; the old key keeps its last_used_at ticking so you can confirm everything migrated before pulling the plug.

Security checklist

  • Store the raw key in env vars, secret managers (1Password, AWS Secrets Manager, doppler), or encrypted CI variables. Never commit it to git.
  • Treat the prefix as the user-facing identifier in audit views — it is safe to share.
  • Set a spend_limit_flow even if you trust the consumer — it’s the cheapest blast radius limit you’ll ever set.
  • Rotate on a schedule (quarterly is a sane default) using the create-then-revoke flow above.
  • Revoke immediately on suspected leaks — soft-revoke preserves the audit trail without giving the attacker any wiggle room.