API reference
Errors and limits
Error codes, rate limits and size limits for every endpoint.
#Errors
Errors are JSON with an error code, and sometimes a hint or the limit that was exceeded:
{ "error": "payload_too_large", "limit": 16000 }| Status | error | Meaning |
|---|---|---|
| 400 | invalid_json | The body isn't valid JSON |
| 400 | invalid_event | An event is missing session_id, its session_id has characters outside A–Z a–z 0–9 . _ : - (hooks too, with a hint naming the field), or it has an unknown event. In a batch, one bad event rejects the whole batch |
| 400 | invalid_ask | An ask is missing session_id, or kind isn't approval or reply |
| 400 | invalid_session | session_id is missing or has characters outside A–Z a–z 0–9 . _ : - |
| 400 | invalid_limits | A limits body without a valid provider or with 0 or more than 4 usable windows |
| 400 | invalid_import | An import batch failed validation (see Import history) |
| 400 | invalid_date, invalid_format, invalid_paging | Bad export parameters |
| 401 | unauthorized | No key, a wrong, revoked or expired key, a key with the wrong scope for this endpoint, or a key whose person has left the team |
| 403 | not_allowed | The key's creator's role can't export this dataset |
| 404 | not_found | No such endpoint |
| 404 | unknown_dataset | No such export dataset |
| 405 | method_not_allowed | Wrong HTTP method; the allow header says which one to use |
| 413 | payload_too_large | The body is over the endpoint's size limit (below) |
| 413 | too_many_events | More than 1,000 events in one request |
| 415 | unsupported_media_type | Not content-type: application/json. For OTLP, protobuf isn't supported — use http/json |
| 402 | upgrade_required | Solo's 1,000 API calls this month are used up — upgrade to Team (see API pricing) |
| 402 | monthly_cap_reached | This month's per-call charges reached the monthly cap ($250 by default; on Enterprise an owner can raise it in Settings → Billing); calls start again on the 1st (UTC) — see API pricing |
| 402 | team_required | A Team feature on a Solo workspace: the anonymous insights API, guardrails, notification channels, the audit log, the weekly view and approvers per project, and exports of the audit, guardrails and channels datasets |
| 429 | rate_limited | Too many requests; wait for the time in the retry-after header (seconds) |
| 429 | daily_limit | The workspace reached its reporting limit for today (UTC) — see Rate limits; retry-after: 3600 |
| 503 | migration_pending | The service is being updated; retry after the retry-after header |
A request that's accepted but has nothing Agentower uses (for example a hook event it doesn't track) still succeeds, with "accepted": 0.
The agent actions API has a few codes of its own. The MCP server answers with JSON-RPC errors instead — see MCP server.
#Rate limits
Separate from what's charged: API calls are priced per call per month — see API pricing. Reporting and public stats are never counted or charged; they only have the rate limits below.
| What | Limit | When exceeded |
|---|---|---|
| Reporting (events, hooks, telemetry, plan limits, asks) | Per workspace, a minute: Solo 600 requests and 6,000 events; Team 6,000 requests and 60,000 events. Per key: 1,200 requests a minute | 429 rate_limited, retry-after: 60. Opening an ask returns {"id": null} instead |
The hook's own routes: settings (GET /v1/settings), guardrail checks (/v1/guard/…), asks (/v1/asks/…, opening and checking), the status line (POST /v1/status/claude-code), plan limits (POST /v1/limits) and history import (POST /v1/import/claude-code) | 600 calls a minute, per key | 429 rate_limited with limit_per_minute: 600, retry-after: 60 |
Export API, and MCP export_data | 60 requests a minute, per key | 429 rate_limited, retry-after: 60 |
| Agent actions API | 60 requests a minute, per key | 429 rate_limited, retry-after: 60 |
Public stats (GET /v1/stats) | 60 requests a minute, per key; answers are cached for 60 seconds | 429 rate_limited, retry-after: 60 |
MCP tools/call | 60 a minute, per key (initialize, tools/list and ping are unlimited) | HTTP 429, JSON-RPC error -32003, retry-after: 60 |
| Notification test messages | 10 an hour, per workspace | The app says to try again later |
| Emails, all of Agentower together | One shared daily count (UTC day). Everything except sign-in links — invites, notification emails, weekly emails — stops once 80 emails have gone out that day, so sign-in links always get through | Those emails wait until the next day; an invite is still created, and its link is on the page to send yourself |
| Email notification channels | 20 emails a day (UTC), per workspace, across all its email channels | The rest of the day's notices aren't emailed; the other channels still get them |
| Reporting volume | Request bodies a minute, per workspace: Solo 2 MB; Team 20 MB | 429 rate_limited, like the request limit |
| Reporting a day (UTC), per workspace | Solo 20,000 requests, then 30,000; Team 40,000, then 60,000 | Past the first number only cheap reports are refused (tool-use pings and plain telemetry); session start and end, prompts, Stop, Notification, asks, holds, errors and new subagents still get through. Past the second, everything gets 429 daily_limit with retry-after: 3600; the hook keeps reports on the computer and sends them later |
#Workspace limits
So one workspace — or a runaway script — can't fill the service, each workspace has generous limits. Reporting still answers ok; what's over a limit is dropped, not stored:
| What | Limit | Over it |
|---|---|---|
| Open agents at once | 200 | Signals from new sessions are dropped until some close |
| Open subagents at once | 500 | New subagents aren't shown |
| New agents and subagents a day (UTC) | Solo 300; Team 5,000 | New sessions are dropped until the next day |
| Projects | 200 | New repositories go to a project called Unsorted |
| Imported past sessions a day | Solo 200; Team 2,000 | The rest of the import is skipped |
| History rows a day (UTC): state changes | Solo 4,000; Team 20,000 | The board still updates live, but the rest of the day's state changes aren't kept in the history |
| History rows a day (UTC): work-record steps | Solo 4,000; Team 20,000 | The board still updates live, but the rest of the day's work record steps aren't kept |
Rows a daily budget doesn't keep are counted, per day, in Agentower's own diagnostics for the workspace as rowsDropped (state changes and work steps separately). Agents' states, the board's totals and usage keep updating as normal.
Hooks are built to stay far below these: each event is one small request.
#Size limits
| Endpoint | Largest body |
|---|---|
POST /v1/events, /v1/logs, /v1/metrics, /v1/traces | 1 MB, and at most 1,000 events per request |
POST /v1/hooks/{tool} | 64 kB |
POST /v1/asks/{tool} | 16 kB, or 64 kB for a plan approval (ExitPlanMode) |
POST /v1/status/claude-code, /v1/limits | 2 kB |
POST /v1/import/claude-code | 100 kB, and at most 200 sessions |
POST /mcp | 64 kB |
POST /v1/agents/{id}/message, …/approve | 8 kB (a message is at most 2,000 characters) |
#Timestamps
A ts you send is used only if it's within 24 hours of Agentower's clock; otherwise the time the request arrived is used. Events are applied in the order they happened, so a late "still working" can't undo a "needs you" that came after it.