Rate limits and quotas
The throttles that keep one heavy user from starving the rest of the org and cap your overall spend.
Strata enforces two kinds of limit. Per-user limits are a rolling 1-hour ceiling resolved per person through a cascade (user override → role → org → env fallback). An org pool is a single shared monthly token bucket the whole organization draws from, with an optional per-user soft cap. You pick one plan for the org; both are configured under Organization settings, along with the separate agent quotas (agents-per-user, agent-runs-per-day, minimum interval, and per-run/per-month cost ceilings). All of this requires canManageOrgSettings to change.
One enforcement engine sits behind every paid surface — web chat, the Teams bot, scheduled and webhook agent runs, voice mode, and the REST API — so no surface can bypass the cap.
Two plans: per-user limits vs. org pool
Under Organization settings → Defaults → Quotas & rate limits → Rate-limit plan, choose how the org is throttled:
- Per-user limits (default) — every person gets their own rolling 1-hour ceiling. The number and unit come from the cascade below. Best when you want predictable per-person fairness.
- Org pool (shared bucket) — the whole org shares one monthly token pool. Anyone can draw from it until it runs dry, with an optional per-user soft cap so no single person drains it. Best when you'd rather manage one number for the whole org than tune per-person limits.
The rest of this page covers per-user limits first, then the org pool.
Per-user limits: two units (chats vs. tokens)
Every rate limit is per hour in a sliding window, and uses one of two units:
chats— count of chat messages sent in the last 60 minutes. Tracked in an in-memory sliding window per user, evicted after an hour of inactivity. Fast and easy to reason about — "100 chats per hour" means at most 100 chats per hour.tokens— sum oftotal_tokensfromactivity_logover the last 60 minutes. Tracked against the database, captures real cost more precisely. A heavy single chat (1M tokens of context) counts as more than a quick "hi."
A chats-mode default of 60 chats/hour is what every org gets out of the box (the CHAT_RATE_LIMIT_PER_HOUR env fallback). Switch to tokens mode when you want to bill heavy power users without artificially capping conversation volume.
The cascade
In the per-user plan, the effective rate limit for any one user is resolved by getEffectiveRateLimit(userId):
limit cascades user → role → org → env
unit cascades role → org → 'chats'
In plain English:
- If the user has
user_settings.rate_limit_overrideset to a positive number, that is the limit. The unit still comes from the user's role (or the org if the role does not specify, orchatsif neither does). - Else if their role has
default_rate_limitset, that is the limit and the role'sdefault_rate_limit_unitis the unit. - Else if the org has
default_rate_limitset, that is the limit and the org'sdefault_rate_limit_unitis the unit. - Else the env fallback (
CHAT_RATE_LIMIT_PER_HOUR, default 60) inchatsmode.
The unit cascade is deliberately role → org → chats (not user → role → org) — a per-user override changes the number, not the unit, because flipping one user from chats to tokens while the rest of the role uses chats produces confusing billing semantics. Pick the unit once at the org or role level.
Setting an organization default
Organization settings → Defaults → Quotas & rate limits. With the Rate-limit plan set to Per-user limits, the Default rate limit (per 1 hour) control appears.
Two controls:
- Number input — leave blank to inherit the env fallback (60 chats/hour). Any positive number sets the org default.
- Unit toggle to the right of the number — flips between
chatsandtokens. Switching units recalculates the displayed number usingAVG_TOKENS_PER_CHAT = 5000so a60 chatsvalue becomes300,000 tokensand vice versa. Empty stays empty.
Organization settings auto-save — there is no Save button. Each change writes silently to the server (a short debounce coalesces rapid edits). The change takes effect on the next chat request from any user whose role does not override it — and applies the same way across Teams, agents, and voice.
Setting a role default
Roles → click a custom role → Defaults for new users in this role → Rate limit (per hour).
Same number + unit toggle. The role's unit is what users in that role get unless they have their own override.
Setting a per-user override
Users → click Manage → Profile & Access tab → rate limit input.
The number is the user's rate_limit_override. Leave blank to clear and fall back to the role/org default. The unit shown is the user's effective unit — driven by their role and org, not by this input.
The audit log records the change as user.rate_limit_changed with the new value.
NoteA per-user override only applies under the per-user plan. When the org runs on the org pool, the per-user soft cap governs each person instead.
Switching to an org pool
Organization settings → Defaults → Quotas & rate limits → Rate-limit plan → Org pool (shared bucket). Three controls appear:
- Monthly token pool — total tokens the entire org can consume each month. Leave blank to disable the pool and fall back to per-user limits.
- Per-user soft cap — the maximum share of the pool any single user can consume in a reset cycle, as a percentage (1–100). For example,
30means no one user can use more than 30% of the monthly pool. Blank disables the per-user cap so anyone can draw the whole pool. - Pool reset day — the day of the month (1–28) the pool resets to zero at 00:00 UTC.
These controls auto-save as you edit them — there is no Save button.
In pool mode the cascade and the chats/tokens unit no longer apply — usage is always measured in tokens against the shared bucket. Two ceilings are enforced:
- Org-wide — once total usage since the last reset reaches the monthly pool, every user is blocked until the next reset day.
- Per-user soft cap (if set) — once a user reaches their share of the pool, they're blocked but others keep their headroom.
WarningThe org pool resets monthly, not hourly. A user who hits the org-wide ceiling can't send again until the pool reset day, which may be weeks away — size the pool generously.
What the user sees at the limit
When a chat request would exceed the policy, the server returns HTTP 429 with:
- A
Retry-Afterheader — seconds until the oldest item in the window ages out (chats mode), or 3600 for tokens mode. - A JSON body:
{
"error": "Rate limit exceeded. You've sent 60 messages in the last hour. Try again in 12 minute(s).",
"retryAfter": 720,
"unit": "chats",
"used": 60,
"limit": 60
}
For tokens mode:
{
"error": "Rate limit exceeded. You've used 305,210 of 300,000 tokens allowed per hour. Try again shortly.",
"retryAfter": 3600,
"unit": "tokens",
"used": 305210,
"limit": 300000
}
For the org pool, the unit field tells the user which ceiling they hit — org_pool for the org-wide bucket or pool_user_cap for their personal soft cap:
{
"error": "You've reached your 30% share of your organization's monthly token pool (15,000,000 of 15,000,000). Others still have headroom — contact your admin if you need more.",
"retryAfter": 3600,
"unit": "pool_user_cap",
"used": 15000000,
"limit": 15000000
}
The Chat UI renders this as an inline rate-limit card explaining what was hit and when the limit resets. The Settings page also exposes a /api/chat/usage endpoint that drives a live usage bar so users can see their consumption against the same policy without having to hit the cap. Under the org pool, that card switches to reflect the user's share of the shared monthly pool.
Per-user analytics
Every time a user is blocked, Strata writes a row to rate_limit_hits (debounced to one row per user per 5 minutes — retry spam does not bloat the table). The Usage page surfaces these:
- "People are at their hourly limit" (or "Person is at their hourly limit" for exactly one) — appears in the Usage summary only while someone is actually limited, and is absent otherwise rather than showing zero. Counts users whose
at_limitflag is set in the current poll. - Users in red in the All users table — anyone currently at their hourly limit.
- Per-user counts in the billing profile drill-down.
These are useful for spotting:
- One user systematically hitting the cap (probably needs an override).
- A role default that is too tight for the team's real workload.
- A pattern of bursts that should trigger a unit switch from chats to tokens.
Agent quotas (separate from rate limits)
Six org-wide quotas govern scheduled agents, configured under Organization settings → Defaults → Quotas & rate limits:
- Max agents per user — cap on how many scheduled agents one user can deploy. Blank = unlimited.
- Max agent runs per day (per user) — daily ceiling on aggregate scheduled agent runs across all of one user's agents. Blocks runs once hit; resets at UTC midnight. Blank = unlimited.
- Minimum interval between runs (seconds) — reject schedules more frequent than this. e.g.
300= "no more than every 5 minutes." Blank = no floor. - Max tokens per agent run — hard ceiling on total tokens a single run may consume. The run stops mid-execution once it's reached — the key guard when you allow short (every-few-minutes) schedules. Recommended 60,000–150,000. Blank = no limit.
- Max spend per agent run — dollar ceiling for one run, in cents (100 = $1.00). The run aborts once its estimated spend crosses this. Recommended 50–200¢. Blank = no cap.
- Monthly spend cap per agent — total each agent may spend per calendar month, in cents. Once reached, that agent's runs are skipped until the month resets. Blank = no cap.
The org-wide kill-switch lives on a separate lock: Organization settings → Locks → Agents. When ON, no one in the org can create or edit agents — already-deployed agents stay paused-but-visible. Per-role canCreateAgents permission still applies on top.
Organization spend ceiling
The agent quotas above cap spend one run or one agent at a time. The org also carries a single monthly AI spend ceiling — an absolute dollar cap on the whole organization's AI usage. Unlike the per-agent quotas, this ceiling lives under Billing and is gated on canManageBilling, not canManageOrgSettings.
When month-to-date spend crosses the ceiling, Strata pauses AI on every surface — web chat, the Teams bot, scheduled and webhook agents, voice, and the REST API — cutting a response mid-stream if a single turn is what tips it over. An admin inbox notice fires once for the period, and the ceiling auto-resumes at the start of the next month. Leave it blank for no cap. The full setup lives in Billing.
What can go wrong
| Error | What it means |
|---|---|
| User reports they cannot send messages | Check their effective policy with the Users Manage modal. If the displayed limit is much lower than expected, the cascade is resolving to a different level than you think. |
Rate limit exceeded on the first message of the day | The window is a rolling 60 minutes, not a calendar day — yesterday's late-night burst can still count. (Per-user plan only.) |
| Bumping a user's override has no effect | Save was successful but the user has cached the rate-limit policy. They will see the new value on their next chat. Or the org runs on the org pool, where per-user overrides don't apply. |
| Everyone in the org is suddenly blocked | The org pool has hit its monthly ceiling. Nobody can send until the pool reset day. Raise the pool or wait for the reset. |
| KPI "Users at hourly limit right now" never appears | Nobody in your org is currently blocked. This is normal. |
| Agent fails to deploy with "schedule too frequent" | Reduce the schedule to at or above your Minimum interval between runs. |
User cannot create an agent despite canCreateAgents = true | The org's Agents lock is on, or the user's per-user agent governance has the lock-creation toggle set. Check both. |
See Roles and permissions for the default_rate_limit field on roles, Usage for the analytics, and Per-user agent governance for the per-user agent controls.