ElevenLabs credit burn, Nov 1–3: root cause

A CI suite ran paid ElevenLabs tests against the live Clara phone agents on every voice pull request, until the account was empty and customer calls failed at pickup.

Proposed — pending review · written 2026-11-03 · times in Central (UTC in brackets) · every number cites a PR, a file line or an ElevenLabs API read

On this page

TL;DR · Who added it and why · Cause chain · Timeline · Who did what · Cost · Which PRs burned it · Why no alarm · What stopped it · Guards (decision) · Not verified

TL;DR

18,407
paid test runs against live Clara agents
Oct 31 22:55Z → Nov 3 20:01Z
24.1M
ElevenLabs credits used
Oct 3–30, whole account: 3.2M
$3,068
ElevenLabs price on runs that used credits
$3,876 incl. runs at zero credits
4 times
the account hit empty
02:38Z for ~12 h; then 17:19, 18:54, 19:41Z

In one line: a free "does Clara still answer right" check, wired to every voice PR in July, became a paid one on Nov 2 when ElevenLabs retired the free endpoint and we ported to the paid one without checking the price. Nothing watched the ElevenLabs balance, so it ran until the account was empty.

Who added it and why

Added Jul 18 by #4103 (fede-propflow, a Claude session under Fede's account), "per Fede's directive: build the harness FIRST", with "nightly full sweep + change-scoped PR runs, soft (report-only)". It was meant to be cheap: "LLM tokens only — no TTS minutes" (voice-comprehensive.yml:4-8).

Made expensive Nov 2 07:10Z by #24185 (gera-propflow, a Claude session under Gera's account). ElevenLabs retired the free endpoint on Oct 31 (#24178); #24185 moved the suite to the paid agent-testing API. It maps every feature of the old API and never names a price: credit, cost, price, billing, usage, quota and spend appear nowhere in #24178, #24182, #24185 or their 34 comments and reviews.

Cause chain
1 · JUL 18 · #4103Suite runs on every voice PR push 2 · PATH LIST · #4931, #141077 globs: prompts, specialists, harness 3 · OCT 31 · #24178ElevenLabs retires the free endpoint 4 · NOV 2 07:10Z · #24185Port to paid API, no price check 5 · NO METERNo spend alarm; auto top-up refills Account empty → customer calls fail at pickup
Any one link missing stops the burn. Links 1–3 were harmless for three months: the old endpoint barely used credits (Oct 26, the day of the old weekly sweep, the whole account used 68,695 credits; the Nov 2 sweep alone used 1.28M). Link 4 made each PR push cost about 425 paid runs. Link 5 meant nobody saw it.
Timeline
0M 1M 2M 3M Oct 31 22Z: 108,787 credits, 48 runs Oct 31 23Z: 1,245,449 credits, 580 runs Nov 01 15Z: 857,849 credits, 424 runs Nov 02 06Z: 405,367 credits, 198 runs Nov 02 07Z: 690,818 credits, 325 runs Nov 02 09Z: 790,852 credits, 312 runs Nov 02 10Z: 492,011 credits, 257 runs Nov 02 14Z: 915,295 credits, 411 runs Nov 02 15Z: 686,784 credits, 347 runs Nov 02 16Z: 1,619,491 credits, 786 runs Nov 02 17Z: 1,339,471 credits, 643 runs Nov 02 18Z: 764,820 credits, 375 runs Nov 02 19Z: 2,337,202 credits, 1,275 runs Nov 02 20Z: 892,812 credits, 425 runs Nov 02 21Z: 1,659,027 credits, 805 runs Nov 02 22Z: 2,919,412 credits, 1,490 runs Nov 02 23Z: 1,379,658 credits, 622 runs Nov 03 00Z: 416,256 credits, 228 runs Nov 03 02Z: 857,210 credits, 850 runs Nov 03 02Z: 434 runs at zero credits (account empty) Nov 03 03Z: 1,284 runs at zero credits (account empty) Nov 03 05Z: 540 runs at zero credits (account empty) Nov 03 06Z: 744 runs at zero credits (account empty) Nov 03 07Z: 1,284 runs at zero credits (account empty) Nov 03 15Z: 36 credits, 2 runs Nov 03 16Z: 646,833 credits, 430 runs Nov 03 17Z: 1,235,805 credits, 1,021 runs Nov 03 17Z: 124 runs at zero credits (account empty) Nov 03 18Z: 1,117,300 credits, 1,049 runs Nov 03 18Z: 286 runs at zero credits (account empty) Nov 03 19Z: 659,546 credits, 1,622 runs Nov 03 19Z: 1,141 runs at zero credits (account empty) Nov 03 20Z: 40,957 credits, 30 runs empty Nov 1 00Z Nov 2 00Z Nov 3 00Z branch port merged empty Pro + top-ups
Credits per hour used by voice-harness:* test runs (blue). Red: runs that ran at zero credits because the account was empty. Source: GET /v1/convai/test-invocations, every row from Oct 31 to Nov 3 20:01Z.
When (CT)UTCWhat happenedSource
Jul 18Jul 19 01:41Suite added with nightly + per-PR runs, "soft (report-only)"#4103
Jul 3006:55Two app folders dropped from the PR trigger to save runner minutes (53 runs that day)#4931
Sep 29–30 Nightly sweep moves to Mondays; PR trigger folded into the main CI workflow, same 7 paths#13872, #14107
Oct 207:19Fede: "the live ElevenLabs tests are no longer necessary". Deletes 11 live test files; this suite is not a test file, so it stays#15270
Oct 31 4:37 PM21:37Free simulate endpoint answers 410 "endpoint_sunset"#24178
Oct 31 5:55 PM22:55First paid run, from #24185's own branch CIinvocations
Nov 1 9:17 AM15:17#24185 branch run: 424 paid runs in 32 min. Its branch ran the suite 5 times (~3.3M credits)run 41320340373
Nov 2 1:10 AM07:10#24185 merged. From here every voice PR push runs ~425 paid tests#24185
Nov 2 3:33 AM09:33Monday sweep: 569 runs, 1.28M creditsrun 41421589799
Nov 2 4 PM22:00Peak hour: 1,490 runs, 2.92M creditsinvocations
Nov 2 8:38 PMNov 3 02:38Account empty. Runs keep going at zero credits until 07:50Z (4,286 runs)invocations
Nov 3 12:23 AM06:23A robot call finds every Clara call dead#24877 body
5:12 AM11:12Health row reads "free plan, 10,000 of 10,000"#24844 body
8:37 AM14:37Pro plan period starts (derived: next reset is Dec 3 14:37:32Z)/v1/user/subscription
9:48 AM15:48Paid runs resume on PR pushesinvocations
10:48 AM16:48First ElevenLabs credit alarm lands#24877
11:19 AM – 1:57 PM17:19 / 18:54 / 19:41Empty three more times; usage top-ups lift the limit 600,000 → 4,236,360invocations, subscription
2:01 PM20:01:36Last paid runinvocations
2:04 PM20:04:30PR lane switched off#24933
Who did what
PRAccountMergedIntent, in its own words
#4103fede-propflowJul 19"build the harness FIRST… CI: nightly full sweep + change-scoped PR runs, soft (report-only) until the gate set is proven green"
#4931fede-propflowJul 30"stop voice-comprehensive firing on app-side voice paths it cannot observe" (runner minutes)
#13872fede-propflowSep 30Nightly to weekly: "30 9 * * * → 30 9 * * 1 Mon"
#14107fede-propflowSep 30"Folds the pull_request arms… into ci.yml lanes… lane globs verbatim"
#15270fede-propflowOct 2"Fede ruled… the live ElevenLabs tests are no longer necessary" (test files only)
#24182gera-propflowOct 31"a sunset simulate endpoint fails the suite once, not per scenario"
#24185gera-propflowNov 2"Ports the voice-comprehensive / simulate job… to the replacement agent-testing endpoints." No price named
#24877gera-propflowNov 3"page #alerts when the ElevenLabs account runs low, runs out, drops to free"
#24933fede-propflowNov 3"switch the voice-comprehensive PR lane off"

Correction: the cron comment and #24933's body credit the lane to #13737. #13737 only moved jobs to cheaper machines; the weekly move was #13872, the fold into the main CI workflow #14107.

Both accounts are used by Claude sessions; the PR bodies end "Generated with Claude Code".

Cost
SliceRunsCreditsElevenLabs price
Whole burn, Oct 31 22:55Z – Nov 3 20:01Z18,40724.08M$3,876
  runs that used credits12,57024.08M$3,068
  runs at zero credits (account empty)5,8370$807 *
Before the account emptied (old plan)9,96720.38M$2,447
On the new Pro plan, from 14:37Z4,1543.70M$819
For scale: whole account, Oct 3–30 (calls and tests) 3.24M 
  • Where the 20.4M came from. On Aug 2 the account ran on a 12-month startup grant, 33.4M credits a year (src/lib/domain/spend/roster.ts:103-114). By 11:12Z Nov 3 it read "free plan". Most likely the burn used up the grant that was meant to last to mid-2027. Inference; confirm on the ElevenLabs billing page.
  • Cash since then: Pro plan (next invoice $104.10 per the API) plus six usage top-ups of 606,060 credits each (600,000 → 4,236,360; derived). The top-up price is not readable through the API.
  • * ElevenLabs puts a price on runs that used zero credits. Whether that was billed is not verified.
  • The earlier "15,719 runs, $3,381" was a partial pull (stopped 18:40Z, included 49 manual tests). The full pull adds 2,109 runs after 18:40Z and 628 on Oct 31.
By agent and by test layer
Live agentRunsCredits
Clara — Leasing7,75313.30M
Clara — Triage4,6115.66M
Clara — Maintenance2,2272.44M
Clara — Resident Services8830.62M
Clara — Leasing [WILLOWS]3520.65M
Clara — Unknown Caller4450.51M
Vendor Calling, Renewal, Coworker Line, Turnover Intake, Renewal Outbound, Handyman2,1360.90M
Layer (scenario file)RunsCredits
regression (one scenario per past bug)11,03015.51M
real (patterns from real calls)7,2258.20M
adversarial + synthetic + architecture1440.37M

Largest name groups: leasing- 3,129 runs, real- 2,714, reg- 2,101, numbered bug ids (13380-, 12342-, …) 2,048, ws- 1,546, tool- 611. Tools were mocked (#24185: an unmocked tool raises an error), so no customer records were written; the harm was the shared credit pool.

Which PRs burned it
AccountPRsPaid CI jobsRunsCreditsPrice
gera-propflow sessions1856~15,616~22.11M~$3,362
fede-propflow sessions47~2,221~0.69M~$360
Monday sweep (cron)—15691.28M$154

Method: 1,998 pull-request CI runs Oct 31–Nov 3 were listed; 105 had a voice-comprehensive / simulate job, plus the Monday sweep; 64 of those 106 jobs ran paid tests (the rest failed fast on the retired endpoint, before #24185 merged, or were cancelled). Each test run was matched to the job running when it was created. 6,670 of 18,407 fell inside two overlapping jobs and were split evenly, so per-PR numbers are approximate. Two runs matched no job.

All 23 sources, by price
PRAccountTitlePaid/all jobsRunsCreditsPrice
#24185gera-propflowfix(voice-harness): port simulate job to ElevenLabs agent-…5/51,5753.31M$397
#24516gera-propflowfix(voice): Triage hears Maintenance-off only from the sta…4/41,3082.63M$316
#24702gera-propflowfix(coworker-line): a staff caller reporting a hazard page…4/41,7430.86M$286
#24524gera-propflowfeat(bench): robot calls and robot texts refuse the Willow…4/51,0632.09M$251
#24899gera-propflowfeat(voice): the staff phone line takes a repair request (…5/51,2181.14M$250
#24886gera-propflowfix(triage): a property manager walking a unit reaches Tur…5/51,1031.43M$248
#24658gera-propflowCoworker Line on at every company: retire the per-company …3/31,2810.88M$229
#24352gera-propflowfix(harness): bench scripts use the canonical test-propert…3/78941.84M$221
#24636gera-propflowfeat(modes): a declared test is the DRAFT row; every actin…3/37901.61M$194
#24732fede-propflowrefactor(scope): old company and building answers delegate…3/31,2470.00M$182
—cronweekly Monday sweep (main)1/15691.28M$154
#24619gera-propflowfix(voice): a company-listed door that won't lock conferen…3/36491.28M$153
#24485gera-propflowrefactor(site): normalizePhoneE164's importers import @pro…2/25531.18M$141
#24807gera-propflowfix(voice): an active leak after hours conferences in the …2/28560.00M$123
#24617gera-propflowfeat(modes): "this is a test" from a teammate phone makes …2/24640.93M$112
#24914fede-propflowfix(voice): a closed office removes the leasing dial befor…2/24840.51M$104
#24603gera-propflowfix(tours): a building named as unit_number reads that bui…2/24250.87M$104
#24544gera-propflowfix(send-gate): a command-line run texts, calls or mails f…1/14450.81M$98
#24436gera-propflowfix(voice): no old-language word before the switch back to…3/43920.80M$96
#24940gera-propflowfix(voice-harness): refuse any shape or property that is n…2/24200.29M$77
#24935gera-propflowfix(voice): Clara never announces a connect nobody can tak…3/44370.16M$65
#24946fede-propflowfix(tours): another home's tour at the same time is a clas…1/24060.17M$63
#24928fede-propflowfix(voice): a name alone is an introduction, not an ask fo…1/1840.01M$12

Gera's sessions carried most of it because their open work (Coworker Line, robot-call guards, triage) touched voice prompts all day Nov 2–3. Nobody chose to run the suite; the lane fired on its own. #24732 and #24807 ran in the empty window, so their runs used zero credits.

Why no alarm
  • No meter existed. Before Nov 3, nothing in the repo read the ElevenLabs balance (main at Nov 1 reads v1/user/subscription only in a comment in the spend roster). No scheduled job on the Mac mini reads ElevenLabs. The spend page showed ElevenLabs as a fixed "$0, grant pays" line (roster.ts:93-114).
  • The suite looked free. Its header still says "LLM tokens only".
  • The lane is report-only. It never blocked a merge, so nobody looked.
  • The morning read was wrong. The Nov 3 voice-minutes rule blamed test call minutes for the 06:23Z outage. Session 009 looked at minutes, not credits. That was a miss.
  • The new alarm (#24877) checks what is left, not how fast it goes. It warns under 10% left, and not at all when the plan can extend (elevenlabs-health.ts:46). Top-ups refill the limit, so a burn can stay above 10%.
What stopped it
UTC, Nov 3ActionEffect
18:56–20:01Cancelled CI runs 41697767897, 41696636947, 41707250128, 41707804640Partly undone. The "CI follow-ups" rerun-if-runner-killed job and new pushes restarted them (41696636947 ran again 19:47–20:01)
~19:52 → 20:04:57CI's ELEVENLABS_API_KEY secret replaced, then restoredNew jobs could not reach ElevenLabs
20:00–20:03Terminated 4 CI machines running the job (i-0cebf420b6e6802ad, i-0fe1ee27a7b8c9c89, i-0b8c098c1d1224216, i-00e70705abc898023)Running jobs died. Last paid run 20:01:36
20:04:30#24933 merged: PR lane off (if: false && …, ci.yml:6651)No new PR runs
Guards — pick one
  1. A. Meter and cap (recommended). The driver refuses to start if planned tests × ~2,000 credits exceed a cap (say 50,000 a run) and stops at it. The health cron alarms on burn rate (credits per hour vs. a normal day), not only on % left, overage plans included. An ElevenLabs line goes into the CI spend report. Pause the Monday sweep until the cap ships.
    Keeps a weekly signal; makes any repeat cost at most one capped run.
  2. B. Separate account. The suite runs only on throwaway clone agents in a separate ElevenLabs workspace with a hard prepaid ceiling. The production key leaves CI.
    Strongest wall; costs a second account and agent-cloning setup.
  3. C. Manual only. Delete the Monday cron too. The suite runs only on manual dispatch; voice changes are proven with the fastlane throwaway clone, one scenario at a time.
    Zero standing spend; loses the weekly regression signal.

Recommendation: A, with the Monday sweep paused today. Any option also fixes the stale "LLM tokens only" header, and adds one line to the PR checklist: a port to a new paid API names its price.

Not verified
  • Whether the account fell to free because the grant ran out, and what the top-ups cost in cash. Needs the ElevenLabs billing page.
  • Whether the $807 priced on zero-credit runs was billed.
  • The key swap start (~19:52Z) and the run cancels come from session 009's own record; GitHub shows only the restore (20:04:57Z).
  • Whether #24877's alarm fired during the 17–20Z empties; #alerts was not read.
  • Per-PR splits are approximate (overlapping jobs split evenly).
PropFlow Docs