Wraps Logo
DocsHome
Reference

API Rate Limits

Rate limits for the Wraps Platform API by plan. Includes response headers and error handling.

Limits by Plan

The Wraps Platform API enforces a per-minute rate limit based on your plan. Limits are applied per organization using DynamoDB-backed sliding windows. There is no daily request cap and no monthly send quota on any plan — sends are unlimited and billed by AWS directly. The per-minute limit exists to protect the API from bursts.

PlanPer Minute
Free50 requests
Pro2,000 requests
Business5,000 requests

Public Endpoints

Unauthenticated endpoints (health check, public tools) use IP-based rate limiting:

ScopeLimit
Per minute per IP10 requests
Per hour per IP100 requests

Event Ingestion

Custom events (sent via POST /v1/events and POST /v1/events/batch) are the one metered resource — they are Wraps' own storage, not AWS sending, which is never metered. Free ingestion continues through a 25% grace margin (6,250 events) before returning 429 with a Retry-After pointing at the 1st of the next month, when the counter resets. Sending is never affected.

PlanCustom events / month
Free5,000
ProUnlimited
BusinessUnlimited
HeaderReports
X-Event-LimitMonthly allowance, or -1 when unlimited
X-Event-CurrentEvents ingested this month
X-Event-RemainingEvents left, or -1 when unlimited
X-Event-PercentPercent of the allowance used, or 0 when unlimited

Response Headers

Every rate-limited response carries these headers. Read the unprefixed RateLimit-* names — the X- forms are the originals, kept so existing integrations keep working.

HeaderDescription
RateLimit-LimitRequests permitted in the window closest to exhaustion
RateLimit-RemainingRequests still available in that window
RateLimit-ResetSeconds until that window resets — not a Unix timestamp
RateLimit-PolicyEvery policy in force, as <limit>;w=<window seconds>
Retry-AfterSeconds to wait before retrying (429 responses only)
X-RateLimit-LimitLegacy alias for RateLimit-Limit
X-RateLimit-RemainingLegacy alias for RateLimit-Remaining
X-RateLimit-ResetLegacy alias for RateLimit-Reset

Successful response

response headers
HTTP/1.1 200 OKRateLimit-Limit: 500RateLimit-Remaining: 487RateLimit-Reset: 34RateLimit-Policy: 500;w=60X-RateLimit-Limit: 500X-RateLimit-Remaining: 487X-RateLimit-Reset: 34

Rate limited response (429)

429 response
HTTP/1.1 429 Too Many RequestsRetry-After: 34RateLimit-Limit: 500RateLimit-Remaining: 0RateLimit-Reset: 34RateLimit-Policy: 500;w=60X-RateLimit-Limit: 500X-RateLimit-Remaining: 0{  "error": "Rate limit exceeded: 500 requests per minute",  "code": "RATE_LIMITED",  "requestId": "01JBZ9K3M4N5P6Q7R8S9T0"}

Handling 429 Errors

When you receive a 429 status code:

  1. Read the Retry-After header for the number of seconds to wait
  2. Wait that duration before retrying
  3. Use exponential backoff if retries continue to fail
TypeScriptretry.ts
async function fetchWithRetry(url: string, options: RequestInit, maxRetries = 3) {  for (let attempt = 0; attempt < maxRetries; attempt++) {    const response = await fetch(url, options);    if (response.status === 429) {      const retryAfter = Number(response.headers.get('Retry-After') ?? 60);      await new Promise(r => setTimeout(r, retryAfter * 1000));      continue;    }    return response;  }  throw new Error('Rate limit exceeded after retries');}

Next Steps

Error Codes

Complete reference for CLI and SDK error codes.

View Error Codes
SDK Reference

Full API reference for the Email SDK.

View SDK Reference