36 - Rate Limiting Guide
Overview
OpenAlgo uses Flask-Limiter with a moving-window strategy to protect endpoints from abuse. Different rate limits apply to different endpoint categories based on their sensitivity and resource usage.
Two properties of the current setup matter before reading the numbers below. limiter.py passes no default_limits, so an endpoint without an explicit @limiter.limit(...) decorator is unlimited. And storage_uri is memory://, so counters live in the worker process; a multi-worker deployment enforces each limit once per worker rather than once per install. There are no limiter.exempt registrations anywhere in the codebase, and limiter.init_app(app) runs unconditionally in create_app().
Architecture Diagram
┌───────────────────────────────────────────────────────────────────────────────┐
│ Rate Limiting Architecture │
└───────────────────────────────────────────────────────────────────────────────┘
Incoming Request
│
▼
┌───────────────────────────────────────────────────────────────────────────────┐
│ Flask-Limiter │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ Configuration │ │
│ │ key_func = get_remote_address (Rate limit by IP) │ │
│ │ storage_uri = "memory://" (In-memory storage) │ │
│ │ strategy = "moving-window" (Sliding window algorithm) │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────────────────────┐
│ Endpoint Category Detection │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Login │ │ API │ │ Order │ │ Webhook │ │
│ │ Endpoints │ │ Endpoints │ │ Endpoints │ │ Endpoints │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 5/min │ │ 50/sec │ │ 10/sec │ │ 100/min │ │
│ │ 25/hour │ │ │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
└───────────────────────────────────────────────────────────────────────────────┘
│
┌─────────────┴─────────────┐
│ │
Under Limit Over Limit
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ Process │ │ 429 Error │
│ Request │ │ Too Many Reqs │
└───────────────┘ └───────────────┘Rate Limit Categories
Environment Variables
These are the eight keys .sample.env ships and utils/env_check.py validates:
RESET_RATE_LIMIT is read by blueprints/auth.py but is not in the rate_limit_vars list that utils/env_check.py validates, so a malformed value there is not caught at startup.
Limit Breakdown
Login
5/min, 25/hr
/auth/login, /<broker>/callback
Prevent brute force
Password reset
15/hr
/auth/reset-password
Prevent reset abuse
API
50/sec
/api/v1/quotes, /api/v1/positionbook, etc.
General data access
Order
10/sec
/api/v1/placeorder, /api/v1/modifyorder, /api/v1/cancelorder
Trading rate control
Smart Order
10/sec
/api/v1/placesmartorder
Automated order rate control
Webhook
100/min
/chartink/webhook, /strategy/webhook
External integrations
Strategy
200/min
Strategy CRUD views in blueprints/strategy.py and blueprints/chartink.py
Strategy execution
Code Defaults Differ From The Sample Values
The number that applies when a key is absent from .env is the second argument to os.getenv in the module, not the value in .sample.env. For API_RATE_LIMIT the two disagree:
50 per second
blueprints/admin.py, blueprints/orders.py, blueprints/sandbox.py, restx_api/margin.py
10 per second
the other 32 restx_api/*.py modules, including quotes.py, orderbook.py, holdings.py, funds.py, depth.py, history.py and cancel_all_order.py
Because .sample.env sets API_RATE_LIMIT="50 per second", a standard install gets 50/sec everywhere. Removing the key from .env silently drops most data endpoints to 10/sec. Keep the key present.
Additional Rate Limit Variables
These are read by code but are not part of the validated set. Several are absent from .sample.env altogether.
SIP_API_RATE_LIMIT
10 per minute
restx_api/sip.py backtest POST
PORTFOLIO_API_RATE_LIMIT
10 per minute
restx_api/portfolio.py backtest POST
PORTFOLIO_TEARSHEET_RATE_LIMIT
5 per minute
restx_api/portfolio.py tearsheet
GREEKS_RATE_LIMIT
30 per minute
restx_api/option_greeks.py
TELEGRAM_RATE_LIMIT
30 per minute
restx_api/telegram_bot.py
WHATSAPP_RATE_LIMIT
30 per minute
restx_api/whatsapp_bot.py
TELEGRAM_MESSAGE_RATE_LIMIT
10 per minute
blueprints/telegram.py
WHATSAPP_MESSAGE_RATE_LIMIT
10 per minute
blueprints/whatsapp.py
MCP_RATE_LIMIT_READ
60 per minute
blueprints/mcp_http.py per-token scope quota
MCP_RATE_LIMIT_WRITE
50 per minute
blueprints/mcp_http.py per-token scope quota
The MCP HTTP surface also carries two limits that are not environment-configurable: _DISPATCH_RATE_LIMIT = "120 per minute" on /mcp and _SSE_RATE_LIMIT = "5 per minute" on the SSE endpoint, both keyed by token rather than by remote address. None of these apply unless MCP_HTTP_ENABLED is True, since the blueprints are only registered in that case.
Implementation
Limiter Initialization
Location: limiter.py
Applying Rate Limits
Login Endpoint Example:
Order Endpoint Example:
API Endpoint Example:
Each module defines its own constant at import time. There is no shared constant, so the effective limit for a route is whatever that one module read from the environment when it was imported. Changing a rate limit therefore requires a restart, not just an .env edit.
Rate Limit Format
Flask-Limiter also accepts compound limits joined by semicolons, and utils/env_check.py validates that form:
Valid Timeunits
second
s
minute
m
hour
h
day
d
Examples
Error Handling
429 Response Handler
Location: app.py
Client-Side Handling
Endpoint Limits Map
REST API Endpoints
/api/v1/placeorder
ORDER_RATE_LIMIT
10/sec
/api/v1/modifyorder
ORDER_RATE_LIMIT
10/sec
/api/v1/cancelorder
ORDER_RATE_LIMIT
10/sec
/api/v1/cancelallorder
API_RATE_LIMIT
50/sec (10/sec if the key is unset)
/api/v1/placesmartorder
SMART_ORDER_RATE_LIMIT
10/sec
/api/v1/quotes
API_RATE_LIMIT
50/sec
/api/v1/multiquotes
API_RATE_LIMIT
50/sec
/api/v1/positionbook
API_RATE_LIMIT
50/sec
/api/v1/orderbook
API_RATE_LIMIT
50/sec
/api/v1/tradebook
API_RATE_LIMIT
50/sec
/api/v1/holdings
API_RATE_LIMIT
50/sec
/api/v1/funds
API_RATE_LIMIT
50/sec
/api/v1/history
API_RATE_LIMIT
50/sec
/api/v1/depth
API_RATE_LIMIT
50/sec
/api/v1/ping
API_RATE_LIMIT
50/sec
/api/v1/intervals
API_RATE_LIMIT
50/sec
/api/v1/optionsmultiorder
ORDER_RATE_LIMIT
10/sec
Authentication Endpoints
/auth/login
LOGIN_RATE_LIMIT_MIN + HOUR
5/min, 25/hr
/auth/reset-password
RESET_RATE_LIMIT
15/hr
/<broker>/callback
LOGIN_RATE_LIMIT_MIN + HOUR
5/min, 25/hr
blueprints/brlogin.py resolves its two constants through get_login_rate_limit_min() and get_login_rate_limit_hour() in utils/config.py, while blueprints/auth.py reads the same environment variables directly. The defaults match, so behaviour is identical, but the two paths are duplicated rather than sharing one source.
Webhook Endpoints
/chartink/webhook
WEBHOOK_RATE_LIMIT
100/min
/strategy/webhook
WEBHOOK_RATE_LIMIT
100/min
STRATEGY_RATE_LIMIT is applied to the strategy management views in blueprints/strategy.py and blueprints/chartink.py, not to the webhook receivers. The Flow webhook receivers /flow/webhook/<token> and /flow/webhook/<token>/<symbol> carry no @limiter.limit decorator at all; they are CSRF-exempt and unlimited, so front them with a reverse proxy limit if they are internet-facing.
Moving Window Strategy
Algorithm Benefits
Accuracy
Higher
Lower
Burst protection
Better
Prone to bursts at boundaries
Memory
Slightly higher
Lower
Implementation
More complex
Simpler
Configuration Validation
Location: utils/env_check.py
Validation is fail-fast: an unset or malformed value in that list calls sys.exit(1) before the Flask app is built. RESET_RATE_LIMIT and every variable in the additional table above are outside this check.
Tuning Recommendations
For High-Frequency Trading
For Webhook-Heavy Usage
For Multi-User Deployments
Consider using Redis for distributed rate limiting:
Key Files Reference
limiter.py
Flask-Limiter construction
app.py
limiter.init_app(app) and the 429 error handler
utils/env_check.py
Rate limit format validation at startup
utils/config.py
get_login_rate_limit_min(), get_login_rate_limit_hour()
restx_api/*.py
API endpoint rate limits
blueprints/auth.py
Login and password-reset rate limits
blueprints/brlogin.py
Broker callback rate limits
blueprints/chartink.py
Chartink webhook and strategy rate limits
blueprints/strategy.py
Strategy webhook and strategy rate limits
blueprints/mcp_http.py
Remote MCP dispatch, SSE and per-scope quotas
Last updated