Developer API errors
All Developer API errors return a JSON object with anerror code and a human-readable message:
Public auth errors (SDK)
The public auth endpoints (/auth/validate, /auth/heartbeat, and /auth/selfban) return errors as real HTTP status codes with a JSON body of the form {"status": "failed", "error": "<code>"}:
Successful responses return
200 with status: "success".
Public auth requests are protected by two layers of throttling:
- API Gateway stage throttling: burst
200, sustained100 req/s(default for every route on this API:/auth/validate,/auth/heartbeat, and/auth/selfban) - Application-level per-minute limits on
/auth/validateonly:30/minper IP5/minper license key
/auth/heartbeat is not IP rate-limited at the application layer. A flood of heartbeats only burns the victim’s credits, so a per-IP limit would add no security value and would interfere with legitimate high-frequency clients (e.g., 1 Hz server-side apps).
Additional application limits on /auth/selfban: 10/min per IP (all self-ban requests), and 3/min per license key for pre-session requests that send licenseKey + app credentials.
When a validate request exceeds either limit, the response is HTTP 429 with:
/auth/validate responses include the X-RateLimit-Remaining header (the lower of the remaining IP and per-license validate quotas). /auth/heartbeat success responses do not include this header: application-level rate buckets apply only where documented above. The official SDKs parse both the HTTP status code and the JSON error field, so 429 responses surface as rate_limited automatically; no special handling is needed in your integration.
Validate errors (/auth/validate)
Heartbeat errors (/auth/heartbeat)
rate_limited and replay_detected are never returned from /auth/heartbeat. Heartbeats are not IP rate-limited and do not enforce nonce replay detection; replay protection is provided by the signed, short-lived session token.Self-ban errors (/auth/selfban)
SDK client-side errors
In addition to server errors, the SDK may detect issues locally before or after a server response:
These errors trigger the
onFailure callback with the "login_failed" or "heartbeat_failed" reason.
Best practices for error handling
- Never expose internal error codes to end users. Map them to user-friendly messages.
- Log the actual error code for debugging, but show generic messages to users.
- Retry on transient errors (
no_creditsfrom your account, network errors) with exponential backoff. - Don’t retry on permanent errors (
invalid_key,revoked,hwid_mismatch); prompt the user to take action instead. - Handle
no_creditsgracefully: this is a billing issue on your end, not the user’s problem.