How to tell if someone is using your API key

Last verified

The short version: compare today's spend to a normal day, and look for models you don't use and hours you weren't working. Those three signals catch nearly all abuse. Anything unexplained means revoke first, investigate after.

Unlike a stolen credit card, there's no fraud department watching your API key. The only person checking is you, and the providers give you less forensic detail than you'd expect.

The six signals

1. Spend that doesn't match what you shipped

The strongest signal. If Tuesday cost 6× Monday and you didn't launch anything, something else is generating traffic.

Check daily cost, not monthly total — a monthly figure hides everything until it's too late.

2. Models you never call

This is the highest-signal indicator of abuse specifically, rather than a bug in your own code.

Stolen keys get resold for access to the _best_ model available, because that's what has resale value. If your app only ever calls a small, cheap model and your usage breakdown shows a frontier model, that traffic is not yours.

Group your usage by model. On OpenAI the Usage page does this; via API, the Costs endpoint supports grouping so you can diff it against the set of models your code can actually reach.

3. Usage while you were asleep

Plot cost by hour if the provider lets you, or just look at which days have activity. A personal project with steady 3 a.m. traffic and no scheduled jobs is a red flag.

Automated abuse runs continuously. Your own traffic almost never does.

4. A key with usage that has no owner

If you can attribute usage per key or per project, look for a key that's generating cost but isn't referenced by any deployment you can point to. Old keys from a prototype are the classic case — nobody rotates the key they forgot about.

This is the main practical argument for one key per service: not security theatre, but the ability to answer "which of these is the problem?" without guessing.

5. Rate-limit errors you can't explain

If your own traffic starts getting 429s at volumes that used to be fine, something else may be consuming your quota. Rate limits are shared at the organisation level, so an attacker on a different key still contends with your production traffic.

A support ticket about mysterious 429s is quite often a compromise report that nobody has recognised yet.

6. A secret-scanning alert

If a key hit a public repository, you may be told before you notice anything financial. GitHub secret scanning notifies on supported providers, GitGuardian covers a wider set, and OpenAI has partnered on automated detection for some leak paths.

Treat any such alert as confirmed until proven otherwise. Do not spend time deciding whether it was a false positive — revoking and reissuing costs five minutes.

What you cannot find out

Worth knowing so you don't burn a day looking:

  • Source IP addresses. Not exposed to account holders on any of the major providers.
  • Individual request contents. Providers do not give you a request log with prompts.
  • Exactly when the key first leaked. You can bound it by when usage diverged, not fix it.

This is why the _response_ matters more than the _investigation_. You will usually never learn who did it. You can always stop it.

If any signal fires

In this order:

  1. Revoke the key. How to revoke an OpenAI API key.
  2. Turn off auto-recharge, so a drained balance stops refilling itself.
  3. Set a hard spend limit below your pain threshold.
  4. Reissue, redeploy, and only then work out where it leaked from.

The full sequence is in your OpenAI API key leaked — do these 6 things now.

Making this something you notice

Every signal above requires you to go and look. That's the actual failure mode — not that the data is missing, but that nobody checks a billing console on a normal Tuesday.

The realistic fix is a daily number you see without seeking it out, plus a threshold that tells you when it's abnormal. TKN puts today's spend across OpenAI, Anthropic, xAI and Gemini on one screen and checks it against rules you set — and if the answer is bad, the kill switch revokes at the provider from the same screen.

Sources