Errors and limits
Error responses
Section titled “Error responses”Errors use standard HTTP status codes. Most error bodies share this shape:
{ "code": "not_found", "message": "Event '123e4567-e89b-12d3-a456-426614174000' not found", "details": {}}codeis a stable, machine-readable string. Use it in your code.messageis a human-readable explanation. It can change, so don’t parse it.detailsis optional and holds extra information for some errors.
Always check the HTTP status code first: a few errors, such as some request validation errors, can have a different body.
Status codes
Section titled “Status codes”| Status | code |
Meaning |
|---|---|---|
200 OK / 201 Created |
— | The request succeeded. |
204 No Content |
— | The request succeeded and there is no body (for example, deleting an event). |
400 Bad Request |
bad_request, validation_error, invalid_fields |
The request is invalid: a missing or wrong field, a bad query parameter, or a value that breaks a rule. invalid_fields lists the problem fields in details.fields. |
401 Unauthorized |
unauthorized |
The API key is missing, malformed or revoked. See Authentication. |
404 Not Found |
not_found |
The record doesn’t exist in your organization. |
409 Conflict |
conflict |
The request clashes with existing data, for example an externalId that is already used by another record. |
429 Too Many Requests |
rate_limit_exceeded |
You sent too many requests. See Rate limit. |
500 Internal Server Error |
internal_error |
Something went wrong on our side. Retry later; if it keeps happening, contact support with the X-Request-Id. |
502 Bad Gateway |
proxy_error |
The API was briefly unreachable. Retry with a backoff. |
Validation errors
Section titled “Validation errors”When a request body or query parameter fails validation, the API returns 400. For errors
raised while processing the request, the body looks like this:
{ "code": "validation_error", "message": "Request validation failed", "details": { "errors": ["…"] }}Rate limit
Section titled “Rate limit”Each API key can make 60 requests per minute. Requests without a valid key are limited by IP address.
Every response includes:
| Header | Meaning |
|---|---|
X-RateLimit-Limit |
Requests allowed per minute (60). |
X-RateLimit-Remaining |
Requests left in the current minute. |
When you go over the limit, the API returns 429 Too Many Requests with a Retry-After
header (in seconds):
{ "code": "rate_limit_exceeded", "message": "Too many requests. Limit is 60 per 60s."}Wait for the number of seconds in Retry-After before sending more requests.
async function safetyRadarFetch(url, options, attempts = 3) { const res = await fetch(url, options); if (res.status === 429 && attempts > 1) { const seconds = Number(res.headers.get('Retry-After') ?? 60); await new Promise((resolve) => setTimeout(resolve, seconds * 1000)); return safetyRadarFetch(url, options, attempts - 1); } return res;}import timeimport requests
def safety_radar_get(url, attempts=3, **kwargs): res = requests.get(url, **kwargs) if res.status_code == 429 and attempts > 1: time.sleep(int(res.headers.get("Retry-After", 60))) return safety_radar_get(url, attempts - 1, **kwargs) return resTo stay under the limit:
- Use the bulk endpoints (
POST /events/bulk,/assets/bulk,/users/bulk,/action-items/bulk) to create or update many records in one request. - Poll for changes with
updatedAfterinstead of re-reading whole lists. See Pagination and polling. - Use a larger
limitto fetch more records per request.
Request limits
Section titled “Request limits”| Limit | Value |
|---|---|
| Records per bulk request: events, assets, users | 1 to 1,000 |
| Records per bulk request: action items | 1 to 100 |
| Request body format | JSON only, with Content-Type: application/json |
Retrying safely
Section titled “Retrying safely”Requests are not automatically deduplicated. If a POST times out, retrying it can create
the record twice. To make retries safe, set an externalId on the records you create: a
second create with the same externalId returns 409 Conflict instead of a duplicate, and
the bulk endpoints update records by externalId.

