Skip to content

Rate limits

z4j applies token-bucket rate limits to public auth paths and to admin paths whose write fan-out can be expensive. Authenticated read paths are not capped.

All values are the in-code defaults defined in z4j_brain.domain.ip_rate_limit. The window is 60 seconds.

EndpointCap (per IP)
POST /api/v1/auth/login20 / min
POST /api/v1/auth/password-reset/request and /confirm10 / min (shared bucket)
GET /api/v1/invitations/preview and POST /api/v1/invitations/accept30 / min (shared bucket)
Bulk-write admin actions (bulk-delete tasks, bulk-retry, purge-queue, schedule trigger / import / resync)10 / min (shared bucket)
Notification-channel /channels/test preflight20 / min
Agent WebSocket connectsdedicated bucket on the /ws endpoint

Exceeding any limit returns 429 Too Many Requests.

In addition to the per-IP login bucket, the brain tracks failed logins per account:

SettingDefaultMeaning
Z4J_LOGIN_LOCKOUT_THRESHOLD10Failed attempts before lockout.
Z4J_LOGIN_LOCKOUT_DURATION_SECONDS900 (15 min)How long the lockout lasts.
Z4J_LOGIN_BACKOFF_BASE_SECONDS0.5Per-failure incremental backoff applied to the response.
Z4J_LOGIN_BACKOFF_MAX_SECONDS5.0Cap on that backoff.
Z4J_LOGIN_MIN_DURATION_MS(settings)Minimum response time held server-side so timing is not exploitable.

The lockout is per-account, so an attacker rotating IPs to evade the per-IP cap still hits the account-level wall.

The brain does not emit X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset today. Detect throttling via the 429 status alone.

Tunables for login lockout and account backoff live in Settings (see above and the env-vars reference). The per-IP bucket sizes are in-code defaults; changing them requires a code change.

/health and /metrics are not rate-limited; scraping is expected.