AI Agent API Calls Increasing but No Revenue: Triage
When AI agent API calls are increasing but there is no revenue, the cause is almost always ordinary: a payment provider hold, a failing webhook, a swapped or expired key, or a retry loop. Agents have no motive, so check Stripe, webhooks, then git.
- Agents do not sabotage: each run only sees its prompt, files and tools, so a sudden break comes from changed code, config, keys, model behaviour or a provider-side hold.
- First confirm in the Stripe, PayPal or Paddle dashboard that money is really failing before you touch any code.
- Check webhook event deliveries for 4xx/5xx errors, a wrong signing secret, a body altered before signature verification or a disabled endpoint, and use git diff against the last good commit to find agent edits.
- Rising calls with flat revenue usually mean a retry loop or a job that stopped deduplicating, so cap iterations, tokens and monthly spend.
- A scheduled synthetic test purchase plus alerts on revenue, webhook failures and cost per transaction would catch this within hours.
Why are my AI agent API calls going up while revenue is flat?
An LLM agent has no motive and no memory of your success. Each run sees only its prompt, context window, files and tool outputs. Telling it that your product is doing well cannot make it act against you.
What does change behaviour is concrete: edited files, a different context, a model or version update, or a tool that started failing. Rising API usage with flat revenue is the classic fingerprint of a retry loop, a polling job, an agent re-running a task, or a failing step that is retried endlessly.
So treat this as an incident with a technical cause. The runbook below takes about 30 minutes if you follow the order, because it checks the cheapest and most common causes first.
How do I confirm money is really failing?
Many cases of "payments stopped" are really unreported revenue or a provider-side hold. Do this before reading any code, since it decides whether you have a code problem at all.
- Open the Stripe, PayPal or Paddle dashboard and look at the payments list for the last 7 days. Compare failed, succeeded and refunded counts to the previous week.
- Look for account-level banners: a verification or identity request, a restricted account, paused payouts, or a reserve placed on your balance.
- Check Disputes for a spike. A wave of chargebacks can trigger holds.
- Check whether customers are paying but your app does not record it. If the provider shows successes and your database shows none, the fault is in your webhook handling, not in payments.
- Check for lapsed cards on your own account (provider fees, subscriptions to hosting) and for an expired or rolled API key.
How do I check whether my Stripe webhook is broken?
In the Stripe dashboard go to Developers > Webhooks, open your endpoint and read the event deliveries list. Each delivery shows the HTTP status your server returned.
Match what you see to the cause. A 400 on every event usually means your handler is rejecting the request after signature verification fails, because construct_event raised an error. The common reasons are a wrong signing secret (whsec_...), a secret from the test-mode endpoint used in live mode, or a framework or middleware that parses and re-serialises the JSON so the raw bytes no longer match the signature. Verify against the raw request body, not a parsed object.
A 404 means the route or URL changed. A 500 means your handler crashes. Repeated failures over several days can lead Stripe to disable the endpoint, so check its status too.
Also check idempotency. Stripe retries events, and may deliver the same event more than once, so the handler must record processed event IDs. The order of operations matters: if you fulfil first and record afterwards, a crash between the two steps leaves the order fulfilled but not recorded, and the retry fulfils it a second time.
The fix is to make handling and recording atomic. Write the event ID and your database changes in a single transaction, so either both commit or neither does. For side effects that cannot be rolled back, such as emails or shipments, write an idempotency record with a status (processing, then done) before fulfilling, pass a stable idempotency key to downstream calls, and return a 500 on failure so Stripe retries.
event = stripe.Webhook.construct_event(
request.get_data(), # raw bytes, not parsed JSON
sig_header,
os.environ["STRIPE_WEBHOOK_SECRET"],
)
with db.transaction(): # one atomic unit: record + fulfil
# INSERT ... ON CONFLICT DO NOTHING; False if the ID already exists
if not claim_event(event["id"], status="processing"):
return "", 200 # duplicate delivery, acknowledge it
handle(event) # writes the order in the same transaction
set_status(event["id"], "done")
# any exception rolls everything back and returns 500, so Stripe retries
return "", 200How do I find what the agent changed?
Version control is the source of truth. If the project is not in git, run git init and commit the current state now, so the next change is at least visible. Then use the history of the files that matter: checkout, webhook, auth and env config.
Look specifically for edits to price or product IDs, the API version, environment variable names, redirect or success URLs, rate limits, and the webhook route. Also check dependency files for upgrades.
git log --since="10 days ago" --stat --oneline
git diff <last-good-commit> HEAD -- app/checkout app/webhooks config
git blame -L 1,80 app/webhooks/stripe.py
git log -p --since="10 days ago" -- .env.example package.json requirements.txt
# restore one file safely instead of resetting everything:
git restore --source=<last-good-commit> -- app/webhooks/stripe.pyWhere are the extra AI agent API calls coming from?
Open your LLM or API provider's usage page and break usage down per key, per endpoint and per hour. A step change at a specific hour points to a deploy or a cron change. A steady climb points to a queue that is growing.
Then look at response codes. Many 429s (rate limit), 401s (bad key) or 5xx responses next to repeated identical requests mean a client retrying without backoff. Check your cron, queue or scheduler for a job that stopped deduplicating, so the same item is processed again every run.
Put a hard ceiling on every loop so a failure costs cents instead of hundreds of dollars.
MAX_STEPS, MAX_TOKENS = 8, 40_000
used = 0
for step in range(MAX_STEPS):
resp = call_model(messages, max_tokens=2_000)
used += resp.usage.total_tokens
if resp.done or used > MAX_TOKENS:
break
else:
alert("agent hit step limit")
# retries: exponential backoff, max 3 attempts, then fail loudlyWhich silent breakages should I check, and what do they look like?
These are the usual suspects. Many produce no visible error, which is why the break goes unnoticed for days.
Data and labeling products have one more failure mode: schema or format drift. If a field or label is renamed, or a model changes its output format, validation fails and the product can look empty or invalid to buyers, so deliveries and purchases stop. Add schema validation and a sample check on every output batch.
| Symptom | Likely cause | Where to look | Fix |
|---|---|---|---|
| Provider shows no failures, no new payments | Checkout broken or traffic lost | Live test purchase, redirect URLs, domain and SSL expiry | Restore the URL or cert, renew the domain |
| Payments succeed, orders not fulfilled | Webhook 400/404/500 or disabled endpoint | Developers > Webhooks > event deliveries | Correct the signing secret, raw-body handling or route, resend failed events |
| 401 errors, calls climbing | Expired or rotated key | Provider usage logs, deploy env | Issue a new key, update the environment |
| Test charges only | Test and live keys swapped | Key prefix sk_test vs sk_live, mode toggle | Use live keys in production |
| Everything broke after a deploy | .env overwritten or API version bumped | git diff on config, dependency files | Restore config, pin the versions |
| Output rejected by buyers or parser | Schema or model format drift | Validation logs, sample outputs | Add schema validation, pin the model version |
| Calls up 10x, errors 429/5xx | Retry loop or duplicate jobs | Usage per key, endpoint and hour; cron or queue | Backoff, idempotency keys, loop caps |
How do I put guardrails on AI agents so this cannot repeat silently?
Assume an agent will eventually make a wrong edit, and limit the blast radius. Give it the least privilege that still lets it work, require review, and make failures loud.
Then monitor outcomes rather than activity. A synthetic purchase that runs on a schedule and alerts on failure would have caught this within hours, and a daily cost-per-successful-transaction number shows AI agent API calls decoupling from revenue straight away.
| Control | How to set it up |
|---|---|
| Least-privilege keys | Use Stripe restricted keys with only the permissions needed, read-only where possible; never hand agents the full secret key |
| Branches and review | Agents commit to branches or pull requests, you review the diff, and there are no direct production deploys |
| Protected files | Use CODEOWNERS or branch protection on checkout, webhook, auth and config paths |
| Spend caps | Set a monthly budget and alert thresholds on the LLM provider, plus per-run step and token limits |
| Environment separation | Keep staging in test mode with its own keys and webhook secret |
| Synthetic test | A scheduled test purchase (test mode on staging, or a refunded live one) that pages you on failure |
| Alerts | Revenue per day below a threshold, webhook failure rate, error rate, and cost per transaction above a limit |
What mistakes make these incidents worse?
Blaming the AI before checking the payment provider is the most common one, and it wastes the first hour on the wrong layer. Pleading or accusing the agent in a prompt only adds noise to its context and fixes nothing.
The others are structural: letting agents edit production without version control, sharing full-access secret keys, having no spend limits, and changing several things at once while debugging. Change one thing, re-test the flow, and record the result, or you will not know which change worked.
Common questions
Can an AI agent break my payments on purpose?
No. A model has no goals between runs and cannot hold a grudge or retaliate. It can make wrong edits, misread instructions or loop on errors, and these have ordinary traces in git, logs and provider dashboards.
Why did my AI coding agent change my code without asking?
It acts on the task and context it was given, and a broad request such as "fix the checkout error" can lead it to edit related files. Tight scopes, branch-only access, protected paths and a required diff review keep edits visible and reversible.
How do I stop an AI agent running up API costs?
Revoke or pause the key, then set a monthly budget and alerts at the provider. In code, add a maximum step count, a max_tokens limit, and retries with backoff capped at about three attempts.
How do I debug an AI agent pipeline?
Log each step's input, output, status code, token count and run ID, then replay the failing run on a single item. Compare against the last good run, and change one variable at a time.
Can I resend Stripe events that my webhook missed?
Yes. Fix the endpoint first, then resend failed events from the event delivery view in the dashboard, or fetch recent events through the Events API and process them. Your handler must be idempotent, with the event ID recorded atomically alongside fulfilment, so replays do not double-fulfil orders.