2026-10-28
How do I get an alert when my OpenAI or Anthropic API bill spikes?
OpenAI spend alerts are a monthly email for an organization or a project. Anthropic's monthly cap stops requests. Ping each job with tokens and cost_usd.
A surprise API bill is usually one job that kept succeeding. OpenAI and Anthropic document monthly controls for an organization, a project, or a workspace. This page is what those official pages say, checked 2026-10-28, and the per-job ping that sends tokens and cost_usd after each run.
The Claude Code heartbeat shows how to read that CLI's total_cost_usd into this same ping, and why that figure is an estimate. The runaway spend note is the short version of a hard cap and a spike over a baseline. The rules in the last section match the runaway limits page and the code behind it.
What OpenAI documents
The spend limits guide describes two monthly controls. Checked 2026-10-28.
- A spend alert sends a notification, and API traffic continues.
- A hard spend limit makes affected API requests return HTTP 429. The error code is organization_spend_limit_exceeded for an organization limit and project_spend_limit_exceeded for a project limit.
- An organization hard limit applies to API traffic across that organization's projects. A project hard limit applies to traffic billed to that project. Both can apply to the same request.
- Either control is separate from the monthly usage limit OpenAI assigns from the organization's usage tier.
In the console, an organization limit is under Organization limits, then Spend, then Edit spend limit. A project limit is under Project settings, then Limits, then Spend, then Edit spend limit. The field is a monthly spend limit. Enforce a hard limit is the switch that turns the notification into the 429.
The Terraform guide for rate limits and spend lists the alert fields. The interval must be month. The currency must be USD. threshold_amount is the monthly threshold in cents. The guide's project example uses 20000 and says that represents USD 200. That USD 200 is the guide's example, not a recommended budget. The notification channel type must be email, and the recipient list must contain at least one address. A subject prefix is optional. An organization alert has no project id, because it measures spend across the organization. A project alert takes a project id. The same page says a spend alert is a notification: it does not stop API requests, and it does not enforce a spending cap.
The spend limits guide says hard-limit enforcement is not instantaneous. The API platform can process a small amount of extra usage while the limit state propagates, so recorded spend can slightly exceed the configured amount. Raising or removing the reached limit lets traffic resume after the update propagates. Otherwise the limit resets with the next monthly cycle.
Token counts for one call are on that call's response. The usage and costs help article lists usage.prompt_tokens, usage.completion_tokens, and usage.total_tokens for Chat Completions, and usage.input_tokens, usage.output_tokens, and usage.total_tokens for Responses. Cached-input and reasoning tokens can appear as well, depending on the endpoint and model. That object is the per-call count. The monthly email is the organization or project threshold above.
What Anthropic documents
The rate limits page describes spend limits as a maximum monthly cost an organization can incur. Checked 2026-10-28. Service-configured limits are enforced at the organization level. You can also set a limit on a workspace.
The documented monthly spend caps are $500 USD on Start, $1,000 USD on Build, and $200,000 USD on Scale. The Custom tier has no monthly spend cap on that table. Those limits are arranged with the account team. New organizations, and organizations with a short usage history, may start on the Evaluation tier, with limits below the standard limits shown on that page.
Reaching the tier's spend cap pauses API usage until 00:00 UTC on the first day of the next month, unless a higher limit is granted sooner. Requests then return HTTP 429 with error type rate_limit_error and error code enforced_spend_limit_reached. That 429 has no retry-after header. The errors page describes the same response.
A limit you choose, below the tier cap, is on the Billing page in the Claude Console, at platform.claude.com/settings/billing. In Spend limits, choose Adjust limit, or Set limit when none is set. The value cannot exceed the current tier's cap. When usage reaches a limit you set, requests return HTTP 400 with error type invalid_request_error. The message starts with "You have reached your specified API usage limits", or "You have reached your specified workspace API usage limits" for a workspace limit. Limits on the Claude Code workspace are checked separately. A Claude Code request over that workspace's limit can return HTTP 429 with a retry-after header.
The rate limits page describes the cap that stops requests. It does not describe an email, or any other notification, when spend is approaching that cap. The Usage and Cost API is the documented way to read the numbers. Its FAQ says usage and cost data typically appears within 5 minutes of API request completion, though delays might occasionally be longer. Cost report buckets are daily, bucket width 1d. Usage report buckets can be one minute, one hour, or one day. The page lists budget monitoring, setting up alerts for spending thresholds, as a cookbook use of that data. The Admin API for those endpoints is unavailable for individual accounts. Priority Tier costs use a different billing model and are left out of the cost endpoint. Usage for that tier is on the usage endpoint.
Send tokens and cost_usd from the job
A monthly organization total and one agent run are different clocks. Create one monitor for the job. When the run finishes, POST that monitor's ping URL with the tokens from the run and, when the runner produced one, the dollar cost. The ping API stores tokens as an integer, cost_usd as a number, and duration_ms as an integer. All three are optional. Any other key is ignored. The token in the URL is the credential. Keep it in an environment variable.
The 1234 and 0.012 below are examples, so the request shape is concrete. Replace them with this run's usage. Omit cost_usd when you do not have a dollar figure for the run. A made-up zero is still a successful ping, so it still moves the deadline, and the dollar window learns nothing from it.
curl -fsS -m 10 -X POST "$NIGHTSHIFT_PING_URL" \
-H "content-type: application/json" \
-d '{"tokens":1234,"cost_usd":0.012}'import os
import requests
URL = os.environ["NIGHTSHIFT_PING_URL"]
# Example figures. Replace them with this run's usage.
tokens = 1234
cost_usd = 0.012
requests.post(URL, json={"tokens": tokens, "cost_usd": cost_usd}, timeout=5)OpenAI's per-call counts are the usage fields in the help article above. Anthropic's Messages usage object uses input_tokens, output_tokens, and separate cache fields. Adding only input and output under-counts a cache-heavy run. The Claude Code post shows one way to sum the four fields that CLI returns. total_cost_usd on that JSON result is a client-side estimate. Post it as cost_usd when that is the figure you have, and treat the alert as an alert on the estimate.
POST the URL with /fail on the error path when you want the monitor marked down immediately. A success ping is what moves the deadline. Read the body of a 200. A paused monitor returns ignored set to paused, and a monitor over the plan quota returns ignored set to over_quota. In both cases the schedule stays where it was. Those responses are on the ping API page.
A hard cap and a spike over the baseline
Free stores tokens and cost_usd and draws them on the chart. Runaway alerts are sent on Pro and Team. The check runs when a success ping counts. The three windows below count success pings only, so /start and /fail stay out of the totals.
- Runs in the last 60 minutes.
- Tokens summed over the last 60 minutes.
- Dollars summed over the last 24 hours. The window ends at the ping and rolls with it.
A hard limit is a number you set: max runs per hour, max tokens per hour, or max USD per day. The alert fires when the window is greater than that number. A window that lands on the cap stays quiet. For example, a hard cap of $25 fires once the rolling 24 hours is above $25. That $25 is an example you would type in. It is not a default, and it is not a measured bill.
A baseline compares the current window with earlier ones. The multiplier defaults to 3, and a saved multiplier is an integer from 2 to 20. The baseline fires when there are at least three samples, the median is above zero, the current window is at least the floor (10 runs, 10,000 tokens, or $1), and the current window is greater than the multiplier times that median. A median of zero stays quiet.
Run and token samples are the previous complete hours, up to seven, skipping hours that ended before the monitor was created. An hour with no success pings is a zero in that list. Cost samples are the previous UTC days, up to seven. Each day is the sum of its hourly costs, and a day that ended before the monitor existed is left out. The current windows stay the rolling 60 minutes and the rolling 24 hours. A new monitor with fewer than three samples does not baseline-alert. When you already know a bad number, set the hard dollar cap.
For example, with the default 3× multiplier, a cost median of $0.20 and a current window of $0.80 clears the multiplier and still sits under the $1 floor, so the cost baseline stays quiet. Both of those amounts are examples.
After an alert, that signal stays quiet for one window, measured from the alert: an hour for runs and tokens, a day for cost. A later breach of the same signal inside that cooldown does not send another message. The three signals are separate, so a run alert and a cost alert can both leave from one ping. The message names the monitor, the observed total, and either the limit or the recent baseline.
The dollar alert follows cost_usd as the ping sent it. It is a signal on that number. The provider invoice remains the bill. One monitor per schedule. The free plan is 3 monitors, no card, with email when a ping is missing and when it returns. Create an account. Pro is $12/month for 25 monitors. Team is $39/month for 100 monitors and up to 10 people. Runaway alerts are those two plans. The docs include curl, Python, and Node next to the ping URL.