When a request fails, the API answers with a status and a JSON object. For the addresses and keys, see API reference.
The error object
{
"type": "/help/api-errors#rate_limited",
"title": "Too Many Requests",
"status": 429,
"code": "rate_limited",
"error": "rate_limited",
"message": "Too many requests this minute. Try again in 12 seconds.",
"requestId": "0b6f0d2e-7a41-4d6c-9f1c-2f6a1d3c8a55"
}
The object follows the standard problem details format (RFC 9457) and is sent as application/problem+json. It keeps the error and message fields the API has always sent, so a script that reads those keeps working.
codeanderrorare the same short code. Test for this, not the message.messagesays what is wrong and what to do.typepoints at this page, at the row for the code, andtitleis the HTTP status in words.requestIdis also sent as theX-Request-Idheader. Quote it if you contact support.
Codes
| Status | Code | What it means |
|---|---|---|
| 400 | bad_request | A query value is not valid, such as a date that is not YYYY-MM-DD, an unknown engine or a limit out of range |
| 400 | bad_cursor | The cursor is not one the API gave you. Leave cursor out to start again |
| 401 | unauthenticated | No key was sent. Send Authorization: Bearer YOUR_KEY |
| 401 | invalid_key | The key is not shaped like one of ours, is unknown, or has been revoked |
| 401 | key_expired | The key's expiry date has passed. Generate a new key |
| 401 | invalid_link | A CSV link is incorrect or turned off |
| 403 | workspace_suspended | The key's workspace is suspended |
| 403 | no_workspace | The key's workspace was not found |
| 404 | not_found | No such address, or no project or response with that id that this key can read |
| 405 | method_not_allowed | The API only reads. Use GET |
| 429 | rate_limited | A request limit is used up. Wait for Retry-After seconds |
| 503 | api_not_available | The API is not available right now |
| 503 | database_not_configured | The API is not available right now |
A 401 or a 405 that is sent before the key is read has error and message only.
Codes for changes
These come only from the addresses that make changes. See Change projects through the API. A refused change changes nothing. When the app itself refuses the change (too_many, too_many_facts, domain_overlap, bad_brand, bad_competitor, bad_prompt, project_limit, prompt_limit, duplicate_prompt, not_paused, demo_project, pitch_frozen, and some conflict and bad_request answers), the answer also has "applied": false; the other refusals have no applied field.
| Status | Code | What it means |
|---|---|---|
| 400 | too_many | The project tracks as many competitors as it can. Delete one first |
| 400 | too_many_facts | The project holds as many brand facts as it can. Delete one first. Nothing was added |
| 400 | bad_brand | The project's name or brand is too long or not valid. The message says which and how long it may be |
| 400 | bad_competitor | A competitor's name, website or other names are too long or not valid. The message says which and how long it may be |
| 400 | bad_prompt | A prompt's text, topic or tags are too long or not valid. The message says which and how long it may be |
| 400 | domain_overlap | The website is already one of another brand's other websites in this project |
| 403 | insufficient_scope | The key is read only. Make a key with the Read and write permission |
| 403 | key_tied_to_project | A key tied to one project cannot create projects. Use a key for the whole workspace |
| 403 | role_read_only | The person who made the key is no longer an Admin or Member of the workspace, so the key cannot make changes |
| 403 | project_limit | The workspace has as many projects as its plan allows. Delete one, or choose a bigger plan |
| 403 | prompt_limit | The project has as many active prompts as it can. Pause one first. The answer also has limit, active and room |
| 409 | conflict | That brand is already tracked in this project |
| 409 | own_brand | The project's own brand cannot be deleted. Change it with PATCH instead |
| 409 | duplicate_prompt | That prompt is already in the list: the same words in the same market |
| 409 | not_paused | Only a paused prompt can be deleted. Pause it first |
| 409 | demo_project | The demo project shows sample data and cannot be changed |
| 409 | pitch_frozen | The pitch project has ended, so its markets and prompts cannot be changed |
A change the app itself refuses for another reason answers bad_request, with the reason in message.
Request limits
Each workspace has an hourly quota that depends on its plan, plus a per-minute limit, shared by every key in the workspace.
| Header | Meaning |
|---|---|
RateLimit-Limit | The requests allowed in the hourly window |
RateLimit-Remaining | Requests left in the window |
RateLimit-Reset | Seconds until the window ends |
RateLimit-Policy | The windows that apply, for example 1000;w=3600, 60;w=60: a quota and its window in seconds |
Retry-After | On a 429, the seconds to wait |
The older X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are still sent. X-RateLimit-Reset is a time in seconds since 1 Jan 1970 (UTC), where RateLimit-Reset is a number of seconds from now.
When you get a 429, wait for Retry-After seconds and try again. Do not retry at once.