Error Handling
How Trakkr API errors are shaped, what each status code means, and how to handle errors in your integration.
Error Response Format
Errors are simple. You get an HTTP status code, and a JSON body with one field: detail. The status code tells you the category. The detail tells you what happened, in plain English.
detailWhat went wrong, written for a person to read. This is a string on almost every endpoint.
codeOnly on the object form of detail. A short, stable string you can branch on, such as entitlement_verification_unavailable.
messageOnly on the object form of detail. The human-readable version of the same problem.
A small number of endpoints (the ones that check paid access and plan entitlements) put an object in detail instead of a string:
detail is a string before you read detail.message, or a plan-access error will crash your handler.type field, no error-code taxonomy across the whole API, and no request-id header. If you need to quote an error to support, send the status code, the endpoint you called, the time, and the detail text.HTTP Status Codes
The API uses conventional HTTP response codes to indicate success or failure:
Success - Request was successful
Client error - Problem with your request
Server error - Something went wrong on our end
| Code | Description |
|---|---|
200 | OK - Request succeeded |
201 | Created - Resource successfully created |
400 | Bad Request - Invalid parameters |
401 | Unauthorized - Invalid or missing API key |
403 | Forbidden - No permission to access resource |
404 | Not Found - Resource doesn't exist |
429 | Too Many Requests - Rate limit exceeded |
500 | Internal Server Error - Something went wrong |
503 | Service Unavailable - Temporary outage |
What detail says
Because the status code carries the category, the wording of detail is free text and can change. These are real messages the API sends today, so you know what to expect:
| Status | When it happens | Example detail |
|---|---|---|
400 | A required query parameter is missing | brand_id is required |
400 | A parameter value is not one of the allowed options | Invalid view 'weekly'. Must be one of: by_model, by_prompt, summary, time_series |
401 | No Authorization header was sent | Missing API key |
401 | The key does not look like a Trakkr key | Invalid API key format. Keys must start with 'sk_live_' |
403 | The key is not recognised | Invalid API key |
403 | A monthly quota is used up | Monthly diagnosis limit reached (200). Upgrade your plan for more. |
404 | The brand does not exist, or your key cannot see it | Brand not found or no data available |
409 | The thing you are creating already exists | Market GB already exists for this brand |
500 | Something failed on our side | Failed to fetch scores |
503 | A dependency is briefly unavailable | Authentication service temporarily unavailable |
detail will break the first time we reword a message.The one exception: 429
Rate limit replies are produced by the limiter before your request reaches the endpoint, so they do not use detail. A 429 body has a single error string that names the limit you hit:
Retry-After header is sent. Limits are per minute, so wait a full minute and try again. See rate limits for the per-endpoint numbers.Best Practices
Switch on the status code
The status code is the stable part of the contract. Write one branch each for 4xx, 429 and 5xx, then use detail only for logging and display.
Log enough to reproduce
There is no request-id header to quote, so log the status code, the endpoint, the parameters you sent, the timestamp, and the response body. That is what support needs.
Show user-friendly messages
Map status codes to your own wording for your users. Don't pass raw detail text straight through to a screen.
Retry transient errors
Retry 5xx and 429 with a growing wait. Don't retry other 4xx errors: the same request will fail the same way.
detail as normal: a 429 uses error, and a gateway or proxy failure may return no JSON at all.