Skip to content

TypeScript SDK

The SDK does two things. guard and reserve put a limit around your code in one call. And every API operation is a typed method, so your editor knows each field and answer.

Terminal window
npm install @limitry/sdk

Set LIMITRY_API_KEY to a key from API keys in the app. Use a test key (lim_test_…) while you build.

guard checks the limit, then runs your code only if it’s allowed. Here it counts one AI call against a limit such as 100 a day:

import { createClient, LimitReached, Unavailable } from "@limitry/sdk";
const limitry = createClient(); // reads LIMITRY_API_KEY
try {
const reply = await limitry.guard(
{ subject: { kind: "user", id: "usr_123" }, action: "ai-call" },
() => callModel(prompt),
);
} catch (error) {
if (error instanceof LimitReached) {
console.log(`Try again in ${error.retryAfterSeconds} seconds`);
} else if (error instanceof Unavailable) {
console.log("Limitry is unreachable and this limit fails closed");
}
}

A refusal throws LimitReached, with reason (limit_reached or too_many_reservations), limitId and retryAfterSeconds.

When you only know the cost afterwards, such as an AI reply your product pays for by the token, reserve reserves what it will probably cost (5 cents here), runs your code and charges what it actually used. If your code throws, the reservation is released:

import { createClient } from "@limitry/sdk";
const limitry = createClient();
const answer = await limitry.reserve(
{ subject: { kind: "user", id: "usr_123" }, action: "ai-call", cost: 5 },
async (reservation) => {
const response = await callModel(prompt);
reservation.cost(priceCents(response.usage)); // your prices, in cents
return response;
},
);

If Limitry can’t be reached, each limit’s fail mode decides: open lets the work run, closed throws Unavailable, never LimitReached. “Can’t be reached” means no decision within 1.5 seconds (timeoutMs), retries included: a network error, a 408, a 429 or a 5xx is retried at most twice with the same key inside that time. A 402 (the workspace is past its plan) counts the same way. A 503 with code moving (a busy workspace’s counts moving between Limitry’s servers, a few seconds) or busy (too many checks at once; nothing was charged) is not “can’t be reached”: the check, commit or release is sent again with the same key for up to 30 seconds, each try with its own 1.5 seconds, before the fail mode decides. Each retry waits the answer’s Retry-After plus a random, growing backoff, so clients spread out instead of retrying together. reservation.cost() takes a whole number from 0 to 1,000,000,000 and throws a RangeError for anything else, before the work’s usage could be lost. reservation.extend() throws the API’s error, such as for an expired reservation. See Add Limitry with your agent for more.

Each API operation is a method, named like its command in the CLI: limitry limits create is limitry.limits.create().

import { createClient } from "@limitry/sdk";
const limitry = createClient();
await limitry.limits.create({
name: "AI replies per day",
subject: { kind: "user" },
action: "ai-call",
amount: 100,
window: "day",
});
const { items } = await limitry.limits.list();
  • Ids in the path are arguments, and everything else is one object: limitry.limits.get(limitId).
  • A method returns the response’s data. A failure throws an ApiError with the error’s code, message, status and requestId.
  • Every write sends an idempotency key, and a failed attempt (a network error, a 5xx, a 429) is retried with the same key, so it happens once. To make your own retry safe too, pass your key as the last argument: limitry.checks.create(check, { idempotencyKey: id }).

Every method, linked to its fields and a full example under Endpoints:

Checks

MethodWhat it does
limitry.checks.create()Check whether a subject may act

Reservations

MethodWhat it does
limitry.reservations.commit()Commit a reservation
limitry.reservations.extend()Extend a reservation
limitry.reservations.release()Release a reservation

Limits

MethodWhat it does
limitry.limits.archive()Archive a limit
limitry.limits.create()Create a limit
limitry.limits.credits.create()Add credits to a balance
limitry.limits.credits.list()List a balance's credits
limitry.limits.get()Get a limit
limitry.limits.list()List limits
limitry.limits.restore()Restore an archived limit
limitry.limits.sync()Sync limits from a list
limitry.limits.update()Change a limit

Subjects

MethodWhat it does
limitry.subjects.get()Get a subject
limitry.subjects.reset()Reset a subject's limits
limitry.subjects.update()Set a subject's billing date

Usage

MethodWhat it does
limitry.usage.query()Get a limit's usage over time
limitry.usage.standing()Get where a subject stands
limitry.usage.subjects()List who is using a limit now

Workspace

MethodWhat it does
limitry.workspace.get()Get the current workspace
limitry.workspace.invitations.list()List pending invitations
limitry.workspace.members.list()List workspace members
limitry.workspace.teams.list()List teams
limitry.workspace.usage()Get your plan's usage this period

Webhooks

MethodWhat it does
limitry.workspace.eventTypes.list()List event types
limitry.workspace.webhookDeliveries.list()List an endpoint's deliveries
limitry.workspace.webhookDeliveries.redeliver()Redeliver an event
limitry.workspace.webhookEndpoints.create()Add a webhook endpoint
limitry.workspace.webhookEndpoints.delete()Remove a webhook endpoint
limitry.workspace.webhookEndpoints.enable()Re-enable a webhook endpoint
limitry.workspace.webhookEndpoints.get()Get a webhook endpoint
limitry.workspace.webhookEndpoints.list()List webhook endpoints
limitry.workspace.webhookEndpoints.test()Send a test event

Approvals

MethodWhat it does
limitry.workspace.approvalActions.list()List the actions you can ask approval for
limitry.workspace.approvalRequests.create()Ask a person to approve an action
limitry.workspace.approvalRequests.get()Check an approval request
limitry.workspace.approvalRequests.redeem()Redeem an approved request

Audit events

MethodWhat it does
limitry.workspace.auditEvents.list()List workspace audit events

Personal access tokens

MethodWhat it does
limitry.user.me()Get the current user
limitry.user.revokeToken()Revoke the token making this request
  • createClient() reads your key from the LIMITRY_API_KEY environment variable. Without it, it throws an error naming the variable. Where there’s no process.env, such as a browser or a Cloudflare Worker, pass the key: createClient({ token: env.LIMITRY_API_KEY }).
  • A test key (lim_test_…) acts in test, and a live key (lim_live_…) in live. See Test and live.
  • A personal access token names the workspace, and acts in test unless you name live: createClient({ token, workspace: "acme", environment: "live" }).

createLimits(client, options) gives you guard and reserve with a different wait for a decision (timeoutMs, 1500 ms by default) or a fixed fail mode:

import { createClient, createLimits } from "@limitry/sdk";
const limits = createLimits(createClient(), { timeoutMs: 500 });

limitry.GET, limitry.POST and the other HTTP methods call any path, with the same types. They return { data, error, response } instead of throwing, and unwrap turns that into the data or an ApiError.