Rate Limiting

This document describes the rate limiting behavior of the remberg API.

Overview

To ensure fair usage and maintain service stability, all API endpoints are subject to rate limiting. When the rate limit is exceeded, the API will respond with HTTP status code 429 Too Many Requests.


Rate Limit Rules

The API enforces two separate rate limits that work together: a burst limit to prevent sudden spikes and a base limit for sustained load.

💡

As a rule-of thumb: configure your integrations to not send more than 5 requests per second to stay below the limits.

Limit Configuration

ThrottlerRequest LimitTime WindowPurpose
Burst10 requests1 secondPrevents sudden request spikes
Base25 requests5 secondsControls sustained request rate

Both limits use a sliding window algorithm and are enforced simultaneously. A request is rate-limited if it exceeds either limit.


How the Dual Limits Work Together

The burst limit prevents short, intense spikes while the base limit ensures fair usage over longer periods.

Example scenario:

  • You send 10 requests instantly → all succeed (burst limit reached)
  • You send 1 more request immediately → 429 (burst limit exceeded)
  • You wait 1 second, then send 10 more → all succeed
  • You continue this pattern → after 25 requests in 5 seconds, you hit the base limit
  • Even if burst limit has capacity, base limit blocks further requests until the 5-second window slides

Key Behaviors

  1. Per-User Limiting Rate limits are applied individually per authenticated user. Each user has their own rate limit buckets, meaning one user's activity does not affect another user's available quota.

  2. Per-Endpoint Limiting Rate limits are tracked separately for each API endpoint. Requests to /v1/contacts do not count against the limit for /v1/assets, and vice versa. This allows you to make concurrent requests to different endpoints without them interfering with each other.

  3. Sliding Window Both rate limits use a sliding window algorithm. The system continuously tracks requests over the past N seconds (1s for burst, 5s for base), rather than resetting at fixed intervals.

  4. 429 Responses Count Against the Limit Important: Requests that receive a 429 Too Many Requests response also count against the rate limit. This prevents retry storms from immediately succeeding. If you receive a 429, wait for the time indicated in the Retry-After-* header before retrying.


Response Headers

The API includes rate limit information in response headers. The headers differ between successful and rate-limited responses.


Headers on Non-Rate-Limited Responses (≠429)

Since there are two throttlers, each provides its own set of headers with a suffix indicating the throttler name:

HeaderDescription
X-RateLimit-Limit-BaseMaximum requests allowed in the base window (25)
X-RateLimit-Remaining-BaseRequests remaining in the current base window
X-RateLimit-Reset-BaseSeconds until the base window resets
X-RateLimit-Limit-BurstMaximum requests allowed in the burst window (10)
X-RateLimit-Remaining-BurstRequests remaining in the current burst window
X-RateLimit-Reset-BurstSeconds until the burst window resets

Headers on Rate Limited Responses (429)

HeaderDescription
Retry-After-BaseSeconds to wait (if base limit triggered)
Retry-After-BurstSeconds to wait (if burst limit triggered)

Note: The X-RateLimit-* headers are only present on successful responses. When rate limited, only the Retry-After-* header for the triggered throttler is included.


Example Successful Response

HTTP 200 OK
X-RateLimit-Limit-Base: 25
X-RateLimit-Remaining-Base: 24
X-RateLimit-Reset-Base: 5
X-RateLimit-Limit-Burst: 10
X-RateLimit-Remaining-Burst: 9
X-RateLimit-Reset-Burst: 1
Content-Type: application/json

Example Rate Limited Response (Burst Limit)

HTTP 429 Too Many Requests
Retry-After-Burst: 1
Content-Type: application/json

{
  "statusCode": 429,
  "message": "Too Many Requests"
}

Example Rate Limited Response (Base Limit)

HTTP 429 Too Many Requests
Retry-After-Base: 5
Content-Type: application/json

{
  "statusCode": 429,
  "message": "Too Many Requests"
}

Best Practices

Implement Exponential Backoff

When receiving a 429 response, implement exponential backoff with jitter, waiting at least Retry-After-* seconds before retrying.


Spread Requests Over Time

Instead of sending bursts of requests, spread them evenly:

// Instead of this (burst):
await Promise.all(items.map((item) => api.update(item)));

// Do this (throttled):
for (const item of items) {
  await api.update(item);
  await new Promise((resolve) => setTimeout(resolve, 250)); // 4 req/s stays under both limits
}

Tip: Sending requests at 4-5 per second keeps you safely under both the burst limit (10/s) and the base limit (25/5s = 5/s average).


Monitor for 429 Responses

Log and monitor 429 responses in your application to identify integration issues before they impact your workflows.


Summary

AspectBurst ThrottlerBase Throttler
Limit10 requests per 1 second25 requests per 5 seconds
PurposePrevent sudden spikesControl sustained load
ScopePer user, per endpointPer user, per endpoint
WindowSliding (1-second lookback)Sliding (5-second lookback)
429 countingYes, counts against limitYes, counts against limit
RecoveryWait for Retry-After-BurstWait for Retry-After-Base

Both limits are enforced simultaneously. A request is blocked if it exceeds either limit.