Errors & Limits
What can go wrong, and the numbers to design for.
#The envelope
Every response is JSON in the same envelope. On success errors is null; on failure data is null and errors has a stable errorCode (branch on it), a human errorMessage (show it, never parse it) and sometimes errorDetails.
{ "errors": { "errorCode": "AGENT_RUNNING", "errorMessage": "An agent run is already in progress", "errorDetails": { "runId": "run_01k6xc4n7d" } }, "data": null }Legacy projects and the older host api-accounts.totalum.app keep two older shapes: 403 VCAAS_INSUFFICIENT_CREDITS answers { "error", "code" } and a secret that fails validation { "success": false, "message", "errors": [...] } (Legacy projects).
#Errors any endpoint can answer
| Code | HTTP | Meaning | What to do |
|---|---|---|---|
invalid token / Unauthorized api key | 401 | Missing or unknown api-key header | Send a valid tlm_sk_ key |
VCAAS_INSUFFICIENT_CREDITS | 403 | Your balance is below 1 credit (reads and deleting a project still work) | Add credits |
PROJECT_NOT_FOUND | 404 | No project with this id in your account | Check the id (List Projects) |
PROJECT_NOT_ALLOWED | 403 | Your key is restricted to other projects | Use a key with access |
API_ACCESS_DISABLED | 403 | API access is switched off for this project in your account settings | Switch it on |
PROJECT_NOT_READY | 409 | The project is still being set up (its first seconds) | Retry after Retry-After seconds |
INSUFFICIENT_CREDITS | 402 | The action costs more than your balance | Add credits |
PROJECT_CREDIT_LIMIT_REACHED | 403 | The project's monthly cap for that category is reached | Raise the cap |
AGENT_RUNNING | 409 | A prompt is running | Wait for agent/status to be "done" |
DEPLOYMENT_RUNNING | 409 | A publish is running | Wait for deployments/status to leave "deploying" |
OPERATION_IN_PROGRESS | 409 | Another long operation (restore, import, pause, database move…) holds the project | Retry when it ends (Get Project State) |
PROJECT_PAUSED_BY_USER | 409 | The project is paused | Resume it |
PROJECT_PAUSED_RUNAWAY | 429 | The emergency stop paused the project after unusual usage (it lifts by itself after 24 hours) | Fix the cause, then release it |
AI_MEDIA_PAUSED_THIS_HOUR | 429 | The app used a lot of credits this hour, so its image, video and speech AI calls are paused until the hour ends (UTC); text AI and everything else keep working | Wait for Retry-After (the start of the next hour) |
RATE_LIMIT_EXCEEDED / RATE_LIMITED | 429 | Too many requests | Back off; honour Retry-After |
VALIDATION_ERROR | 400 | A field is missing or has the wrong type | Fix the request |
INVALID_JSON | 400 | The body is not valid JSON | Fix the body |
PAYLOAD_TOO_LARGE | 413 | The JSON body is over 1 MB | Upload files with Upload File |
ROUTE_NOT_FOUND | 404 | No endpoint at this path | Check the path |
METHOD_NOT_ALLOWED | 405 | The path exists for other methods (listed in the Allow header) | Use one of them |
ENGINE_UNAVAILABLE | 503 | A temporary failure | Retry in a few seconds |
INTERNAL_ERROR | 500 | An unexpected error | Retry; contact support if it persists |
Retrying. 4xx means the request must change (except 409 and 429, which clear by themselves). 503 and the PROJECT_NOT_READY 409 are temporary: retry after Retry-After. Every long operation (prompt, publish, restore, import) answers at once and is followed by polling; never retry the start call while the first one is still running.
#Limits
The API's own limits. Plan, project, database and built-in feature limits are all on Limits.
| What | Limit |
|---|---|
| Authentication | One api-key header per request, kept on your server |
| JSON request body | 1 MB |
| File upload | 20 MB per file (Upload File); 300 uploads a minute |
| Prompt | 40,000 characters, up to 10 attachments |
| Multi-prompt batch | 50 prompts |
| One prompt's run | The agent works up to about 40 minutes, then wraps up and saves its work |
| Concurrency per project | One prompt, one publish, one restore or import at a time |
| Requests per API key | Free 10 a second, paid plans 100, Enterprise 1,000 (counted each second, Enterprise over 10 s); over it 429 RATE_LIMITED with Retry-After |
| Prompts per account | All projects together: as many a minute as the plan's new projects a minute (a create counts as one), and twice that many running at once — see Limits; over it 429 RATE_LIMITED with Retry-After |
| Project creation | Per plan: Free 2 projects (1 a minute), Starter 10, Builder 50, Professional 300, Enterprise unlimited — see Create Project |
| Project id | 4–35 characters: lowercase letters, digits and single hyphens, starting with a letter |
| File read / write through the API | 1 MB read, 512 KB write; 300 writes a minute |
| Secrets | 500 per project, values up to 10,000 characters |
| Scheduled jobs | 2 (Free), 10 (Starter) or 20 per environment; every hour (Free) or every minute (paid) at most |
| Export | 5 an hour per project |
| Webhooks | One unfiltered subscription per event; deliveries time out after 10 s |
| The app's built-in features | 100 calls a second per project; 20 paid calls a minute per visitor (AI, web, browser) |
| Database (per environment) | 10 GB on the default database (move to Turso for more); a query runs up to 30 s; 100 bound parameters per query |
| Published site | 5,000 requests a minute per visitor by default (rate limit) |
#Plans and credits
Every plan can use the API, including the free one. Everything is paid in credits: plan credits renew each billing period and are spent first; purchased credits never expire.
- Prompts are metered by the work done: at least 3 credits, usually 3 to 50. A failed run that built nothing is refunded.
- Fixed-price actions (create, publish, restore, export…) are listed by Get Credit Costs.
- The running app (hosting, database, files, AI, e-mail, scraping…) is metered per use; a published project on a paid plan also pays a small monthly fee, and an active custom domain another.
- Cap each project with credit limits and follow spending with Usage & Analytics.
