PlayHTShut down: December 31, 2025

PlayHT shut down: move your PlayHT API calls to Cartesia

Code that still calls api.play.ht now fails at the DNS lookup, so every PlayHT request in your codebase needs a new target.

What happened to PlayHT

The dated events that ended the PlayHT API, each linked to its source.

Meta confirms it acquired PlayAI

Meta bought the company behind PlayHT and did not disclose terms. The team moved to Meta.

Biometric Update

The PlayHT API goes offline

API calls stopped working about two weeks after the acquisition, months before the platform's announced end date.

Inworld, migrating from PlayHT

The platform closes

Murf's transition guide quotes the date the platform would shut down completely.

Murf, PlayAI transition guide

Migrate from PlayHT with your coding agent

Paste this into Claude Code, Cursor or Codex in the repo that calls PlayHT. It carries the field mapping, the Cartesia request and a rollout that keeps PlayHT behind a flag until you switch.

10 fields mapped, with a rollback plan

Prompt

Connect MCP
Move this codebase from PlayHT to Cartesia for text to speech. Keep PlayHT working behind a flag until I switch over.

Shut down on December 31, 2025. Meta confirmed it had acquired PlayAI, PlayHT's parent, on July 12, 2025, and the API went offline around July 26, 2025. Inworld and Murf both give December 31, 2025 as the date the platform closed for good. We found no shutdown notice from PlayHT itself. On November 5, 2026 (UTC), `play.ht` and `api.play.ht` no longer resolved.

July 12, 2025: Meta confirms it acquired PlayAI. Meta bought the company behind PlayHT and did not disclose terms. The team moved to Meta. (https://www.biometricupdate.com/202507/meta-acquires-voice-generator-startup-playai)

July 26, 2025: The PlayHT API goes offline. API calls stopped working about two weeks after the acquisition, months before the platform's announced end date. (https://inworld.ai/resources/migrate-from-playht)

## 1. Find the calls
Search for `api.play.ht`, `PLAYHT_API_KEY` or `PLAYHT_USER_ID`. The request to replace is `POST https://api.play.ht/api/v2/tts/stream`. List every call site before you edit anything.

## 2. Target
- Request: `POST https://api.cartesia.ai/tts/bytes`
- Model: `model_id: "sonic-3.6"`
- Headers: `X-API-Key` read from the `CARTESIA_API_KEY` environment variable, and `Cartesia-Version: 2026-08-14`
- Auth swap: PlayHT sends the key in `AUTHORIZATION: Bearer` secret key plus an `X-USER-ID` header. Replace it with `X-API-Key` from `CARTESIA_API_KEY` on the Cartesia path only, and keep PlayHT's key for the PlayHT path. Both values are dead now. Remove them from your secrets store.
- Add `CARTESIA_API_KEY` wherever the project documents its environment (`.env.example`, README, deploy config). Never hardcode the key.
- Request size: PlayHT caps a request at 2,000 characters per request; 20,000 on Play3.0-mini. Cartesia publishes no per-request maximum, so keep any chunking the code already does and split at sentence boundaries; for long text, stream over the Cartesia TTS WebSocket.
- Voice IDs don't carry over. Keep each voice ID in one named constant or config value, put a placeholder where each PlayHT voice was, and list them for me so I can pick replacements at https://www.cartesia.ai/voices.
- Suggested starting points to put in those placeholders, for me to confirm by ear: Podcast or audiobook narrator → `a33f7a4c-100f-41cf-a1fd-5822e8fc253f` (Lauren - Lively Narrator); Support line or IVR prompt → `f786b574-daa5-4673-aa0c-cbe3e8534c02` (Katie - Friendly Fixer); Measured male voice for explainers → `98a34ef2-2140-4c28-9c71-663dc4dd7022` (Clyde - Calm Narrator).

## 3. Field mapping, PlayHT → Cartesia
- `POST https://api.play.ht/api/v2/tts/stream` → `POST /tts/bytes`
- `AUTHORIZATION: Bearer <secret key>` and `X-USER-ID` → `X-API-Key` and `Cartesia-Version: 2026-08-14`. Delete the user ID from your config. Cartesia has no equivalent.
- `voice`: an `s3://` manifest URL → `voice`: `{"id": "<voice id>"}`. PlayHT voices and clones went offline with the service. Pick a library voice, or clone again from your original recording.
- `voice_engine`: `PlayDialog`, `Play3.0-mini`, `PlayHT2.0` and others → `model_id`: `sonic-3.6`
- `text` (2,000 characters; 20,000 on `Play3.0-mini`) → `transcript`
- `language`: a lowercase name such as `english` → `language`: a code such as `en` or `en-GB`
- `output_format`: `mp3`, `wav` or `mulaw` → `output_format` object: `container` `mp3`, `wav` or `raw`, with `pcm_mulaw` for mu-law
- `sample_rate` (8000 to 48000) → `output_format.sample_rate` (8000 to 48000)
- `speed` (0.1 to 5) → `generation_config.speed` (0.6 to 1.5). Anything slower than 0.6 or faster than 1.5 has to be clamped.
- `emotion` → `generation_config.emotion`. The two vendors use different emotion names. Map each one by ear.

## 4. PlayHT fields with no Cartesia equivalent
- `output_format`: `ogg` or `flac`. What to do: Generate `mp3` or PCM, then convert with ffmpeg or your encoder of choice.
- `quality`, `temperature`, `seed`, `voice_guidance`, `style_guidance`, `text_guidance`. What to do: Drop them.
- `voice_2`, `turn_prefix`, `turn_prefix_2` (two-speaker PlayDialog). What to do: Synthesize each speaker's turns with that speaker's voice and join the clips in order.

## 5. Reference request
Match the language and HTTP client the codebase already uses. This is the same request in Python:
```python
import os
import requests

text = "Episode twelve. Today we talk to a beekeeper about the first warm week of spring."
VOICE_ID = "6ccbfb76-1fc6-48f7-b71d-91ac6298247b"  # from /voices

response = requests.post(
    "https://api.cartesia.ai/tts/bytes",
    headers={
        "X-API-Key": os.environ["CARTESIA_API_KEY"],
        "Cartesia-Version": "2026-08-14",
    },
    json={
        "model_id": "sonic-3.6",
        "transcript": text,
        "voice": {"id": VOICE_ID},
        "language": "en",
        "output_format": {
            "container": "mp3",
            "sample_rate": 44100,
            "bit_rate": 128000,
        },
    },
)
response.raise_for_status()
open("out.mp3", "wb").write(response.content)
```

## 6. Roll out
1. Choose PlayHT or Cartesia per request from one config flag, defaulting to PlayHT.
2. Run the same scripts through both and save the clips side by side for me to listen to. Check that the container, encoding and sample rate match what downstream code expects.
3. Leave the PlayHT client, call and key in place so rollback is flipping the flag. Don't delete them in this change.
4. Run the existing tests, and add one that checks the Cartesia request body.

## Docs
- PlayHT stream API reference (docs.play.ht, still online): https://docs.play.ht/reference/api-generate-tts-audio-stream
- Inworld, migrating from PlayHT: https://inworld.ai/resources/migrate-from-playht
- Murf, PlayAI transition guide: https://murf.ai/blog/play-ai-transition-guide
- Cartesia TTS bytes API reference: https://docs.cartesia.ai/api-reference/tts/bytes
- Cartesia voice cloning guide: https://docs.cartesia.ai/build-with-cartesia/capability-guides/clone-voices

When you're done, tell me which files changed, which fields you couldn't map, and how to flip the flag.

Every PlayHT field, mapped to Cartesia

The prompt carries this table. Each row is a field in your PlayHT request and the Cartesia field that replaces it.

  1. PlayHT

    POST https://api.play.ht/api/v2/tts/stream

    Cartesia
    POST /tts/bytes
  2. PlayHT

    AUTHORIZATION: Bearer <secret key> and X-USER-ID

    Cartesia
    X-API-Key and Cartesia-Version: 2026-08-14
    Note
    Delete the user ID from your config. Cartesia has no equivalent.
  3. PlayHT

    voice: an s3:// manifest URL

    Cartesia
    voice: {"id": "<voice id>"}
    Note
    PlayHT voices and clones went offline with the service. Pick a library voice, or clone again from your original recording.
  4. PlayHT

    voice_engine: PlayDialog, Play3.0-mini, PlayHT2.0 and others

    Cartesia
    model_id: sonic-3.6
  5. PlayHT

    text (2,000 characters; 20,000 on Play3.0-mini)

    Cartesia
    transcript
  6. PlayHT

    language: a lowercase name such as english

    Cartesia
    language: a code such as en or en-GB
  7. PlayHT

    output_format: mp3, wav or mulaw

    Cartesia
    output_format object: container mp3, wav or raw, with pcm_mulaw for mu-law
  8. PlayHT

    sample_rate (8000 to 48000)

    Cartesia
    output_format.sample_rate (8000 to 48000)
  9. PlayHT

    speed (0.1 to 5)

    Cartesia
    generation_config.speed (0.6 to 1.5)
    Note
    Anything slower than 0.6 or faster than 1.5 has to be clamped.
  10. PlayHT

    emotion

    Cartesia
    generation_config.emotion
    Note
    The two vendors use different emotion names. Map each one by ear.

PlayHT API key and auth, mapped to Cartesia

Cartesia reads the key from the X-API-Key header and pins the API version with Cartesia-Version on every request.

  1. PlayHT

    AUTHORIZATION: Bearer secret key plus an X-USER-ID header

    Cartesia
    X-API-Key plus Cartesia-Version: 2026-08-14
    Note
    Both values are dead now. Remove them from your secrets store.

PlayHT API pricing per 1,000 characters

List prices per 1,000 characters from the vendor's own pricing page. Plans, regions and volume discounts change what you pay.

  1. Model or plan

    PlayHT API

    PlayHT
    Not published (service ended)
    Note
    The pricing page went offline with the domain, so there is no current figure to cite.

On Cartesia, usage draws from your plan's credits: 20,000 credits a month on the Free plan (about 20,000 characters). Enterprise pricing is custom.

Cartesia plans and pricing

Sources

Prices read from each company's pricing page in November 2026.

PlayHT limits compared with Cartesia

Published limits from both companies. Plans change them, so check both pages before you size a rollout.

  1. Limit

    Request limit

    Cartesia
    No published maximum; stream long text over the TTS WebSocket
    PlayHT
    2,000 characters per request; 20,000 on Play3.0-mini
  2. Limit

    Languages

    Cartesia
    44 languages for text to speech
    PlayHT
    37 language values on Play3.0-mini and PlayDialog

Cartesia's figures come from its pricing page and voice library.

Cartesia pricing and plan limits

Sources

Limits read from each company's documentation in November 2026.

What you get on Cartesia

What changes once the PlayHT call is gone.

One key, no user ID

PlayHT wanted a secret key in AUTHORIZATION plus your account's X-USER-ID on every call. Cartesia takes one X-API-Key and a Cartesia-Version header.

Voices are IDs, not S3 manifests

PlayHT named each voice with an s3://.../manifest.json URL. A Cartesia voice is a UUID you copy from the voice library or get back when you clone.

Word timings for captions

Turn on add_timestamps over the TTS WebSocket to get a start and end time for every word, which is enough to sync podcast transcripts or subtitles.

How to migrate from PlayHT to Cartesia

The same changes the prompt makes, if you'd rather make them yourself.

  1. Search the codebase for api.play.ht, X-USER-ID and voice_engine to find every call site, including ones that have failed silently since July 2025.

  2. Get a Cartesia API key. For each PlayHT voice, shortlist a library voice by role, or clone from the recording you originally uploaded to PlayHT (10 seconds minimum, Pro plan or higher).

  3. Replace the request as in the code above. Translate language names to codes and clamp speed.

  4. Split two-speaker PlayDialog scripts into one request per turn.

  5. Remove the PlayHT key and user ID from your secrets store once no code reads them.

Frequently asked questions

What happened to PlayHT?

Yes. The API went dark around July 26, 2025, after Meta acquired PlayAI, and the platform closed on December 31, 2025, according to Inworld and Murf. PlayHT's own docs site at docs.play.ht is still up and carries no notice, which is why some teams only find out from failing requests.

Can I recover my PlayHT voices?

Not from PlayHT. If you still have the recording you used to clone a voice, and permission to use it, Cartesia makes an instant clone from 10 seconds of it on a Pro plan or higher. A professional clone needs 30 minutes of audio and a Startup plan.

Where did play.ht pricing go?

Offline, along with the rest of play.ht. We can't cite a PlayHT price because no live page states one. Cartesia's plans are on /pricing.

What doesn't carry over from PlayHT?

quality, temperature, seed and the three guidance knobs have no Cartesia fields. Two-speaker PlayDialog requests become one request per turn. ogg and flac output need a transcode, and speed narrows from 0.1 to 5 down to 0.6 to 1.5.

How do I check the new voice against the old one?

You can't run PlayHT side by side any more, so compare against clips you saved while it worked. Pull a few stored PlayHT outputs, render the same scripts on Cartesia, and listen to them in pairs before you pick a voice for each role.

Get started today

Talk to an expert.

Connect with a member of our team and learn how Cartesia can help you build world-class voice experiences.

Contact Sales

Start building.

Create an API key, then hand your coding agent the migration prompt and a few of your own scripts.

Try Cartesia