Platform
API and login rate limits
Machine API traffic uses node-local Hammer counters. Password login uses a separate PostgreSQL-backed throttle shared by every application node.
On this page
01 Default limits
details1000 requests per 60 seconds
API_RATE_LIMIT controls the default ceiling (1000). Authenticated machine requests are keyed by credential ID; unauthenticated bootstrap requests are keyed by client IP. The 60-second period is fixed in runtime configuration. ETS counters are local to each application node.
02 Password login protection
details10 failures per identity and IP
Ten failed passwords for the same normalized email and client IP within 15 minutes start a 30-minute cooldown. The tenth failure returns HTTP 429 with retry-after; a successful login clears this identity/IP bucket.
50 unreturned attempts per client IP
A broader 15-minute IP ceiling limits email rotation and Argon2 CPU abuse. Every submission reserves one slot and a verified login returns its own slot, so the budget is spent by failures and shared NAT egress traffic is not punished for succeeding. IPv6 clients are counted per /64 prefix. Login counters are durable in PostgreSQL and shared across application nodes.
03 Trusted client IPs
detailsForwarded headers are fail-closed
The app reads x-forwarded-for only when the direct peer is listed in TRUSTED_PROXY_IPS. Forwarded headers from every other peer are ignored; keep the application origin firewalled from direct traffic.
04 Response headers
detailsx-ratelimit-remaining
Requests remaining in the current window. Present on successful machine /api/v1 responses that pass through the API rate-limit plug. Operator, SCIM, /health, /metrics, and /webhooks do not run that plug and do not send these headers.
x-ratelimit-reset
ISO 8601 timestamp indicating when the current rate limit window resets.
05 When rate limited (HTTP 429)
exampleResponse format
API limits return retry-after plus the shared RFC 9457 problem body. Password-login limits return retry-after with a minimal plain-text 429 response so browsers and automated clients preserve the real status instead of following a redirect loop.
HTTP/1.1 429 Too Many Requests
retry-after: 42
content-type: application/json
{
"type": "https://robotscenter.net/problems/rate-limited",
"title": "Rate limited",
"status": 429,
"detail": "Rate limit exceeded. Please retry later.",
"request_id": "req-abc123",
"extra": { "retry_after_seconds": 42 }
}
06 How the machine API is keyed
detailsCredential, user, engagement, partner, or IP
Authenticated machine requests are keyed by credential ID. Browser-authenticated API calls use the user. Partner routes key partner:{id}. Engagement ingest keys engagement:{id}. Everything else falls back to client IP.
Surfaces without this Hammer bucket
The operator session API, SCIM /scim/v2, GET /health, GET /metrics, and POST /webhooks/nowpayments do not run the machine API rate-limit plug.
07 Failed-auth throttle on partner planes
details30 HTTP 401/403s per client address per 60 seconds
Partner and engagement routes also run AuthFailureThrottle. After 30 failed authentications from one client address in 60 seconds the next attempt is HTTP 429 with detail "Too many failed authentication attempts. Please retry later." Only 401 and 403 count.
08 Configuration
detailsEnvironment variables
Set API_RATE_LIMIT to change the per-node machine API ceiling. Set TRUSTED_PROXY_IPS to the comma-separated direct reverse-proxy addresses allowed to supply x-forwarded-for. Login thresholds are fixed production safety limits.
Related docs
see also