Strata PlatformDocs

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 member limits are a rolling 1-hour ceiling resolved per person through a cascade (user override → role → org → env fallback). A shared pool is a single monthly token bucket the whole organization draws from, with an optional cap on each member's share. You pick one plan for the org; both are configured under Organization, 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 → Member defaults → Rate limits → Plan, choose how the org is throttled:

  • Per member (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.
  • Shared pool — the whole org shares one monthly token pool. Anyone can draw from it until it runs dry, with an optional Per-member share of the pool 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 of total_tokens from activity_log over 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-member plan, the effective rate limit for any one user is resolved by getEffectiveRateLimit(userId):

limit  cascades user → role → org → env
unit   comes from the level that set the number (env counts chats)

In plain English:

  1. If the user has user_settings.rate_limit_override set to a positive number, that is the limit — unless the padlock on Limit per member, per hour is closed under Organization › Member defaults, which ignores every per-user override. The override keeps the unit of the level it overrides: the role's when the role sets a number, otherwise the org's.
  2. Else if their role has default_rate_limit set, that is the limit, counted in the role's default_rate_limit_unit (or the org's unit if the role stores none).
  3. Else if the org has default_rate_limit set, that is the limit and the org's default_rate_limit_unit is the unit.
  4. Else the env fallback (CHAT_RATE_LIMIT_PER_HOUR, default 60), counted in chats whatever unit a role or the org has saved.

The unit travels with the number that set it. A per-user override changes the number, never the unit, because flipping one user from chats to tokens while the rest of the role uses chats produces confusing billing semantics. A role's unit counts only when the role sets a number, so pick the unit where you set the number: on the role, or at the org level.

Setting an organization default

Organization → Member defaults → Rate limits → Limit per member, per hour. The row is active while Plan is set to Per member. Under Shared pool it is dimmed once a pool is set, but stays editable; with no pool set it is not dimmed, because it is then the limit in force.

Two controls:

  • Number input — 1 to 10,000,000. Leave blank to inherit the env fallback; the row states it (Blank uses this deployment's default of 60 chats an hour.). A value out of range or not a whole number is held on the row and not saved.
  • Unit dropdown beside the number — chats or tokens. Switching units recalculates the number from the value you last typed, using AVG_TOKENS_PER_CHAT = 5000, so a 60 chats value becomes 300,000 tokens and back again; tokens → chats rounds, never below 1. Empty stays empty. A switch that would take the number past 10,000,000 is refused: the unit goes back, and the row gives the converted figure and ends Lower the limit first. The number and its unit save together.

The Organization page's settings save themselves — there is no Save button. Each change is sent after a short pause (rapid edits are coalesced into one write) and confirmed by an Organization settings updated toast. The change takes effect on the next chat request from any user whose role does not set its own number — and applies the same way across Teams, agents, and voice.

Setting a role default

Roles → click a custom role → Member defaults tab → Rules → Rate limit (per hour).

Same number + unit toggle. When the role sets a number, its unit counts that number and any per-user override for someone in the role. With the number blank, the role's unit has no effect: the organization's number and unit apply, or, if the organization sets no number either, the deployment default, counted in chats.

Setting a per-user override

Users → click Manage → Profile tab → Rate limit override.

The number is the user's rate_limit_override. Leave blank to clear and fall back to the role/org default. There is no unit control: the override is counted in the unit of the level it overrides — the role's when the role sets a number, otherwise the org's. While the padlock on Limit per member, per hour is closed under Organization › Member defaults, overrides are ignored.

The audit log records the change as user.rate_limit_changed with the new value.

Note

A per-user override only applies under the per-member plan (or under a shared pool with no pool set). When the org runs on a shared pool, the Per-member share of the pool governs each person instead.

Switching to an org pool

Organization → Member defaults → Rate limits → Plan → Shared pool. Three rows become active (under Per member they are dimmed):

  • Monthly token pool — total tokens the entire org can consume each month. Leave blank (or 0) to disable the pool and fall back to the limit per member.
  • Per-member share of the pool — the maximum share of the pool any single user can consume in a reset cycle, as a percentage (1–100). For example, 30 means no one user can use more than 30% of the monthly pool. Blank means no 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. It cannot be left blank.

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:

  1. Org-wide — once total usage since the last reset reaches the monthly pool, every user is blocked until the next reset day.
  2. Per-member share of the pool (if set) — once a user reaches their share of the pool, they're blocked but others keep their headroom.
Warning

The 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-After header — 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
}

Every refusal also carries five more fields: canRequestIncrease (true only at a member's own monthly spend limit), period (month, trial or hour), resetsAt (when that window resets, or null for a trial, whose window ends instead), pct (what was used, as a percentage of the limit) and adminNotified (true only when the refusal put a notice in your admins' inbox: the monthly AI spend ceiling, and the monthly credit allowance outside a trial). The Chat UI renders this as an inline rate-limit card explaining what was hit and when the limit resets; it says Your org admin has been notified only when adminNotified is true. 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_limit flag 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 limits govern scheduled agents, configured under Organization → Agents, in two groups, Count and frequency and Cost. /admin/defaults#agents still takes you there. Each has an explicit No limit or Limit choice, so a blank or a 0 never has to mean "none"; limits that come from your plan or the platform are shown under the field.

  • Agents per member — how many scheduled agents one member can have. Checked when an agent is created; existing agents are not affected. A limit of 0 blocks new agents.
  • Runs per member, per day — counts every run: scheduled, webhook, manual, test and agent-invoked. Further runs are blocked until midnight UTC.
  • Minimum time between runs — in minutes. Applies when an agent is created or edited; agents already running keep their schedule. The platform floor is 5 minutes whatever you set, and a value under it is refused on the row.
  • Spend per run — in dollars (for example $1.00). A run stops once its estimated spend crosses this (estimated as described under Monthly AI spend ceiling, prompt-cache reads and writes included). Recommended $0.50 to $2.00.
  • Monthly spend per agent — in dollars. Applies to each agent separately, not to a person or the organization. An agent over it is skipped until the month resets. On a template's page, its row reads Blocked by monthly cap once the scheduler has actually refused one of its runs for this limit this month; raising the limit clears it.
  • Tokens per run — behind Advanced: tokens per run. A hard ceiling on total tokens one run may use; the run stops when it is reached. Recommended 60,000 to 150,000.

A value that cannot be saved (under the floor, above a limit's maximum, or not a number) is never sent: the row says why, and when you leave the field it goes back to the saved value, for example Couldn't save: enter 5 minutes or more. Reverted to 15.

Freeze agent changes, under Rules for everyone, effective now at the top of the section, is the org-wide stop. While it is on, nobody in the org, admins included, can create or edit an agent. Existing agents keep running on their schedules, and scheduled, manual and webhook runs continue; pause an agent on its own page if it is misbehaving. Per-role canCreateAgents permission still applies on top.

Note

Organizations on a free trial carry tighter agent caps that no admin setting can loosen: at most 2 scheduled agents, and no schedule more frequent than once an hour. These sit under any org-level quota you set.

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, and that is the only place it can be changed. Organization → Member defaults → Rate limits states its current value read-only, with a Set it in Billing button beside it — a rate limit alone does not answer "why did this person stop?", so the group names the ceiling without becoming a second place to edit it.

Spend limits for members

A member can also carry a monthly spend limit of their own. It is resolved in this order: a limit set on the member (Users → Profile), else a limit from the groups they are in: the lowest of their groups' member limits, or the highest if your organization chooses Higher group limit under Member limit from groups in Usage → Spend limits (a group's limit applies to each member separately; for an amount a group's members share, see Shared budgets for groups), else the organization's Default limit per person (Billing → Manage billing), else no limit. Setting any of them requires Manage billing.

  • What it counts. The estimated model usage of the member's own work this month: chats, documents, analyses, dashboards, voice and their agents' runs, at list prices on your organization's own Azure AI Foundry. It is the same estimate the monthly AI spend ceiling adds up for everyone, plus usage charges where your organization is invoiced for them. Work on a model Strata has no price for counts at a conservative fallback rate ($5 per million input tokens and $25 per million output tokens). API keys, the support assistant and Recap never count toward a person's limit. It is an estimate, not an invoice, and the member sees it labelled that way.
  • Blank and zero. A blank field means no limit at that level. $0 is a real limit: a member it applies to is stopped. Before Billing saves a $0 Default limit per person, it asks, naming how many members it would stop.
  • Weekly pace. Billing → Manage billing → Weekly pace sets the most of their monthly limit any member may use in one week, from Monday 00:00 UTC to the next Monday, so nobody spends the month in its first days. It applies to whichever monthly limit binds the member: their own, a group's or the default. A member who reaches it is stopped until Monday, with Request more usage (a higher monthly limit raises the week's share with it), and Settings → Usage shows the week, its share and when it resets, in their own time. Leave it blank for no weekly pace.
  • Alerts at 75%, 90% and 100%. When a member reaches 75%, 90% or all of their monthly limit, every active admin who can Manage billing gets an inbox notice and an email, once per member, per month, for each. The member sees the same points in a banner over the message box. A $0 limit never alerts: an admin set it on purpose.
  • When it applies. After the organization's ceilings and before the hourly limit and the pool. It is checked as each message, voice turn or agent run starts, so an answer already under way finishes and the limit stops the next one. It resets on the 1st of each month (UTC).
  • API keys and bots. API service accounts and the organization's connection bots have no member limit; the organization's ceilings still bound them.
  • Support. The support assistant is never stopped by a money limit (a member's own limit, the AI spend ceiling or the credit allowance): Kronisys pays for it, and it counts toward none of them. The hourly limit and the pool still apply to it.
  • What the member sees. The refusal names the limit and when it resets, and offers Request more usage. Settings → Usage shows the limit with the same button. In voice mode the voice button stays next to Send at a usage limit: opening it says which limit stopped them and when it resets before it asks for the microphone, with Request more usage at their own limit. Teams links to Settings → Usage.
  • Requests. A member can have one request waiting at a time. Only a waiting request stops them asking again: after a decline they can ask again whenever they need to. Filing a request sends no admin a notice; it waits at the top of the Usage page, and on the Billing page for admins with Manage billing, which answers a request but does not by itself open the Usage page. Approve sets the member's own monthly limit to the amount you enter, which must be above the limit that applies to them now (the queue suggests twice that): it applies within a minute and stays their limit until someone changes it. An amount at or below their current limit is refused and the request keeps waiting. Decline leaves their limit unchanged. Only an admin with Manage billing sees Approve and Decline; anyone else who can view the queue is told who can act. Either way the member is emailed the answer, at the address they sign in with, and it also appears in their Strata inbox.
  • Scheduled agents. A scheduled run stopped by a monthly limit or by the pool tries again at the earlier of that limit's reset and one hour; a run stopped by the hourly limit tries again in 15 minutes.

Shared budgets for groups

A group that has a member monthly limit can also have one shared monthly budget that its members draw on together. Set it with Edit limits on the group in Usage → Spend limits; doing so requires Manage billing.

  • Both limits count. Every message, voice session and agent run counts against the member's own monthly limit and against the shared budget that pays for it. A member stops when their own limit runs out, or when every shared budget they can use has run out.
  • Which budget pays. A member in several groups with budgets draws on the largest budget first, then the next largest with money left. To decide the order yourself, choose Custom order under Which shared budget pays first in Usage → Spend limits and move the groups with the arrows: the first budget in the order with money left pays, and a budget added later comes after the ones you ordered, largest first. Put the most specific team first. The budget is chosen as each message, voice session or agent run starts, and everything that piece of work costs (the documents it writes and their review included) counts against that budget.
  • What it counts. The same estimate as a member's own limit (estimated model usage at list prices on your organization's own Azure AI Foundry, plus usage charges where your organization is invoiced for them), for the work the budget paid for. API keys, the support assistant and Recap never count. A budget counts from when it is created, then resets on the 1st of each month (UTC).
  • $0, Paused and none. $0 freezes the budget: its members cannot spend from it. Paused keeps the amount but enforces nothing, and nothing is counted against it until you set an amount again. No shared budget removes it. Removing the group's member limit, here or in the group's settings, removes its shared budget too, because a shared budget needs one.
  • The member limit is a guard rail. It caps one person; it is not an equal share of the budget. When the member limit times the number of members is no more than the budget, so the budget could never run out, Edit limits says so and offers to raise it.
  • Alerts at 50%, 75%, 95% and 100%. Every active admin who can Manage billing gets an inbox notice and an email when a budget reaches each point, once per budget amount each month, with a View group button that opens the group's row on the Usage page. Raising the budget starts the alerts again for the new amount. A $0 budget never alerts.
  • What members see. Nothing, until it stops them. Then chat says Your team's shared budget has run out, with Request more usage, and the banner over the message box and Settings → Usage say so too. Members are never shown the group's name or the budget's amount. Teams, the Outlook add-in, voice and the API give the same sentence.
  • Requests. A member stopped by a shared budget asks for more the usual way. Their request shows which group's budget had run out, with Edit group limits. Raising that budget so it has money left, or pausing or removing it, answers the request: the member is emailed, and told in their inbox, that their team's shared budget was raised. Approve still raises the member's own limit instead.
  • Scheduled agents. A run stopped by a shared budget tries again at the earlier of the 1st and one hour, like the other monthly limits.
  • Support. The support assistant is never stopped by a shared budget.

What can go wrong

ErrorWhat it means
User reports they cannot send messagesCheck 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 dayThe 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 effectSave 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 a shared pool, where per-user overrides don't apply, or the padlock on Limit per member, per hour is closed, which ignores every per-user override.
Everyone in the org is suddenly blockedThe 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 appearsNobody 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 time between runs (and the 5-minute platform floor).
User cannot create an agent despite canCreateAgents = trueFreeze agent changes is on under Agents, 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.

Related