npm packages are not installable yet: [email protected] can be published after 2026-09-16 10:30 UTC. Details
Tollstile

Add spend limits for agents

Cap how many paid calls and how much spend a single payer can make.

Public Beta · early access
import { limit, payers } from "tollstile";

const guarded = toll.price("$0.40", {
  require: [
    limit({ perPayer: "100/hour", spendPerDay: "$20" }),
    payers({ deny: ["0xBAD…"] }),
  ],
});
  • limit() counts charges from the ledger that were not released, failed, or refunded. Concurrent requests can briefly exceed a limit by the number in flight.
  • payers() matches payer ids case-insensitively (EVM addresses differ only by checksum casing).
  • Denials are 429 for limits and 403 for payer rules, and nothing is reserved.

Only for expensive calls

import { amountOver, when } from "tollstile";

toll.price("$10", { require: [when(amountOver("$5"), strongerCheck)] });

Write your own requirement

import type { Requirement } from "tollstile";

const businessHours: Requirement = {
  name: "business-hours",
  async check({ now }) {
    const hour = now.getUTCHours();
    return hour >= 9 && hour < 17 ? { ok: true } : { ok: false, status: 403, reason: "closed" };
  },
};

Requirements also receive claims, a single-use store for nonces, and the quote, which carries a fresh nonce for evidence bound to this request.

Retries

Send Idempotency-Key on the first paid request and keep it on retries of the same request (on MCP: _meta["tollstile/idempotency-key"]). A completed charge returns 409 already_paid; an in-flight charge returns 409 request_in_progress; an unknown outcome returns 503 payment_outcome_unknown. Do not start a new payment while the outcome is unknown. Released/refunded attempts may run again. See Idempotency for request matching and rail-specific key scopes.

On this page