Rate Limits
Understand Saber API rate-limit headers, retry behavior, and polling guidance for reliable signal, list, and automation workflows.
Saber applies rate limits to authenticated public API requests to protect shared infrastructure and keep long-running research workloads predictable.
Rate limits are scoped to the API key. Requests authenticated through HubSpot are scoped to the HubSpot hub ID instead.
Default limits
| Request type | Default limit | Burst capacity | Notes |
|---|---|---|---|
Write requests (POST, PUT, DELETE) | 2,000 requests per minute | 400 | Used for operations that create, update, delete, or trigger work. |
Read requests (GET, HEAD, OPTIONS) | 100,000 requests per minute | 10,000 | Higher limit for polling, status checks, and read-only list calls. |
| Signal template proposal | 6 requests per minute | 3 | Extra per-route cap for POST /v1/signal-templates/extract/propose because it triggers an LLM call. |
These are the default platform limits. Your organization may have different limits depending on plan, environment, or custom configuration.
Response headers
Every rate-limited public API response includes headers that describe the current bucket:
| Header | Description |
|---|---|
X-Ratelimit-Limit | Maximum requests allowed in the current bucket. |
X-Ratelimit-Remaining | Requests remaining before the bucket is exhausted. |
X-Ratelimit-Reset | Unix timestamp for the next reset window. |
Use these headers to slow down before receiving a 429.
429 responses
When the global API-key limit is exceeded, Saber returns:
{
"statusCode": 429,
"message": "Rate limit exceeded",
"error": "Too Many Requests",
"retryAfter": 12
}retryAfter is the number of seconds to wait before sending another request.
Some endpoint-specific limiters can return the standard Saber error envelope instead:
{
"error": {
"type": "TIMEOUT",
"code": "TOO_MANY_REQUESTS",
"message": "Per-route rate limit exceeded",
"requestId": "..."
}
}In client code, handle both shapes for HTTP 429.
Retry strategy
When you receive a 429:
- Wait for
retryAfterseconds if it is present. - Otherwise wait until the
X-Ratelimit-Resettimestamp. - Add jitter before retrying if many workers share the same API key.
- Keep retries bounded so failed jobs do not loop forever.
For polling workflows, prefer the higher-capacity read endpoints and back off when X-Ratelimit-Remaining gets low.
Credits are separate
Rate limits control request volume. Credits control billable work.
Creating signals and some batch operations can consume credits even if you stay within the request limit. Check your balance before large runs:
saber creditsOr call the credits endpoint directly:
curl https://api.saber.app/v1/credits \
-H "Authorization: Bearer <your-api-key>"