Use cases
The same check covers each of these. What changes is the limit you set and the subject you check.
Keep your product's AI costs per user under control
Your product has AI features your users rely on, and you pay for them by the token. A few heavy users, or one script, can cost more than they pay you.
The rule. Each of your free users gets a $2 AI budget a month. Hold an estimate before each reply, and charge what it actually cost.
await limitry.hold(
{
subject: { kind: "user", id: user.id },
action: "ai-call",
estimate: 5,
},
async (held) => {
const res = await llm(prompt);
held.cost(priceInCents(res.usage));
return res;
},
);with limitry.hold(
subject={"kind": "user", "id": user.id}, action="ai-call", estimate=5
) as held:
res = llm(prompt)
held.cost(price_in_cents(res.usage))Sell prepaid credits
Customers buy credits in packs, and everyone on their team spends from the same balance. When it runs out, they should be asked to top up, not told to wait.
The rule. Each team has a balance that never resets. Your payment webhook adds credits; every member's request draws from it.
await limitry.guard(
{
subject: { kind: "user", id: user.id },
shared: [{ kind: "team", id: user.teamId }],
action: "report",
cost: 25,
},
() => buildReport(params),
);with limitry.guard(
subject={"kind": "user", "id": user.id},
shared=[{"kind": "team", "id": user.team_id}],
action="report",
cost=25,
):
report = build_report(params)Rate-limit your own API's customers
Your customers call your API with their own keys. One customer's runaway loop shouldn't slow down everyone else.
The rule. Each key gets 60 requests in any minute and 1,000 in any hour. Over either, answer 429 with Retry-After.
await limitry.guard(
{
subject: { kind: "apikey", id: keyId },
action: "api-request",
},
() => route(request),
);with limitry.guard(subject={"kind": "apikey", "id": key_id}, action="api-request"):
response = route(request)Give AI agents a budget
Agents in your product call models and paid tools in a loop. A loop that goes wrong can spend a lot before anyone looks.
The rule. Each agent gets $5 a day across every model and tool call. At the cap, it stops between steps until the next day, and someone on your team can reset it early from the Usage page.
await limitry.hold(
{
subject: { kind: "agent", id: agentId },
action: "tool",
estimate: 10,
},
async (held) => {
const result = await callTool(input);
held.cost(result.costCents);
return result;
},
);with limitry.hold(
subject={"kind": "agent", "id": agent_id}, action="tool", estimate=10
) as held:
result = call_tool(tool_input)
held.cost(result.cost_cents)Cap heavy jobs running at once
Exports, imports and renders are heavy. You want each customer to run only a few at a time, and a crashed job mustn't hold its place forever.
The rule. Each workspace runs at most 3 exports at once. A job takes a slot when it starts and gives it back when it ends, or when its worker stops responding.
await limitry.hold(
{
subject: { kind: "workspace", id: workspaceId },
action: "export",
},
() => runExport(job),
);with limitry.hold(
subject={"kind": "workspace", "id": workspace_id}, action="export"
):
run_export(job)Refill on each customer's billing date
Your customers subscribe on any day of the month, and some pay yearly. Their allowance should refill on the day they're billed, not on the 1st.
The rule. Each team's 1,000 reports refill on its own billing day, every month, for annual plans too. Support can refill a team at once.
// From your billing webhook, when a subscription starts
await limitry.subjects.update("team", team.id, {
anchor: subscription.startedAt,
});# From your billing webhook, when a subscription starts
limitry.subjects.update("team", team.id, anchor=subscription.started_at)Limits that refill after first use
If you build a chat product, you can give each of your users a burst of messages that refills a few hours after they start, so a quiet user loses nothing.
The rule. Each of your users gets 45 messages per 5 hours, counted from their first message, next to their monthly budget.
await limitry.limits.create({
name: "Messages per 5 hours",
subjectKind: "user",
action: "chat",
amount: 45,
window: "hour",
every: 5,
start: "first_use",
});limitry.limits.create(
name="Messages per 5 hours",
subject_kind="user",
action="chat",
amount=45,
window="hour",
every=5,
start="first_use",
)A free plan that can't be abused
Your free plan has a monthly quota. One new sign-up shouldn't be able to use the whole month in an hour.
The rule. Free teams get 3,000 emails a month and at most 100 a day. Paid teams get their quota with no daily cap.
await limitry.guard(
{
subject: { kind: `team-${team.plan}`, id: team.id },
action: "send-email",
},
() => sendEmail(message),
);with limitry.guard(
subject={"kind": f"team-{team.plan}", "id": team.id}, action="send-email"
):
send_email(message)Something else?
If you can say it as "this many, per this, per this long", Limitry can probably enforce it. Tell us what you need, or read how limits work.