Skip to content

Anthropic Spend Kill-Switch

Unlike GCP (where gcloud billing projects unlink is a one-call hard cap), Anthropic does not expose a programmatic β€œdetach billing” API. The kill-switch is therefore a combination of:

  1. Hard monthly spend limit configured in the Anthropic Console β€” Anthropic stops accepting API calls when the limit is reached. This is the actual hard cap.
  2. Usage alerts at 50% / 80% / 100% β€” emailed to [email protected].
  3. Application-layer safeguards (rate limit, Turnstile, history caps) that bound the worst-case burn rate while the hard cap is in flight.

The application-layer safeguards live in workers/api/src/routes/support-chat.ts.

One-time setup in the Anthropic Console

  1. https://console.anthropic.com/settings/billing β†’ Cost section
  2. Set Monthly spend limit = $200 (initial value β€” bump as legitimate usage warrants)
  3. Set Email alerts at 50%, 80%, 100% to [email protected]
  4. Confirm the affected key (ANTHROPIC_API_KEY, used by the support chat) is on this workspace. Each Anthropic workspace has its own limit.

Once the monthly limit is hit, every messages.create returns HTTP 429 / billing_limit_exceeded until the next calendar month or until the limit is raised.

What happens when the cap fires

  • Support chat at https://theaccessible.org/support starts returning the generic β€œAssistant error” message β€” clients fall through to the contact form (intended behavior).
  • All other Anthropic-using surfaces fail simultaneously. Today the support chat is the only public consumer; if you add more, list them here so on-call knows the blast radius.

Investigating before raising the cap

  1. Read recent abuse logs in Supabase:
    SELECT level, message, metadata, created_at
    FROM app_logs
    WHERE service = 'support-chat'
    AND created_at > now() - interval '24 hours'
    ORDER BY created_at DESC
    LIMIT 200;
  2. Group by metadata->>'ip' and metadata->>'status' to spot rate-limited or turnstile-failed bursts:
    SELECT
    metadata->>'ip' AS ip,
    metadata->>'status' AS status,
    count(*) AS n
    FROM app_logs
    WHERE service = 'support-chat' AND created_at > now() - interval '24 hours'
    GROUP BY 1, 2 ORDER BY n DESC LIMIT 50;
  3. Check the Anthropic Console usage chart at https://console.anthropic.com/settings/usage β€” confirm the shape (steady growth = legit, vertical wall = abuse).

If abuse is confirmed:

  • Rotate ANTHROPIC_API_KEY (see docs/admin/secrets-inventory-and-rotation.md).
  • Add the offending IP/CIDR to a Cloudflare WAF rule before re-raising the cap.
  • workers/api/src/routes/support-chat.ts β€” rate limits, Turnstile, history caps, abuse logging
  • docs/admin/gcp-budget-killswitch.md β€” sibling document for Gemini spend
  • GitHub Issue #711 β€” original tracking issue for support-chat safeguards