Skip to content

Limits

A limit says how much a subject may use per window. It reads as one sentence: each user may use 200 cents per month. Subjects are whoever acts in your product, such as your users, teams, API keys or AI agents. You choose the labels, and Limitry only matches them.

Kind Reads as window
Per period each user may use 100 credits per month minute, hour, day, week, month or year
Balance each user starts with 500 credits; add more total, a balance that never resets
Running at once each user may run 3 at the same time concurrent: a slot per running job (a reservation), given back when it finishes

In the app, New limit on the Limits page asks for the kind, then the sentence: Each [user] may use [100] [credits] per [month]. Everything else is under More options, with the defaults below, and a preview reads back what a subject would see. After you save, Add another limit opens a new one with the same unit and period filled in.

Only subject.kind, amount and window are required.

Field Meaning
subject Who it applies to. {"kind": "user"} is every user; add "id": "usr_123" for one subject.
amount How many units per window. For concurrent, how many at once.
window minute, hour, day, week, month, year, total or concurrent. See below.
action The action it limits. Default *, every action.
unit What the amount counts (calls, credits, cents), in words. Default units.
name Your label, unique among the environment’s active limits. Default: the sentence, such as “100 credits per user per month”.
every How many windows a period lasts: every: 3 with month is a quarter. Default 1.
start Where a period begins: calendar (the default), billing_date or first_use. See When limits reset.
rolling With minute, hour or day: count the last 60 seconds, minutes or 24 hours. Default false.
failMode What your code should do when Limitry can’t be reached: open (allow, the default) or closed (deny).
enabled Whether checks enforce it. Default true.

A name made from the sentence names the action when it isn’t *: “100 credits per user per month for ai-call”. If another active limit already has that name, the API answers 409 with invalid_request and creates nothing. Send a name of its own.

Limitry saves every count before a check answers, whatever the limit. There is no faster mode that could lose a count.

  • minute, hour, day, week, month and year reset at the end of each period: on UTC boundaries by default, on each subject’s billing date, or a set time after its first use. A period can be several windows long: every 3 months, every 5 hours. See When limits reset.
  • minute, hour and day can also be rolling: they count the last 60 seconds, minutes or 24 hours.
  • total is a balance that never resets, for prepaid credits. See Pools, balances and budgets.
  • concurrent allows at most amount at once. See Rolling windows and concurrency.

When several limits match a subject and action, all of them apply, with one exception. That’s how you give each of your users a monthly AI budget and a cap of 100 AI replies a day: two limits, and a check has to fit both. A limit for one subject (with subject.id set) replaces the limits for its whole kind that have the same action and window. The exception is how you give one customer more than their kind allows, or less. The kind’s other limits still apply: a subject with its own minute limit is still held to the kind’s day limit.

To limit a user, their team and their tenant at once, make one limit for each and name all three in the check. See Budgets at several levels.

In the app, limits are on the Limits page. Owners and admins can change them, and every member can see them. From your code or the CLI, a key or token needs the limits:read or limits:write scope:

The Limits page in live: six limits, each with Edit and Archive. Agent daily budget, 500 cents per agent a day; Credits, a 100 credits team balance; API burst, 60 requests in any 60 seconds; Exports at once, 3 at once per workspace; AI budget, 200 cents per user a month; API per hour, 1,000 requests in any 60 minutes. The two budgets show Denies if unreachable.The Limits page in live: six limits, each with Edit and Archive. Agent daily budget, 500 cents per agent a day; Credits, a 100 credits team balance; API burst, 60 requests in any 60 seconds; Exports at once, 3 at once per workspace; AI budget, 200 cents per user a month; API per hour, 1,000 requests in any 60 minutes. The two budgets show Denies if unreachable.The Limits page in live: six limits, each with Edit and Archive. Agent daily budget, 500 cents per agent a day; Credits, a 100 credits team balance; API burst, 60 requests in any 60 seconds; Exports at once, 3 at once per workspace; AI budget, 200 cents per user a month; API per hour, 1,000 requests in any 60 minutes. The two budgets show Denies if unreachable.The Limits page in live: six limits, each with Edit and Archive. Agent daily budget, 500 cents per agent a day; Credits, a 100 credits team balance; API burst, 60 requests in any 60 seconds; Exports at once, 3 at once per workspace; AI budget, 200 cents per user a month; API per hour, 1,000 requests in any 60 minutes. The two budgets show Denies if unreachable.
import { createClient } from "@limitry/sdk";
const limitry = createClient();
// Named "200 cents per user per month for ai-call"
await limitry.limits.create({
subject: { kind: "user" },
action: "ai-call",
amount: 200,
unit: "cents",
window: "month",
failMode: "closed",
});

Agents can do the same through the MCP server. The workspace’s audit log records every change, and a change reaches checks at once.

You can change a limit’s name, amount and fail mode at any time, and turn it off or on. What it counts is fixed once it exists: subject (kind and id), action, unit, window, every, start and rolling. Changing one of those would start the limit’s counts over, or compare counts in the wrong unit, so Limitry refuses it with 400 invalid_request and a message saying what to do.

To change what a limit counts, create a new limit with the new values, then archive the old one. Its history stays. In the app, the edit view shows the fixed fields as text, with “Create a new limit to change this”. In a limitry.json, give the entry a new name.

A limit that’s off (enabled: false) never refuses, but checks still count against it: turn it on again and it starts from what was really used, not from zero.

Each limit says when a check last reached it (lastCheckedAt, to the hour, from usage history). The Limits page flags a limit that no check has reached in 7 days: “No check has named a team in 7 days: this limit isn’t being enforced”. It usually means your checks send a different subject kind or action than the limit has, such as teams for team. Fix the check, or create a limit that matches it.

Test and live each have their own limits. The app shows the side you picked at the top right, and a key manages the limits of its own environment. Set limits up in test, then click Copy to live to create or update them in live. See Test and live.

To keep your limits in your repository instead, list them in a limitry.json and run limitry sync. It creates, changes and (if you ask) archives limits by name to match the file, from your machine or from CI. See Sync limits from GitHub.

In test, the Limits page has Try a check. Pick a limit, type a subject id such as usr_123, and click Check. You get the same answer your code would get from a check with a test key: allowed or refused, and what’s left on every limit that applies. Click it until a limit refuses to see a refusal. These checks count against your test allowance and aren’t billed. Owners and admins can try checks; it isn’t on the live side, where a check would count for real.

While a workspace has no limits in test, the Limits page offers Add example limits: images per user per day, an AI budget per user per month, and API calls per key per minute, each named “Example: …”. Simulate traffic then sends a few hundred test checks from pretend users and keys, enough that some are refused, and the Usage page shows them within a minute. Test checks aren’t billed. Remove examples archives the example limits and nothing else. Examples are for test only.

Limitry never erases a limit. When you no longer need one, archive it: Archive on the Limits page, or limitry limits archive <limit-id>. Checks stop enforcing it at once and don’t count against it while it is archived. It leaves the list, but its usage history and credits stay. The Usage page still shows it, marked archived. Archived limits on the Limits page lists them, and Restore (or limitry limits restore <limit-id>) brings one back. An archived limit’s name is free, so a new limit can take it. You can’t restore a limit while another active limit has its name.