August 2026 · Quota watch series
How to Detect When an API Key Expires or Silently Fails
The answer: make one small authenticated call with the key on a schedule, against the vendor’s cheapest endpoint, and classify the response instead of just checking for “not 200”. A 401 or 403 means the key itself is dead. A 429 or an empty usage counter means the key is fine but the budget behind it is gone. Anything else that answers but no longer looks like the response you expect is its own alarm. You need the scheduled call because nothing else will tell you: vendors email an expiry notice to whoever created the key, if they send one at all, and most application code swallows auth errors inside retry loops until someone asks why yesterday’s data is missing.
Why a dead key never announces itself
An expired key does not throw an alarm anywhere you look. The job that used it often exits green: the HTTP client retried, got 401 three times, logged a warning nobody reads, and returned an empty result that the rest of the pipeline happily processed. Dashboards render yesterday’s cache. The one email the vendor sent went to the inbox of a person who set the key up two teams ago. By the time the failure is visible, it is visible as missing data, and you are debugging the pipeline instead of rotating a credential.
The manual route: a canary call and a response you actually read
Every serious vendor has one endpoint that is cheap or free to call and requires real authentication. That is your canary. Three examples we use in our own probes, with the real field names:
GitHub: /rate_limit is authenticated, free, and does not consume quota. As a bonus, if the token has an expiration date, every response carries it in the github-authentication-token-expiration header, which is the rare advance signal in this space:
SerpAPI: https://serpapi.com/account?api_key=KEY returns plan_searches_left, this_month_usage, and extra_credits. A dead key gets a 401. A live key with plan_searches_left plus extra_credits at zero is the silent-failure case: every search from here on fails while the key itself is perfectly valid.
OpenAI: a GET to /v1/models validates the key without spending a token. The trap here is 429: it can mean a rate limit, which passes, or it can carry the error code insufficient_quota in the body, which means your key works and your account cannot pay. Those need opposite responses from you, and only the body tells them apart.
The mistake in most homemade checkers: collapsing everything into “up” or “down”. A key check has at least four distinct outcomes: the key is dead (401, and on some vendors 403), the budget is exhausted, you are temporarily rate limited, or the response no longer has the fields your parser expects. A checker that pages you to rotate a healthy key on a rate-limit blip trains you to ignore it, and one that reports “up” on an empty quota misses the exact failure you built it for. Building our probes, GitHub’s 403 took us a header to disambiguate: x-ratelimit-remaining at zero means rate limit, budget left means the token lost a permission.
Wrap those calls in a daily cron job that posts anything other than a clean pass to the channel where your incidents live, and you have a working manual monitor for one or two keys.
The automated route: one JSON block per key
Datasource Pulse runs that same classification as a service: one block per credential, $0.02 per check, no subscription. A key checked daily is about $0.61 a month.
The four outcomes above come back as stable verdict strings: a dead or revoked key is state: failing with dead_token, an empty budget is quota_exhausted, a temporary throttle is rate_limited, and a response that stopped matching the vendor’s own schema is unexpected_response. Alerts fire on state transitions, not on every run, so a key that is down for six hours produces one alert and one recovery notice when it comes back, not seventy identical pages. One honest scope note: this is a dead man’s switch. It fires when a key stops working, not days before a dated expiry. Where a vendor offers an advance signal, like GitHub’s expiration header, read that too; for the majority of vendors that expire keys with no date and no warning, the switch is all there is.
Which route should you take?
For one key at one vendor, write the cron script; the endpoints above are stable and the classification logic is an afternoon of work to get right. The automated route earns its keep when the key count grows: five keys across three vendors means five response formats, five sets of edge cases like the 403 and 429 ambiguities above, and a recovery-notice problem your one-shot script does not solve. One daily run covering every credential, with the same verdict strings across vendors, is the point where buying beats building.
Whichever route you take, trip the alarm once on purpose: run a check with a scrambled key, watch dead_token land where you expect it, then put the real key back. An alert you have never seen fire is a guess, not a monitor.
Datasource Pulse watches the data sources your product depends on: credentials, quotas, and scraper output quality. One alert when something degrades, one notice when it recovers. 35+ vendors are pre-wired as a head start, and any endpoint the list is missing is one generic_http block away.