Appearance
Responses & Errors
Response Envelope
Responses use one of three shapes depending on the endpoint:
| Shape | Endpoints |
|---|---|
| Bare object | GET /me |
{ "data": { … } } | Single-resource endpoints (/projects/{id}, /countries/{id}, etc.) |
{ "data": [ … ] } | Collection endpoints (/projects, /reports, /keywords, etc.) |
Paginated collections also include meta and links blocks (see Pagination below).
Cached endpoints include a cache_refreshed_at ISO 8601 timestamp at the top level alongside data. Non-cached endpoints do not include this field.
Errors
All errors follow the same envelope regardless of the HTTP status code:
json
{
"error": {
"code": "not_found",
"message": "The requested resource was not found."
}
}| HTTP status | code | When |
|---|---|---|
| 400 | bad_request | Unknown query parameter, out-of-range value, or malformed input |
| 401 | unauthenticated | Missing or invalid Bearer token |
| 403 | forbidden | Token is valid but cannot access this resource (wrong agency, IP not whitelisted, or insufficient scope) |
| 404 | not_found | Resource does not exist |
| 405 | method_not_allowed | Wrong HTTP method used |
| 422 | validation_error | Input failed validation; message names the first failing field |
| 429 | rate_limit_exceeded | Per-minute or per-hour limit exceeded |
| 500 | server_error | Unexpected server error - no internal details are exposed |
Examples:
json
// 400 - unknown query parameter
{ "error": { "code": "bad_request", "message": "Unknown query parameter(s): statuss. Allowed: status, search, agency_id, page, per_page." } }
// 400 - out-of-range report number
{ "error": { "code": "bad_request", "message": "report_number must be between 1 and 26." } }
// 403 - project belongs to a different agency
{ "error": { "code": "forbidden", "message": "You do not have permission to access this resource." } }
// 403 - request from non-whitelisted IP
{ "error": { "code": "forbidden", "message": "Your IP address is not allowed to use this API key." } }Pagination
Only GET /projects is paginated. All other list endpoints return the full set of results.
Add ?page=N to fetch subsequent pages (default: page 1, 100 results per page).
sh
curl -H "Authorization: Bearer YOUR_API_TOKEN" \
"https://admin.trakk.ai/api/v1/projects?page=2"Paginated responses include meta and links alongside data:
json
{
"data": [ "…" ],
"meta": {
"current_page": 2,
"from": 101,
"to": 200,
"per_page": 100,
"total": 247,
"last_page": 3
},
"links": {
"first": "/api/v1/projects?page=1",
"prev": "/api/v1/projects?page=1",
"next": "/api/v1/projects?page=3",
"last": "/api/v1/projects?page=3"
},
"cache_refreshed_at": "2026-03-30T12:00:00.000000Z"
}Out-of-range pages return an empty data array, not an error.
Caching
The following endpoints cache their responses server-side (TTL: 1 hour):
| Endpoint | Cached |
|---|---|
GET /projects | Yes |
GET /projects/{project} | Yes |
GET /projects/{project}/reports | Yes |
GET /projects/{project}/reports/latest | Yes |
GET /projects/{project}/reports/{report_number}/content | Yes |
GET /projects/{project}/keywords | Yes |
GET /me, /countries, /languages, /users | No |
Cached responses include cache_refreshed_at (ISO 8601) at the top level. The cache is invalidated automatically when project data, keywords, or report content changes - stale data is not served after a write.