Starship Rewards API

Rate Limits

Every rate limit the Starship API enforces — the rules, what each is keyed on, and how to read the headers

Rate Limits

This page is the single source of truth for Starship's rate limits. Every limit listed here is enforced by the gateway; no other limits exist.

How rules are matched

Rules are evaluated in the order listed below, matching the request path by prefix. The first matching rule wins — a request to POST /api/v1/orders is governed by the orders rule and never also by the general rule.

Each rule is counted against a key, which determines whose budget the request spends:

KeyMeaning
API keyYour X-API-Key. All requests using the same key share one budget, regardless of source IP.
ClientYour account. Shared across every credential you hold.
IPThe source IP of the request.

Client API (/api/v1/*)

RuleApplies toLimitWindowKeyed on
Order creationPOST /api/v1/orders100 requests1 minuteAPI key
Product imagesGET /api/v1/products/images
GET /api/v1/products/{id}/image
100 requests1 minuteClient
GeneralEvery other /api/v1/* endpoint1,000 requests1 hourAPI key

The general rule is the one that will bite you. Product listing, product details, charges, order lookups, wallet reads, transaction history, payouts, beneficiaries and webhook management all draw on the same 1,000-per-hour budget. There is no separate per-endpoint allowance for any of them, and there is no burst allowance layered on top.

Designing around the general limit

The general limit rewards bulk reads over chatty ones:

  • Import the catalog in pages, not per product. GET /api/v1/products accepts limit up to 10,000 and returns each product's denominations and your resolved discount in the same payload. A full catalog import costs a handful of requests, not one per product.
  • Do not call the Charges API per product at import time. It is a quote endpoint, not a prerequisite for ordering — see Pricing and Charges. POST /api/v1/orders re-prices server-side at creation and debits the authoritative amount.
  • Back off when polling order status. 10 seconds is the floor, 60 seconds is preferred for DELAYED orders. See Delivery Semantics.
  • Cache reference data. Countries, currencies and categories change rarely and are served with a 24-hour cache header.

Authentication endpoints

These are keyed on IP, not on your API key, and several apply a block period after the limit is hit — during a block, every request from that IP is rejected until the block expires.

RuleApplies toLimitWindowBlock after breach
LoginPOST /auth/login5 requests1 minute15 minutes
Token refreshPOST /auth/refresh20 requests1 minute

Automated test suites trip the login limit constantly. Five failed or successful logins from one IP inside a minute earns that IP a 15-minute block. Authenticate once and reuse the token across your suite rather than logging in per test case.

Additional limits apply to portal-only flows (password reset, 2FA enrolment, credential management). They are keyed on the signed-in user and are not reachable from the client API.

Reading the headers

Every response carries your current standing against the matched rule:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1640995200
HeaderMeaning
X-RateLimit-LimitThe matched rule's ceiling
X-RateLimit-RemainingRequests left in the current window
X-RateLimit-ResetUnix timestamp when the window resets

When you are throttled

A breached limit returns 429 Too Many Requests:

HTTP/1.1 429 Too Many Requests
Retry-After: 1800
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
Content-Type: application/json
{
  "error": "rate_limit_exceeded",
  "message": "Rate limit exceeded. Please retry after 30 minutes or contact support to increase your limit.",
  "retry_after": 1800
}

Branch on the error field, which is the literal string rate_limit_exceeded. The message text is human-readable, varies by rule, and rounds to whole minutes — do not parse it. Use retry_after, which mirrors the Retry-After header and is expressed in seconds.

Honour Retry-After. It is expressed in seconds and tells you exactly when the window reopens; retrying sooner spends nothing but your own capacity. Wrap retries in exponential backoff with jitter so a fleet of workers doesn't resynchronise onto the same reset boundary.

Need a higher limit?

If your traffic profile genuinely needs more headroom, contact your Starship representative with your expected request volume, its shape (steady versus bursty), and which endpoints dominate it. Limits are configured per account and can be reviewed.