---
title: Errors and rate limits
slug: errors-rate-limits
description: Error response shape, common statuses, retry behavior, and rate-limit contract.
openapi_tags: [System]
---

# Errors and rate limits

Agent Notifier returns compact JSON errors:

```json
{
  "error": "title is required"
}
```

## Common statuses

| Status | Meaning | Retry? |
|---:|---|---|
| `200` | Request succeeded. | No retry needed. |
| `201` | Resource created. | No retry needed. |
| `202` | Message accepted for asynchronous delivery. | No retry needed unless later delivery proof is required. |
| `204` | Resource deleted or no response body. | No retry needed. |
| `400` | Validation error or invalid query/body. | Fix request first. |
| `401` | Missing or invalid API key, bearer token, or admin key. | Refresh credentials or rotate keys. |
| `404` | Resource or docs page not found. | Check IDs and route spelling. |
| `409` | Conflict, such as duplicate device registration. | Usually no; reconcile state first. |
| `429` | Reserved for rate limiting. | Retry after the advertised delay once implemented. |
| `500` | Unexpected server error. | Retry with backoff; include request ID when reporting. |
| `502` | Upstream dependency failed, such as Azure Blob during media upload. | Retry with backoff if the request is idempotent or safe to repeat. |
| `503` | Dependency or configuration unavailable. | Retry later or check service readiness/config. |

## Request IDs

The API middleware emits request IDs. When a response includes `X-Request-ID`, include it in bug reports or support notes.

## Retry guidance

- Use exponential backoff with jitter for `500`, `502`, `503`, and transient network failures.
- Do not blindly retry `400` or `401` responses.
- For message sends, make client-side retries idempotent with a UUID `client_event_id` that stays stable only for that logical notification. Generate a fresh UUID for each new notification.
- Honor `Retry-After` when it is present on future `429` responses.

## Rate limits

The product plan includes tier-based message quotas, including a Free-tier monthly message cap. The OpenAPI spec does not yet document active `429` responses or rate-limit headers.

Implementation should reserve this public contract before enforcing limits:

| Header | Purpose |
|---|---|
| `RateLimit-Limit` | Request or message limit for the current window. |
| `RateLimit-Remaining` | Remaining requests/messages in the current window. |
| `RateLimit-Reset` | Unix timestamp or seconds until the window resets. |
| `Retry-After` | Retry delay for `429` responses. |

Until those headers are implemented, public docs should avoid promising exact enforcement behavior.
