Web Rabbit MediaDocs
Get Started

Rate limits

Per-key and per-IP limits enforced at the Cloudflare edge.

The API enforces per-key rate limits at the Cloudflare edge using the native Rate Limiting binding — limits are strongly consistent per data center, so bursts cannot slip through eventual-consistency windows. Payments and Messaging share one contract.

Limits

Limits are per API key, counted in a 10-second window, and apply identically to Payments and Messaging. Every plan has a burst allowance: short spikes above the sustained rate are absorbed, and only sustained traffic above the burst ceiling is rejected.

FieldTypeDescription
Standard (default)120 req / 10 s · burst 240Every key starts here. 720 sustained requests a minute.
Scale600 req / 10 s · burst 1,200For platforms with evening peaks — ride-hailing, delivery, ticketing. Granted on request, no charge.
Enterprise2,000 req / 10 s · burst 4,000Negotiated. Contact us with your peak RPS.
Status & balance readsseparate budgetTransaction status, campaign delivery reports and balance reads draw on their own pool, so polling never starves your sends.
Unauthenticated (per IP)20 req / 10 sProtects the 401 path from brute-force key guessing. Also covers GET /v1/health.
›Moving up a tier
Email support@webrabbitmedia.com with your business id and expected peak requests per second. Scale is normally granted the same day and applied to your keys without a redeploy — nothing in your code changes.

Headers on every response

FieldTypeDescription
x-ratelimit-limitintegerSustained budget for this window.
x-ratelimit-remainingintegerRequests left in the current window.
x-ratelimit-resetunix secondsWhen the window rolls over.
x-ratelimit-tierstringstandard, scale or enterprise.
retry-aftersecondsOn 429 only.
x-request-iduuidOn every response, including errors. Quote it in support requests.

Prefer webhooks over polling

Signed HMAC-SHA256 webhooks are live and are the intended way to learn a transaction's outcome — they remove most polling traffic entirely. Keep a slow reconciliation poll as a safety net, not as your primary path.

429 response

HTTP/2 429 Too Many Requests
HTTP/2 429
content-type: application/json
retry-after: 10
x-ratelimit-limit: 120
x-ratelimit-remaining: 0
x-ratelimit-reset: 1789000010
x-ratelimit-tier: standard
x-request-id: 6f3c7d1e-9a2b-4c8f-b5e0-2b1a7e9d0c33

{
  "error": "Rate limit exceeded",
  "request_id": "6f3c7d1e-9a2b-4c8f-b5e0-2b1a7e9d0c33"
}

Handling

  • Respect the Retry-After header (seconds).
  • Use exponential backoff with jitter on repeated 429s.
  • Pair retries with an Idempotency-Key to keep them safe — see Idempotency.
shell
# retry once, honouring Retry-After
resp=$(curl -s -D /tmp/h -o /tmp/b -w "%{http_code}" \
  https://api.webrabbitmedia.com/v1/transactions \
  -H "Authorization: Bearer wr_live_...")

if [ "$resp" = "429" ]; then
  wait=$(grep -i '^retry-after:' /tmp/h | tr -dc '0-9')
  sleep "${wait:-10}"
  curl -s https://api.webrabbitmedia.com/v1/transactions \
    -H "Authorization: Bearer wr_live_..."
fi