Skip to main content

Rate limits

The Certificall API caps the number of requests accepted over a rolling 60-second window. Beyond that, it responds with 429 Too Many Requests.

How the quota is counted

The quota is counted per company and per endpoint.

Two consequences worth knowing:

  • Your calls are not penalised by other partners' traffic. Your quota is your own.
  • Calling from several servers neither splits nor multiplies your quota: what is counted is your company, not the originating IP address.
  • Each endpoint has its own counter. Saturating GET /cases does not consume the quota of PATCH /cases/update.

On public endpoints that require no authentication (case sharing, images, media), the company cannot be identified: the quota there is not scoped per company. Those endpoints are sized accordingly, with noticeably higher limits.

note

Requests rejected for another reason (insufficient rights, unknown case…) also consume quota. A failing loop can therefore trigger a 429.

Limits per endpoint

EndpointLimit (per minute)
POST /certificall/api/auth/token200
GET /certificall/api/cases5
PATCH /certificall/api/cases/bulk-update10 (up to 100 cases per call)
POST /certificall/api/reports/report/:reportToken25
GET /certificall/api/reports/:reportToken100
GET /certificall/share/case/:shareToken180
GET /certificall/images/:imageUrl500
GET /certificall/medias/video/:videoUrl500
All other endpoints (including PATCH /certificall/api/cases/update)60

The 429 response

Status code: 429 Too Many Requests

{
"statusCode": 429,
"message": "Rate limit exceeded: max 60 requests per 60s on this endpoint. Retry after 42s.",
"requestId": "b3f1c2e4-...",
"method": "PATCH",
"path": "/certificall/api/cases/update",
"timestamp": "2026-08-13T09:12:34.567Z",
"name": "ApiError",
"details": {
"header": "Error on request: b3f1c2e4-..."
}
}

Response headers:

HeaderMeaning
Retry-AfterNumber of seconds to wait before retrying
X-RateLimit-LimitRequests allowed within the window
X-RateLimit-RemainingRequests left (0 on a 429)
X-RateLimit-ResetSeconds before the counter resets

The X-RateLimit-* headers are also present on successful responses: you can watch X-RateLimit-Remaining to slow down before being blocked.

What to do

  1. Honour Retry-After. Retrying immediately only burns more quota.
  2. Watch X-RateLimit-Remaining and space out your calls as it approaches zero.
  3. Prefer bulk endpoints over loops. To update several cases in a row (for instance propagating a scheduled date), use bulk update: it counts as a single request, where a loop consumes as many as it holds cases. When no bulk endpoint fits your need, spread the requests across the window rather than sending them all at once.

Example of handling a 429:

async function callWithRetry(request, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const response = await request();
if (response.status !== 429) return response;

const retryAfter = Number(response.headers.get('Retry-After')) || 60;
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
}
throw new Error('Quota still exceeded after several attempts');
}

Need a higher limit?

If your integration regularly hits these limits, get in touch: quotas can be adjusted to match your usage.