Text to Speech API for Audiobooks: Cost, Chunking, and Workflow

A 300-page book is about 450,000 characters: $45.00 of speech-2.8-hd at list, $42.75 at the current 5% group discount, and roughly 8 hours 20 minutes of finished audio. This page works through that arithmetic, the chunking and file-naming rules that keep a long manuscript reproducible, and a two-pass draft-then-master workflow.

The arithmetic for a 300-page book

Take an ordinary trade paperback: 300 pages at roughly 250 words per page is 75,000 words. English runs about six characters per word once you count the trailing space, so the manuscript you actually submit is approximately 450,000 characters. Those two figures are planning estimates, not measurements. The only number that gets billed is the length of the strings you send, which you can compute with len(text) before you hold an API key.

MiniMax speech models on YiduoChan are billed per input character at MiniMax's own published pay-as-you-go rates. speech-2.8-hd is $100 per 1M characters ($0.10 per 1,000); speech-2.8-turbo is $60 per 1M ($0.06 per 1,000). Every account currently sits in a group whose ratio is 0.95, so the amount actually deducted is 5% below list. Treat that as the current group discount rather than a permanent guarantee, and check the speech pricing page before you commit a quote to a client.

Line itemspeech-2.8-turbospeech-2.8-hd
List price per 1M input characters$60.00$100.00
Effective rate at the current 5% group discount$57.00$95.00
450,000-character manuscript, list$27.00$45.00
450,000-character manuscript, 5% off$25.65$42.75
One 15,000-character chapter, list$0.90$1.50
One 15,000-character chapter, 5% off$0.86$1.43
Per finished audio hour (about 54,000 chars), list$3.24$5.40
Per finished audio hour, 5% off$3.08$5.13

Half-cent values are shown rounded. Exactly, the discounted chapter figures are $0.855 and $1.425, and the discounted turbo audio hour is $3.078.

Duration follows from the same estimate: about 900 characters per minute of speech, so 450,000 characters is roughly 500 minutes, or 8 hours 20 minutes of finished audio. Expressed per hour that is about 54,000 characters, which is the conversion you want when a publisher quotes you a target runtime instead of a word count.

Why per-character billing makes long form predictable

The bill is a function of the input you send, not of the audio that comes back. A 450,000-character manuscript costs $45.00 at list, or $42.75 with the current 5% group discount, on speech-2.8-hd whether it renders to eight hours or nine, whether you request mp3 or wav, and whether the narrator reads quickly or slowly. That single property is what turns an audiobook budget into a spreadsheet exercise rather than a pilot project. Count the characters of the final manuscript in one pass, multiply, and you have the cost to the cent before the first request goes out.

It also makes trimming worth an hour of your time. Billing counts every character you submit, including spaces, punctuation, running headers, footnote markers and any markdown left in the source. Stripping 2% of a 450,000-character manuscript removes 9,000 characters, which is $0.90 at list on speech-2.8-hd and $0.855 at the current group rate. The larger benefit is that you are no longer paying a narrator to read your asterisks aloud.

The second property that matters across a long run is that failed requests are never charged. A full book is hundreds or thousands of requests spread over hours. A dropped connection during chapter 22, a chunk that returns an error, a retry loop that fires three times before it succeeds — none of those consume credits. Only a response you actually received is billed. So a resumable render loop can afford to be aggressive: retry on any error, split and retry on a chunk that keeps failing, and your cost model stays exactly the character count of the text that produced audio on disk.

Chunking a manuscript

There is no published per-request character limit for /v1/audio/speech. Because the limit is not documented, do not design around a number you guessed. Chunk the manuscript, keep each request comfortably small, and treat an error on an oversized chunk as a signal to split further rather than as a cost event.

Chapter first

Split on chapter boundaries before anything else. The chapter is the unit an editor talks about, the unit a listener navigates, and the unit you will re-render when a proper noun comes back wrong. In the example book, 30 chapters averaging 15,000 characters each accounts for the full 450,000, and each one is about 16 minutes 40 seconds of audio at the 900-characters-per-minute estimate. Chapter-sized requests also give you a natural progress log: 30 lines of output, each with a character count you can reconcile against the invoice.

Then paragraph

Where a chapter is long enough to make you uneasy, split it again on blank lines and pack whole paragraphs into parts under a fixed ceiling — 8,000 characters is a conservative starting point. Never split mid-sentence. Prosody is generated per request, so a break inside a clause is audible at the seam, while a break between paragraphs lands where a short silence is natural anyway. Keep the packing greedy and deterministic so that re-running the splitter on an unchanged chapter produces byte-identical parts.

File names that sort into playback order

Zero-pad every index to a width that covers the largest value you will ever reach: ch001.wav through ch030.wav, and ch014_p0007.wav for paragraph parts. Unpadded names sort as ch1, ch10, ch2 in every shell glob, every sorted() call and every file manager, and that mistake is discovered at the concatenation step, after the money is spent. Give front matter its own slot at ch000_frontmatter so it sorts ahead of chapter one. Keep each pass in its own directory (draft/, master/) rather than encoding the model into the filename, so the same sorted list works for both.

Re-rendering one chapter

Chapter-level granularity is what keeps corrections cheap. A 15,000-character chapter re-rendered on speech-2.8-hd is $1.50 at list and $1.425 at the current group rate; on speech-2.8-turbo it is $0.90 and $0.855. Fixing a mispronounced surname in chapter 14 therefore costs $1.50 against a $45.00 full render — one thirtieth of the book, matching its share of the characters — and it costs nothing at all if the request fails on the way. If you had chunked the whole book into a single request you would be re-rendering 450,000 characters to fix 40 of them.

Keeping voice and pacing consistent

Consistency across eight hours of audio is a configuration problem, not a tuning problem. Fix one voice ID for the entire title and never vary it: English_expressive_narrator for English narration, or another published ID such as male-qn-qingse or female-shaonv. Voice cloning is not offered, so the narrator identity is exactly the voice ID you pin.

Do the same with provider extras. Build one metadata object containing voice_setting.emotion and audio_setting.sample_rate, define it once at module level, and pass that same object into every request in the book. Varying emotion per chapter produces an audible shift at the chapter boundary unless you intended one; varying sample_rate forces a resample at the concatenation step. Write the model ID, voice ID, response format and metadata object into a manifest.json next to the audio, so a re-render six months later reproduces the settings that chapters 13 and 15 were made with. And do not mix speech-2.8-turbo and speech-2.8-hd inside one finished title.

Formats: master lossless, distribute mp3

response_format accepts mp3, wav, flac and pcm, and defaults to mp3. Because billing is per input character, the format you choose does not change the price — a wav master of the example book costs the same $45.00 at list as an mp3 draft of it.

Render the master as wav or flac. Both are lossless, so normalising levels, trimming silences and concatenating parts introduces no generation loss, and flac stores the same samples in a smaller file than wav. Use pcm only when you are feeding raw samples straight into a DSP chain and already know the sample rate and bit depth, since there is no container header to tell you. Produce mp3 once, at the very end, by encoding the finished lossless master — not by asking the API for mp3 and then re-encoding it after editing. Use mp3 directly for the throwaway draft pass, where the file is going to be listened to once and deleted. Streaming audio is not documented for this endpoint, so write the renderer as a batch job, which is what a batch renderer wants anyway.

A renderer for chapter strings

The loop below quotes the job first, then renders chapter strings to numbered files, skipping anything already on disk so an interrupted run resumes without paying twice. It uses the OpenAI-compatible base URL https://yiduochan.com/v1 with Authorization: Bearer <your API key> supplied by the SDK; see the SDK setup notes for the Node equivalent.

import glob, json, os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["YIDUOCHAN_API_KEY"],
    base_url="https://yiduochan.com/v1",
)

LIST_USD_PER_1M = {"speech-2.8-turbo": 60.0, "speech-2.8-hd": 100.0}
GROUP_RATIO = 0.95  # current 5% group discount

VOICE = "English_expressive_narrator"
METADATA = {
    "voice_setting": {"emotion": "neutral"},
    "audio_setting": {"sample_rate": 44100},
}


def quote(chapters, model):
    chars = sum(len(c) for c in chapters)
    listed = chars / 1_000_000 * LIST_USD_PER_1M[model]
    return chars, round(listed, 4), round(listed * GROUP_RATIO, 4)


def split_paragraphs(text, max_chars=8000):
    """Pack whole paragraphs into parts; never split a sentence."""
    parts, buf = [], ""
    for para in text.split("\n\n"):
        if buf and len(buf) + len(para) + 2 > max_chars:
            parts.append(buf)
            buf = para
        else:
            buf = f"{buf}\n\n{para}" if buf else para
    if buf:
        parts.append(buf)
    return parts


def render(chapters, model, fmt, outdir):
    os.makedirs(outdir, exist_ok=True)
    for i, chapter in enumerate(chapters, start=1):
        for j, part in enumerate(split_paragraphs(chapter), start=1):
            path = os.path.join(outdir, f"ch{i:03d}_p{j:04d}.{fmt}")
            if os.path.exists(path):      # resume; failed runs cost nothing
                continue
            audio = client.audio.speech.create(
                model=model,
                input=part,
                voice=VOICE,
                response_format=fmt,
                extra_body={"metadata": METADATA},
            )
            with open(path, "wb") as f:
                f.write(audio.content)
            print(path, len(part), "chars")
    with open(os.path.join(outdir, "manifest.json"), "w") as f:
        json.dump({"model": model, "voice": VOICE,
                   "response_format": fmt, "metadata": METADATA}, f, indent=2)


chapters = [open(p, encoding="utf-8").read()
            for p in sorted(glob.glob("manuscript/ch*.txt"))]

print(quote(chapters, "speech-2.8-hd"))       # (450000, 45.0, 42.75)
render(chapters, "speech-2.8-turbo", "mp3", "draft")   # pass 1
render(chapters, "speech-2.8-hd", "wav", "master")      # pass 2

Two passes: draft on turbo, master on hd

The failure mode of a one-pass audiobook is discovering, at hour six of listening, that the narrator reads a recurring surname wrong, says "eighteen forty-two" where the manuscript meant a page reference, or narrates a stray markdown heading. Every one of those is a manuscript problem, and you want to find them at the cheap rate.

Pass one renders the whole book on speech-2.8-turbo to draft/ as mp3 and exists only to be listened to at speed. Fix the manuscript text, then pass two renders the corrected text on speech-2.8-hd to master/ as wav.

PassModelFormatCharactersListAt 5% off
1 — draft and QAspeech-2.8-turbomp3450,000$27.00$25.65
2 — masterspeech-2.8-hdwav450,000$45.00$42.75
Combined900,000$72.00$68.40

That is 1.6 times the cost of a single hd pass: $27.00 more at list, $25.65 more at the current group rate. The break-even is easy to state. One hd chapter re-render costs $1.50 at list, so the draft pass pays for itself the moment it prevents 18 chapter re-renders ($27.00 divided by $1.50 = 18). The ratio is identical at the discounted rate, $25.65 divided by $1.425 = 18. On a 30-chapter book that is 60% of the chapters.

Getting an account and checking your own numbers

Access is prepaid USD credits with no subscription and no free trial credits. The minimum top-up is $5, with presets at $5, $10, $20, $50, $100, $200 and $500 or a custom amount, and credits are valid for 12 months. The $100 preset covers the two-pass example at $68.40 with room left for re-renders. Sign up at /register, review the rates on /pricing, and put your own character counts through the cost calculator before you plan a list of titles.

The same endpoint and the same billing model apply to shorter work; see TTS for video voiceover for the short-form patterns, the speech-2.8 model page for parameter details, and the MiniMax hub for the chat models. Call GET /v1/models to confirm the exact model IDs your key can reach, and write to [email protected] if an estimate and an invoice disagree.

FAQ

How much does it cost to narrate a 300-page book?

A 300-page book is roughly 450,000 characters, which is $45.00 on speech-2.8-hd or $27.00 on speech-2.8-turbo at list price. At the current 5% group discount those become $42.75 and $25.65.

Is there a maximum number of characters per request?

No per-request character limit is published, so chunk by chapter and then by paragraph and keep each request small. If an oversized chunk returns an error, split it and retry — the failed call is not billed.

Do failed or retried requests cost anything?

No. Failed requests are never charged, so a resumable render loop that retries on error costs only wall-clock time.

Which output format should I master in?

Render the master as wav or flac and encode mp3 once at the end from that lossless master. The format never changes the price, because billing is per input character.

Can I clone a narrator's voice?

No, voice cloning is not offered. Pin one published voice ID such as English_expressive_narrator for the whole title and reuse the same metadata object on every request.

Are there free credits for testing?

No. Access is prepaid pay-as-you-go USD credits with a $5 minimum top-up, and credits are valid for 12 months.

Sign up and get an API key See full model pricing