Spend Brake

A proxy for paid APIs

Hard dollar caps for every paid API your apps and agents call. Enforced before the request leaves.

Swap one base URL and one key. Every call is priced per SKU, checked against your caps in one atomic step, and refused with a clear 402 once a cap would be crossed. Google Maps Platform first; Twilio, Mapbox, HERE, Tavily, Exa, Brave and SerpApi built in.

Free plan: 1 key and $50/month of protected spend, no card. Or self-host the Apache-2.0 core with one docker compose.

app.ts → through Spend Brake
- https://maps.googleapis.com/maps/api/geocode/json
+ https://proxy.spendbrake.dev/google-maps/maps/api/geocode/json
-   ?address=Sofia&key=AIza…
+   ?address=Sofia&key=sb_live_…

HTTP/1.1 200 OK
X-Brake-Cost-Micros: 5000
X-Brake-Remaining-Micros: 3000

… the next call would cross the cap:
HTTP/1.1 402 Payment Required
{"error":"budget_exceeded",
 "message":"Spend cap reached for org. Stop and ask the user to raise the cap.",
 "scope":"org","window":"d:20261029","cap":5000000,"spent":4997000,
 "resetsAt":"2026-10-30T00:00:00.000Z"}
Before, not after Priced and reserved against every cap before the request is forwarded. Not hours later from billing data.
Micro-dollar exact Google's SKU tiers and field masks are understood, so a $0.04 request is never counted like a free one.
One request of overshoot Worst-case cost is reserved first and settled after. Overshoot is bounded by a single call's worst case.

How it works

Your key never leaves the proxy. Clients only hold revocable virtual keys.

You keep your provider account and your own key. Spend Brake stores it encrypted, forwards each request with it, and hands your apps and agents sb_live_… keys you can cap, scope and kill.

  1. Authenticate

    The virtual key is checked (cached 5 s) along with its environment, agent and session.

  2. Price

    SKU from the path and field mask, worst case in micro-dollars, from price files that cite their source.

  3. Reserve

    One Lua call on Valkey: kill switch, loop breaker, and a reservation against every cap at once.

  4. Forward

    The real key is decrypted locally and never logged. Responses stream through; nothing is cached.

  5. Settle

    The actual cost replaces the reservation and a usage event lands in the ledger, in the background.

app / agent → proxy → provider, then Valkey → worker → Postgres ledger → alerts → webhooks / email. Valkey down means fail closed (503) unless a key opts into a small fail-open allowance.

What you get

Caps that hold, and everything around them.

Hard caps at every scope

Per org, key, SKU, environment, agent and agent session; per day and per month. All checked atomically, so parallel requests cannot slip past together.

Priced per SKU, in real time

Google Maps Platform Places, Geocoding and Routes priced per field mask; Twilio settled at its final price. A daily check watches provider price pages for drift.

Kill switch

One call, link or button stops a key, a provider, a session or the whole org immediately. Alerts carry signed Kill, Raise and Mute links so you can act from your phone.

Loop detection

A circuit trips when a key repeats identical requests, or a session pumps calls, past your rule. The caller gets 429 loop_detected with a retry time, and you get an alert.

Budget alerts with actions

Signed webhooks with Slack, Discord and Teams presets or raw JSON, plus email. Thresholds, kills, loops and price changes, each with one-click actions.

Telemetry for each org

Your own Prometheus endpoint at GET /v1/metrics: requests by outcome, cost, refunds, latency histograms and live budget. OpenTelemetry export sends every call as a span to your collector, joined to the caller's trace.

The brake CLI

brake init sets up an org, stores the provider key and prints the exact Google Cloud steps to restrict it to the proxy. brake session runs any agent inside its own budget.

Built to stay inside provider terms

Bring your own key, always. Responses are never cached to cut billing. Only request metadata is stored, never bodies or query strings. Every request reaches the provider with your key.

Migration estimate

brake estimate prices your last 30 days of Google usage on Geoapify, Stadia Maps, Open Places API, Mapbox and HERE side by side, and shows what would stay on Google.

For AI agents

Give every agent run a budget it cannot talk its way out of.

Run any agent or script inside a session with its own cap. When the money runs out, the agent gets one line telling it to stop and ask you, not a quietly growing bill.

  • Session keys that can spend at most what you say, count against the agent's daily budget and the parent key's caps, and are revoked when the agent exits.
  • Capped calls from inside the agent: brake maps geocode, brake maps search or brake call <provider> <method> <path>, each printing the cost.
  • Clear exit codes (3 for a cap, 4 for the loop breaker) with one line the agent can act on.
  • Per-session loop rules and, on the Agents plan, session analytics and custom loop rules.
shell
$ export BRAKE_KEY=sb_live_… BRAKE_URL=https://proxy.spendbrake.dev
$ brake session --budget 5 --day-budget 20 --agent claude -- claude

# inside the agent
$ brake maps geocode "Vitosha Blvd 1, Sofia" --pretty
HTTP 200 · cost $0.0050 · remaining $4.99
{ "results": [ … ] }

… the agent keeps going …
brake: STOP. Spend cap reached for sess:s_7f3a (cap $5.00).
Do not retry; ask the user to raise the cap.  exit 3

Compared with Google's own controls

Budgets alert. Quotas count requests. Spend Brake stops dollars.

Keep Google's budgets and quotas on as a backstop. Spend Brake is the part that acts before the money is spent.

Google Cloud budgets Maps Platform quotas Spend Brake
Stops spend No, alerts only Yes Yes, before the request leaves
Unit Dollars Requests per API per minute or day Dollars, micro-dollar exact
Knows SKU tiers (field masks) After billing No: a $0.04 request counts like a free one Yes, priced per field mask
Delay Hours (billing data) Real time Real time
Granularity Project / billing account Project, per API Org, key, SKU, environment, agent, session; day and month
Loop / runaway detection No No Yes, trips a circuit
Kill switch No Set a quota to 0 by hand One call, link or button; immediate
Alerts with actions Email, Pub/Sub No Webhooks (Slack, Discord, Teams, raw) and email with Kill / Raise / Mute links

Client-side Maps (the Maps JavaScript API, tiles and widgets) is out of scope: Spend Brake proxies server-side APIs.

Pricing

Hosted plans, billed monthly through Stripe. Cancel any time.

Every plan enforces caps the same way. Plans differ in how many keys, providers and agent sessions you run, and how long call history is kept.

Free

$0

One project, one provider, a real cap.

  • 1 key, 1 provider
  • Up to $50/month of protected spend
  • 10,000 requests/month
  • 20 agent sessions/month
  • 7 days of call history
Create account

Indie

$9/month

Side projects and small apps with real traffic.

  • Unlimited keys, 2 providers
  • No limit on protected spend
  • 100,000 requests/month
  • 100 agent sessions/month
  • 7 days of call history
Start with Indie

Agents

$149/month

Fleets of agents, every provider, a year of history.

  • Unlimited keys, every provider
  • No limit on protected spend
  • 10,000,000 requests/month
  • Unlimited agent sessions
  • 1 year of call history
  • Session analytics and custom loop rules
  • OpenTelemetry export to your collector
Start with Agents

Self-hosted

The core is Apache-2.0 and never needs a license key: proxy, budget engine, caps, kill switch, loop detection, CLI, catalog, dashboard and signed webhooks. Business and Enterprise licenses add single sign-on (OIDC, SAML), more roles, two-person approval for raising caps, audit export, several orgs per install, the signed catalog feed and billing reconciliation. Licenses are checked offline.

Business

$299/month

Self-hosted license, 3 orgs per install.

Enterprise

from $10,000/year

Self-hosted license, 25 orgs per install, invoiced. Get in touch.

Prices in USD, before tax. Downgrades and failed payments only block creating new keys, providers and sessions: existing keys and caps keep enforcing.

Self-hosting

Run it on your own host in five minutes.

One Docker Compose file starts the proxy, admin API, notifier, dashboard, worker, Valkey and Postgres. An HTTPS overlay adds Caddy with automatic certificates; proxy replicas and Valkey Cluster are covered when you outgrow one box.

  • Nothing phones home. Licenses are Ed25519-signed files verified offline. A self-hosted install sends no data to Spend Brake.
  • Backups and upgrades are scripted. For now you build the images and the CLI from source; published images and an npm package are coming.
  • The same CLI works against your install: brake init --api-url … --proxy-url …

Read the self-hosting guide

quickstart
$ git clone https://github.com/KIvanow/spend-brake && cd spend-brake
$ cp infra/.env.example infra/.env   # fill in the secrets
$ docker compose -f infra/docker-compose.yml up -d --build --wait

$ pnpm install && pnpm --filter @spend-brake/cli build
$ node apps/cli/dist/brake.cjs init --api-url http://localhost:8081 \
    --proxy-url http://localhost:8080 --org acme --day-cap 5 --month-cap 50
Org acme is ready. An admin token is saved to ~/.config/brake/config.json.

Your virtual key (shown once, store it now):
  sb_live_…

Use it instead of the Google key, with the proxy as the base URL:
  http://localhost:8080/google-maps/maps/api/geocode/json?address=Sofia&key=sb_live_…
… then the Google Cloud steps to restrict the real key to the proxy.

Caps only hold if the proxy is the only path to spend.

Restrict each provider key to the proxy's outbound IP addresses and the APIs you use; brake init prints the exact steps. Keep the provider's own budgets and quotas on as a backstop. Overshoot is bounded by one request's worst case, and your provider's bill remains the authoritative record of what you spent.

Get started

One base URL. One key. A cap that means it.

Create a free account, add a provider key, set a cap and make the first call from the Get started page.