Guides

Errors, pagination, and rate limits

Handle Monument REST API status codes and error bodies, page through list endpoints, and stay within rate limits.

This guide covers the three things every integration has to handle: how errors come back, how to page through lists, and how the rate limiter behaves.

Status codes

  • 200 OK and 201 Created return a record.
  • 204 No Content is returned by deletes and has an empty body.
  • 400 Bad Request means the query or JSON body failed validation.
  • 401 Unauthorized means the key is missing, invalid, revoked, or expired.
  • 403 Forbidden means your key does not have permission for the operation. Check the permissions of the person who created the key.
  • 404 Not Found means the record does not exist or is not visible to your key.
  • 409 Conflict means the operation conflicts with the current record state. Read the error message and resolve the conflict before retrying.
  • 429 Too Many Requests means you hit the rate limit.

Error shape

Errors return an error label and a human-readable message. Validation failures also include a details object describing which fields were rejected.

Error body
{
  "error": "Bad Request",
  "message": "Invalid request body",
  "details": {
    "fieldErrors": { "name": ["Required"] },
    "formErrors": []
  }
}
Some endpoints add a machine-readable code and a requestId alongside those fields. Log the message and, when present, the requestId to make support requests faster.

Paginate list endpoints

List endpoints return a pagination object with total, limit, and offset. Walk offset-based pages until you have collected total records.

JavaScript
const headers = { 'X-API-Key': 'monument_your_api_key' };
const limit = 100;
let offset = 0;
const all = [];

for (;;) {
  const res = await fetch(
    `https://api.monument.so/api/v1/projects?limit=${limit}&offset=${offset}`,
    { headers },
  );
  const { data, pagination } = await res.json();
  all.push(...data);

  offset += limit;
  if (offset >= pagination.total) break;
}

Rate limits

Keys default to 60 requests per minute and may be given a custom per-minute limit. Every response carries the current window on three headers:

  • X-RateLimit-Limit is the ceiling for this window.
  • X-RateLimit-Remaining is how many requests are left.
  • X-RateLimit-Reset is the Unix timestamp, in seconds, when the window resets.

When you exceed the limit, the request returns 429 with a Retry-After header (seconds to wait) and this body:

429 body
{
  "error": "Too Many Requests",
  "message": "Rate limit exceeded. Retry after 12 seconds.",
  "code": "RATE_LIMITED",
  "retryAfter": 12
}

Retry safely

Honour the Retry-After header before retrying a 429, and watch X-RateLimit-Remaining to slow down before reaching the limit. Use increasing delays between retries. For reads, retry temporary 5xx failures. After a write fails or times out, check whether it succeeded before sending it again; a blind retry can create duplicates. Resolve other 4xx errors before retrying.