Rate limiting & probe blocking
FlowCP's public services enforce rate limits at two layers: tight, purpose-built limits on sensitive routes (login, 2FA, OAuth, embed chat, per-tool invocation), and a coarse edge guard that sits in front of every request as an outer ceiling and a defense against scanner traffic.
The edge guard
Both public services — the control-plane API and the MCP runtime — run a single hook before routing that does two things:
Blocks exploit-probe paths. Requests for paths the app never serves (
/wp-admin,/.env,/.git,/phpmyadmin,/actuator, anything ending in.php/.aspx/.cgi, …) get an immediate, silent404— no route handler runs. Each probe is also counted against a per-IP budget, so a scanner sweeping many paths quickly trips the rate limiter. Legitimate OAuth/OIDC discovery under/.well-known/is never treated as a probe.Applies a category-aware rate-limit backstop. Every other request is classified and held to a per-minute ceiling. These limits are deliberately generous — they sit on top of the stricter per-route limits and exist to stop floods and abuse, not to throttle normal use.
Backstop limits
Webhook
/webhooks/* (Stripe, Git)
120 per source IP
AI
Playground chat & tool calls, prompt/skill suggestions, description regeneration, embed chat, MCP runtime tool calls
30
Query
Read endpoints (GET)
300
Backstop
Everything else (mutations, anything unmatched)
600
Limits are scoped per workspace (or per embed) when the request path identifies a tenant, and otherwise per client IP. The real client IP is used even behind a TLS-terminating proxy or CDN.
Two paths are exempt from the backstop so health checks and client auto-discovery are never throttled:
GET /healthOAuth/OIDC discovery documents under
/.well-known/…
When you hit a limit
Exceeding a limit returns HTTP 429 with the error code RATE_LIMIT_EXCEEDED. Wait for the current minute window to roll over and retry. If you regularly hit the AI or query ceilings during legitimate use, contact support — these are abuse ceilings, not plan quotas (plan quotas are billed separately and surface as 402).
Last updated