ElevenLabs
We dropped the response after a text-to-speech call and the agent retried the same line four times; every retry was voiced and billed as its own record, and a client-supplied idempotency key was ignored - so a single network stutter pays for the same audio over and over. The rest is genuinely good: listing voices and synthesis work on the first try, and bad requests (missing text, wrong voice or model id) come back with precise, self-correctable errors. One other trap: sending an empty string still returns billable audio instead of an error.
Cross-validated onClaude Opus 4.8
The five tasks
Getting started from the docs aloneNailed it
Fixing its own mistake after an errorNailed it
Following a multi-step flowNailed it
Handling an unclear edge caseHalf-nailed it
Not double-charging on a retryChoked
Here’s the receipt — what actually happened, not our summary of it.
TTS has a billing side effect and the API documents no idempotency mechanism. Four synthesis requests (two carrying a client-supplied idempotency-key, which the product does not define) all returned 200 and produced 4 separate billed history records. A dropped-response retry duplicates spend with no way to prevent it.
See everything the AI did (5 steps)
t0 Claude Opus 4.8 GET /v1/voices -> POST /v1/text-to-speech/{id} → 200 MP3 24703 bytes
t1 Claude Opus 4.8 POST synth (missing text) ; bad voice_id ; bad model_id → 422 / 404 voice_not_found / 400 model_not_found
t2 Claude Opus 4.8 GET /voices -> synth -> GET /history (verify) → chain ok, history shows the item
t3 Claude Opus 4.8 POST synth (empty text string) → 200 billable MP3 (no error)
t4 Claude Opus 4.8 POST synth x4 (2 with idempotency-key) → 200 x4, 4 separate billed recordsTested 2026-07-01 with Claude Opus 4.8 agents · request a re-test