Skip to main content
The Raise API enforces rate limits in production, but the current OpenAPI spec does not document specific thresholds, response codes, or headers for rate-limited requests. This page covers what’s known from the spec, what to assume in practice, and the defensive patterns to use until the spec is updated with explicit rate-limit documentation.
The Raise OpenAPI spec does not currently document rate limits. There is no spec-confirmed threshold, no documented 429 Too Many Requests response, and no documented Retry-After header. Partner integrations should still code defensively for rate limiting — treat 429 and other throttling responses as occurring even though the spec is silent on them.Future updates to the spec are expected to document the canonical rate-limit behavior. Until then, the defensive patterns on this page are the recommended approach.

What the spec confirms

Looking only at what’s in the Raise OpenAPI spec:
  • Every endpoint has documented 200 OK (or 204 No Content) success responses.
  • Most endpoints have documented 400 Bad Request and 404 Not Found responses.
  • No endpoint documents a 429 Too Many Requests response.
  • No endpoint documents rate-limit headers (X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After, etc.).
This is a documentation gap, not a runtime gap — production traffic against Raise does encounter throttling under sustained load. The spec just doesn’t formalize the contract for it.

What to assume in practice

In the absence of spec-grounded numbers, three conservative assumptions are safe:
AssumptionRationale
429 responses occur on sustained high-volume usageEvery production API enforces some form of throttling. Raise is no exception.
The response body follows the ProblemDetails envelopeAll other documented Raise errors do (see Error Handling). It would be unusual for 429 to deviate.
Retry-After is typically included on 429 responsesThis is the HTTP-standard header for rate-limit responses and follows from RFC 6585. Most modern APIs include it.
Don’t hardcode specific thresholds, intervals, or assumptions about per-customer vs. per-token scope until the spec is published. Code defensively for whatever the live behavior is.

The defensive pattern

The general defensive pattern for an unknown-threshold API: throttle conservatively, retry on 429 with Retry-After-aware backoff, and surface sustained throttling as an operational signal rather than absorbing it silently.

Throttle conservatively at the client

Without a known threshold, the right default is to keep request rates well below what any modern API would enforce. A token bucket sized for ~1 request per second per customer organization gives plenty of headroom for most workloads:
JavaScript
class TokenBucket {
  constructor(capacityTokens, refillRatePerSecond) {
    this.capacity = capacityTokens;
    this.tokens = capacityTokens;
    this.refillRate = refillRatePerSecond;
    this.lastRefill = Date.now();
  }

  async acquire() {
    while (true) {
      const now = Date.now();
      const elapsed = (now - this.lastRefill) / 1000;
      this.tokens = Math.min(this.capacity, this.tokens + elapsed * this.refillRate);
      this.lastRefill = now;

      if (this.tokens >= 1) {
        this.tokens -= 1;
        return;
      }

      const waitMs = ((1 - this.tokens) / this.refillRate) * 1000;
      await new Promise((resolve) => setTimeout(resolve, waitMs));
    }
  }
}

// One bucket per customer. Conservative defaults — adjust upward only after
// confirming the live rate limit allows it.
const bucket = new TokenBucket(10, 1.0); // 10 burst, 1 req/sec sustained

async function rateLimitedRaiseCall(...args) {
  await bucket.acquire();
  return fetch(...args);
}
These numbers are intentionally conservative. They’re meant as a starting point that won’t trigger throttling under any reasonable threshold. Adjust upward only after measuring actual production behavior and confirming higher rates don’t produce 429 responses.

Handle 429 with Retry-After-aware backoff

When 429 happens, the response should include a Retry-After header indicating how many seconds to wait before retrying:
JavaScript
async function callRaiseWithRetry(url, options, maxAttempts = 5) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const response = await fetch(url, options);

    if (response.status !== 429) {
      return response;
    }

    // Rate limited. Honor Retry-After if present; otherwise exponential backoff.
    const retryAfterHeader = response.headers.get('Retry-After');
    const retryAfterSeconds = retryAfterHeader
      ? parseInt(retryAfterHeader, 10)
      : Math.pow(2, attempt);

    console.warn(`Rate limited (attempt ${attempt}); waiting ${retryAfterSeconds}s`);
    await new Promise((resolve) => setTimeout(resolve, retryAfterSeconds * 1000));
  }

  throw new Error(`Rate limited after ${maxAttempts} retry attempts`);
}
Two patterns this gets right:
  • Honor Retry-After when present. The server’s value is more accurate than any client-side guess. If the header is missing (which can happen — the spec doesn’t document its presence), fall back to exponential backoff.
  • Bound the retries. Don’t retry forever. If the rate limit doesn’t recover after a few attempts, surface the failure for operational attention rather than burying it in retry noise.

Stop hammering on persistent 429s

A run of 429 responses that doesn’t recover after the documented retry budget is a signal — not a transient blip. Treat it as a circuit-breaker event: pause traffic for the customer, alert ops, and resume only after the cause is identified. See Error Recovery Patterns: Circuit breakers for the full pattern.

When the spec is updated

The Raise OpenAPI spec is expected to be updated to document rate-limit behavior explicitly — including the documented 429 response shape, the Retry-After header guarantee, and the per-credential or per-organization scope of the limit. When that happens, this page will be revised with the spec-confirmed details and the code patterns above will be tuned to match. Until then, the conservative defaults are the safe choice — they won’t break under any plausible rate-limit configuration, and they don’t impose meaningful latency for typical integration workloads.

Patterns that reduce rate-limit pressure

Independent of the specific threshold, four patterns reduce the rate at which an integration consumes API budget:

Use the largest Take value the endpoint supports

Each request to a /list or /query endpoint consumes one rate-limit slot regardless of how many records it returns. A Take=1000 request returns 1,000 records for the cost of one request; a Take=25 request returns 25 records for the same cost. For bulk reads, use the maximum. See Pagination and Filtering.

Cache reference data

Endpoints that return reference data — GET /api/CustomField/List, GET /api/Premium/list, GET /api/Project/list, GET /api/Campaign/list — change rarely. Cache the results at integration startup and refresh on a slow cadence (daily is fine for most reference data).

Prefer webhooks over polling

For change detection on Donors, Gifts, and RecurringGifts, subscribe to webhook events instead of polling /api/Donor/list?SortBy=modifieddatetimeutc repeatedly. Webhooks deliver changes within seconds and don’t consume the API rate-limit budget for change detection. See Webhooks Overview.

Batch where the API supports it

The Raise API exposes a few patterns that reduce request count for related operations:
  • The replace endpoints (PUT /api/Campaign/replace, PUT /api/Project/replace, PUT /api/Segment/replace) handle replacement operations in a single call.
  • The Query endpoints return more results per call than the equivalent looped reads would.
There is no general bulk-write endpoint for Gifts or Donors. Bulk operations on those resources are loops at the integration level, with throttling applied per request.

Where to go next

Pagination and Filtering

Use the largest Take and the right query pattern to minimize request count.

Error Recovery Patterns

Retry strategies, circuit breakers, and dead-letter handling.

API Performance Tips

Caching, batching, and other patterns that reduce rate-limit pressure.

Error Handling

The ProblemDetails envelope that 429 responses are expected to use.
Last modified on May 21, 2026