Docs
Checking Raims account
Integrations

Rate limiting

Control the rate and concurrency of Raims API calls and handle 429 responses with bounded retries.

The API limits how often you send calls and how many requests remain in progress. Your integration should control both, handle 429 Too Many Requests and spread work over time.

Use this guide when preparing an integration, investigating refusals due to excess traffic or planning higher volume. The limits listed here apply to the Raims API; endpoint-specific rules must also be respected.

Shared limits

The allowance belongs to the company and environment identified by the API key. All keys for the same company share the limits in that environment, even when calls come from different servers, processes or applications. Creating or rotating a key does not increase the allowance. Production and Sandbox have separate allowances.

Each endpoint has an additional rate limit. Its HTTP method and path in the reference identify the endpoint: GET /v1/charges/{id} shares the same allowance across all IDs. GET /v1/charges and POST /v1/charges have separate endpoint allowances and share the company's total allowance in the environment.

Coordinate usage across your integration's components. Local control in each process alone does not control their combined traffic.

API limits by company and environment

The values below are the default limits. They may vary according to your company's configured limits.

LimitProductionSandbox
Total requests per second10025
Requests per second for each endpoint2525
Total requests in progress5050

The limits apply together. In Production, for example, the total limit of 100 requests per second does not allow that volume to be concentrated on an endpoint limited to 25. In Sandbox, calls to different endpoints also share the total limit of 25.

Treat them as usage ceilings, rather than a permanent sending target. An HTTP call may query or change a resource; the allowance does not represent a number of payments processed per second.

Rate and concurrency

Rate is how many calls are sent over time. Concurrency is how many have not finished. A slow query continues to occupy capacity even when no new calls are sent.

For example, sending ten calls per second that each take five seconds can keep about fifty calls in progress. Reducing the rate alone does not immediately release calls that are already running.

Spread out call start times and limit how many can remain in progress. Avoid sending an entire batch at once. Short bursts can receive 429 even when the observed average is below the limit; do not use the transition between seconds to concentrate two batches.

Understand the 429 response

429 RATE_LIMITED means the request was refused due to excess traffic and was not executed. The response tells you how long to wait and which control to adjust:

HTTP
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Cache-Control: no-store
Retry-After: 1
Raims-Rate-Limited-Reason: endpoint-rate

{
  "error": {
    "code": "RATE_LIMITED",
    "message": "The API request limit was exceeded. Wait for Retry-After and reduce the request rate or the number of concurrent requests."
  }
}

Retry-After is a positive integer number of seconds. Wait at least that long before retrying. The value 1 above is an example; always use the value received in the response.

Raims-Rate-Limited-ReasonWhat to adjust
global-rateReduce the company's total call rate in the environment.
endpoint-rateReduce calls to the same endpoint, including different IDs.
global-concurrencyReduce the company's total simultaneous calls in the environment.
endpoint-concurrencyWhen enabled for the company, reduce simultaneous calls to the same endpoint.
resource-specificFollow the resource's own interval identified by error.code.

Some endpoints have their own limits and waiting intervals in addition to the API's general limits. See each endpoint's reference for the applicable rules.

Make decisions using the status, error.code and the header reason. The text in error.message helps with diagnosis and must not be compared in your system's logic. General errors do not need error.details.

Wait before retrying

When you receive 429, preserve pending work and reschedule the attempt:

  1. Read Retry-After and the reason for the limit.
  2. Reduce the rate or concurrency according to the reason.
  3. Wait at least the received interval. After further refusals, increase the delay and add a small random variation, called jitter.
  4. Set a maximum number of attempts and an overall deadline. If either is reached, stop the current attempt and preserve the work for later handling.

One possible rule is to use the greater of Retry-After and an increasing delay, then add jitter. Never shorten the server's waiting interval to fit a local deadline: if it exceeds that deadline, defer the work instead of retrying early.

Do not restart all refused calls together when the waiting interval ends. Use a queue and maintain the outgoing rate during retries as well. Keep retry handling in one place so that different application layers do not repeat the same call simultaneously.

For calls that create or change data, or when a connection ends without a response, check the result before submitting again. Losing a response does not prove that the request was not processed. Do not recreate a charge to resolve uncertainty about the previous one.

Queued query example

This Node.js example retrieves a customer using GET. It keeps one call in progress per process, waits 100 ms between items and makes at most four attempts when it receives 429. Each attempt has a timeout of up to 30 seconds; an item's execution deadline is two minutes, starting when it leaves the queue. These values are example choices, not additional API limits.

Store the key in RAIMS_API_KEY on your integration's backend. Pass a customer ID from the same company and environment as the key. Do not run the code in a browser or write the key to logs.

JavaScript
const apiKey = process.env.RAIMS_API_KEY;
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
let queue = Promise.resolve();

function retrieveCustomer(id) {
  const task = queue.then(() => retrieveWithRetry(id));
  queue = task.catch(() => {}).then(() => sleep(100));
  return task;
}

async function retrieveWithRetry(id) {
  if (!apiKey) throw new Error('RAIMS_API_KEY is required.');
  const deadline = Date.now() + 120_000;

  for (let attempt = 0; attempt < 4; attempt += 1) {
    const remaining = deadline - Date.now();
    if (remaining <= 0) throw new Error('Request deadline exceeded.');

    const response = await fetch(
      `https://api.raims.com/v1/customers/${encodeURIComponent(id)}`,
      {
        method: 'GET',
        headers: {
          Authorization: `Bearer ${apiKey}`,
          Accept: 'application/json',
        },
        redirect: 'error',
        signal: AbortSignal.timeout(Math.min(30_000, remaining)),
      },
    );
    if (response.ok) return response.json();

    const retryAfter = response.headers.get('Retry-After');
    await response.body?.cancel();
    if (response.status !== 429) throw new Error(`HTTP ${response.status}`);

    const seconds = /^[1-9]\d*$/.test(retryAfter ?? '')
      ? Number(retryAfter)
      : NaN;
    if (attempt === 3 || !Number.isSafeInteger(seconds)) {
      throw new Error('Rate limit: stop and reschedule the request.');
    }

    const delay =
      Math.max(seconds * 1000, 500 * 2 ** attempt) +
      Math.floor(Math.random() * 250);
    if (delay >= deadline - Date.now()) {
      throw new Error('Retry-After exceeds the remaining request deadline.');
    }
    await sleep(delay);
  }
}

The function returns an error to its caller when the deadline expires, the header cannot be interpreted or another failure occurs. It does not automatically retry timeouts, connection errors or HTTP responses other than 429. Handle those results in your application and preserve work that needs to be rescheduled.

This queue is local. When running multiple instances, coordinate their combined usage and limit pending item counts and time spent in the queue. The example does not replace that shared control or provide a complete API client.

Avoid unnecessary calls

Use webhooks to receive supported changes instead of continuously querying the same resource. Validate the signature and handle redeliveries without repeating the effect. Query the resource when you need to retrieve its current state; do not depend on event order.

For lists, apply available filters, process each page and advance only while page.has_next is true. Copy page.next_after to after, keeping the filters. Do not restart the entire list on each attempt. See Listing and pagination.

Separate batch query tasks from calls needed for payment. Reserve capacity for interactive use and avoid repeating queries whose results your application can still use.

Diagnose and request a review

Measure the total and per-endpoint call rate, simultaneous calls, response duration and refusals by reason. Record the method, endpoint template, environment, time, HTTP status, error.code, reason for the limit, Retry-After and number of attempts. Use aggregate metrics.

Do not record API keys, authentication headers, bodies containing personal data or sensitive links. For diagnosis, using the /v1/charges/{id} template avoids recording each charge's identifier in the metric.

If refusals persist, check usage across all applications for the same company and environment. To discuss higher limits for your integration's needs, contact your account manager through the Raims Dashboard chat or email integracoes@raims.com. Include the endpoints, expected volume, bursts, concurrency, latency and busiest times. Do not send your key. The request will be reviewed; contacting us does not confirm an increase.