Browse the docs

Rate Limits

Request rate limits and 429 handling.

Requests to the API are limited to 100 requests per 60-second window, per endpoint, per calling IP address. The same limit applies in Sandbox and production.

What that means in practice:

  • Per endpoint. Each method and path (for example GET /v2/api-gateway/cards and POST /v2/api-gateway/cards) has its own budget. Exhausting one endpoint's budget does not affect calls to another.
  • Per calling IP address. The budget is counted for the address your requests arrive from, not for your API key. Several servers calling from different addresses each get their own budget; several API keys used from one address share one.
  • Every request counts, including requests that fail validation or authentication and calls to the endpoints that do not need an API key.
  • The headers are authoritative. Read X-RateLimit-Remaining and the Retry-After on a 429 rather than counting requests against the figure yourself; the headers describe the window that is actually in force for your traffic.

Response headers

Every response that was allowed through carries the current state of the window for that endpoint:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 60
  • X-RateLimit-Limit — requests allowed per window.
  • X-RateLimit-Remaining — requests left in the current window.
  • X-RateLimit-Reset — seconds until the window resets.

When you exceed the limit

The API responds with 429 Too Many Requests, a Retry-After header (seconds to wait) and the standard error body. The X-RateLimit-* headers are not sent on the 429 itself.

GET https://api.themooncard.com/v1/api-gateway/moon-reserve
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json; charset=utf-8

{"message":"ThrottlerException: Too Many Requests","code":"HTTP_EXCEPTION"}

The code on this response is the generic HTTP_EXCEPTION, so detect rate limiting from the 429 status, not from code. Wait for the number of seconds in Retry-After before sending the next request to that endpoint. Other endpoints remain available. See Errors for the error body format.

Other limits that return 429 or 400

These are attempt limits on specific flows, independent of the per-endpoint window:

FlowLimitResponse
Cardholder login (POST /v2/api-gateway/cardholders/auth/login, step 2)5 wrong codes for the current login code429 { "message": "Too many attempts. Please try again later.", "code": "TOO_MANY_ATTEMPTS" }. No Retry-After. Request a new code (step 1) to reset the count.
Card activation with a one-time code (POST /v1/public/2fa/card/activate)3 attempts per session400 { "message": "Maximum attempts exceeded", "code": "MAX_ATTEMPTS_EXCEEDED" } on the fourth attempt; the session is discarded. Start a new session and request a new code.

Recommendations

  • Implement exponential backoff with jitter on 429 responses, and honour Retry-After as the minimum wait.
  • Prefer webhooks over polling for transaction and balance updates — see Webhooks.
  • Batch or space out bulk operations (for example issuing many cards) so that no single endpoint receives more than 100 requests per minute from one address; watch X-RateLimit-Remaining and slow down before it reaches zero.

Last updated August 17, 2026