API Reference
API: Errors & Rate Limits
Beacon uses conventional HTTP status codes to indicate success or failure. This page covers every status code the API returns, the error response format, rate limiting headers, and best practices for resilient integrations.
HTTP status codes
| Code | Name | Description |
|---|---|---|
200 |
OK | The request succeeded. Returned for GET and PATCH requests. |
201 |
Created | A new resource was created successfully. Returned for POST requests. |
401 |
Unauthorized | The request is missing an API token or the token is invalid/revoked. |
403 |
Forbidden | The token is valid but does not have permission for this action. This can happen if you try to access a resource in a different workspace. |
404 |
Not Found | The requested resource does not exist. Check the ID or slug in the URL. |
422 |
Unprocessable Entity | The request body contains invalid data. The response includes field-level error messages. |
429 |
Too Many Requests | Rate limit exceeded. Wait and retry after the period indicated in the Retry-After header. |
500 |
Internal Server Error | Something went wrong on our end. If this persists, contact support. |
Error response format
All error responses (4xx and 5xx) follow a consistent JSON structure:
{
"message": "The given data was invalid.",
"errors": {
"title": [
"The title field is required."
],
"impact": [
"The selected impact is invalid."
]
}
}
| Field | Type | Description |
|---|---|---|
message |
string | A human-readable summary of the error. Always present. |
errors |
object | An object mapping field names to arrays of error messages. Present on 422 responses. May be absent on other error codes. |
Error examples
401 Unauthorized (missing or invalid token):
{
"message": "Unauthenticated."
}
404 Not Found:
{
"message": "No query results for model [StatusPage]."
}
422 Validation error:
{
"message": "The given data was invalid.",
"errors": {
"status": [
"The selected status is invalid. Valid values: operational, degraded, degraded_performance, partial_outage, major_outage, maintenance, unknown."
]
}
}
Rate limiting
Beacon enforces rate limits to ensure platform stability. Limits are applied at two scopes:
| Scope | Limit | Window |
|---|---|---|
| Per workspace (by token) | 120 requests | 1 minute |
| Per IP address | 60 requests | 1 minute |
Rate limit headers
Every API response includes headers that indicate your current rate limit status:
| Header | Description |
|---|---|
X-RateLimit-Limit |
The maximum number of requests allowed in the current window. |
X-RateLimit-Remaining |
The number of requests remaining before the limit is reached. |
Retry-After |
The number of seconds to wait before retrying. Only present on 429 responses. |
Example response headers:
HTTP/1.1 200 OK
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
Content-Type: application/json
Handling 429 Too Many Requests
When you exceed the rate limit, Beacon returns a 429 response:
HTTP/1.1 429 Too Many Requests
Retry-After: 23
Content-Type: application/json
{
"message": "Too Many Requests"
}
Your code should:
- Read the
Retry-Afterheader to find out how long to wait. - Pause for that many seconds before retrying the request.
- Do not retry in a tight loop -- this will extend the rate limit window.
Best practices
Exponential backoff
For transient errors (429, 500, 502, 503, 504), implement exponential backoff with jitter:
// Pseudocode: exponential backoff
max_retries = 5
base_delay = 1 // seconds
for attempt in 1..max_retries:
response = make_request()
if response.status == 429:
wait = response.headers["Retry-After"]
elif response.status >= 500:
wait = base_delay * (2 ** attempt) + random(0, 1)
else:
break
sleep(wait)
Idempotency
PATCH requests are naturally idempotent -- sending the same update twice produces the same result. POST requests (creating incidents and updates) are not idempotent by default.
To avoid creating duplicate resources when retrying after network errors:
- Check whether the resource was actually created before retrying a failed POST (the server may have processed it even if you did not receive the response).
- Use unique titles or external identifiers to detect duplicates.
- For incident updates, check the incident timeline to see if your update was already posted.
General error handling
- Always check the HTTP status code before parsing the response body.
- Log the full error response (message and errors object) for debugging.
- Do not retry 401, 403, or 422 errors -- these indicate a problem with the request itself, not a transient failure.
- Monitor your
X-RateLimit-Remainingheader to proactively throttle requests before hitting the limit.