Token Vault
Guides

Hardening Your Webhook

Rate limits, backoff, and budget alerts that keep a runaway agent from burning your webhook's quota — Token Vault's defaults plus the Cloudflare-side rules worth adding.

Your webhook is the data plane: every credential fetch and proxied call lands on infrastructure you pay for. A crash-looping container that re-fetches a credential on every restart can burn a Cloudflare Worker's daily quota in minutes — fully authenticated, policy-passing traffic, so nothing about it looks like an attack. This guide covers the layers that stop that, from the defaults Token Vault enforces for you to the Cloudflare rules you should add yourself.

What Token Vault already enforces

These floor limits are on by default for every account — no policy setup required:

PathDefault limitOn exceed
GET /api/agents/credentials60/min per agent429 + Retry-After
MCP proxy (/api/proxy/mcp)300/min per proxy429 + Retry-After
POST /api/tokens/{service}/refresh10/hour per service429 + Retry-After

Repeated rejections — invalid keys, policy denials, expired grants — escalate into a penalty box: each strike doubles a lockout (1s up to 15 minutes) during which requests are refused immediately, before any policy evaluation or webhook traffic. One successful request clears it.

Token Vault also protects your webhook from itself: a 429 from your webhook is never retried (the Retry-After you send is propagated to the calling agent), and after repeated failures Token Vault opens a circuit breaker and stops calling your webhook entirely for a cool-off window.

Want tighter limits for a specific agent or token? Attach a rate_limit policy — the stricter of the two applies.

Have your webhook return 429

Since spec 2.5, the webhook contract includes 429 as a first-class response: send it with a Retry-After header (seconds) and Token Vault backs off instead of retrying. The TypeScript reference webhook ships this as a per-isolate token bucket — enable it with one env var:

# wrangler.toml
[vars]
TV_RATE_LIMIT_PER_MINUTE = "300"

Each Workers isolate counts alone, so treat this as damage-bounding, not a global limit.

Add a Cloudflare rate-limiting rule

The durable, global limit lives at Cloudflare's edge, in front of your Worker — it works even for traffic that never touches Token Vault (agents follow a 307 redirect and then talk to your webhook directly, so their retries are invisible to Token Vault).

Dashboard → your zone → Security → WAF → Rate limiting rules (the free plan includes one rule):

  • If: hostname equals your webhook host
  • Rate: 300 requests / 1 minute per IP (match TV_RATE_LIMIT_PER_MINUTE)
  • Then: Block for 1 minute

Set a budget alert

Rate limits bound the damage; an alert tells you it's happening. On Cloudflare: Notifications → Add → Usage Based Billing / Workers usage and set a threshold well below the quota you'd care about. On Cloud Run or Lambda, use the platform's budget alerts. Pair it with the activity log in the Token Vault dashboard — a rate-limited agent shows up there immediately.

Client-side: the tvault CLI backs off for you

tvault honors Retry-After on 429 with exponential backoff, fails fast (exit code 7) when the wait exceeds 10 seconds, and never retries mutating requests. If you script credential fetches yourself, do the same: treat 429 as "sleep, then retry", not as an error to loop on.

On this page