Sign in Start free

Guides

Bulk and long-form: hundreds of lines without babysitting

The trick is making the failure of line 340 cheap.

Last checked 2026-08-14

In short

Import a CSV with one line per row - text, voice, optional speed - and Naadly queues it as a job, renders each row separately and tells you when it is done by webhook or on the jobs page. Because rows render independently, a bad row is a one-row re-render rather than a restart. Bulk is on paid plans from $15 a month.

Prepare the CSV properly

  • One row per spoken line, and an id column of your own so you can match files to source material later.
  • Voice per row if the batch is a cast; one voice repeated if it is a narration.
  • Run the pronunciation list first - a batch is exactly where a mispronounced name multiplies.
  • Test twenty rows before submitting two thousand.

A worked example: a 40-chapter book

  1. Split the manuscript into one project per chapter, one line per paragraph. Forty jobs of a few hundred lines each beat one job of twelve thousand, because the unit of retry is the unit of annoyance.
  2. Render chapter one only. Listen to all of it - not the first page - and fix the pronunciation list from what you hear.
  3. Submit the rest. The queue works through them while you do something else, and the jobs page shows which chapter is where.
  4. Collect by webhook if you are automating, or download per chapter if you are not.
  5. Re-render the lines you flagged while listening; the rest of the chapter is untouched and does not cost minutes again.

The thing that makes this bearable is that lines are addressable. An editor who says "page 210 reads the year wrong" is asking for one line, not a re-run.

Queued jobs and webhooks

Long work is a job, not a request: submit it, close the tab, and get a signed webhook when it finishes. Deliveries are HMAC-signed and retried with backoff, and every attempt is logged, so an integration can be debugged after the fact rather than guessed at.

If you would rather poll, the job endpoint returns status and the output keys - but polling a queue you could have been told about is how people end up rate-limited by their own script.

Limits, and how to live inside them

Characters per request are capped by plan, engines have finite concurrency, and Indic and translation carry their own meters. In practice: chapter-sized jobs beat book-sized ones, a couple of hundred rows per batch is comfortable, and a retry of one row is free enough to be your first response to a bad render.

Metering is by minutes of audio produced, so the cost of a batch is the length of its output rather than the number of attempts it took to get there - which is the difference between a bulk workflow you can iterate on and one you cannot.

Questions

How many lines can one job have?
Hundreds comfortably; the hard limit is the plan's characters per request. Split a book into chapters.
What happens if one line fails?
The rest still finish. Re-render the failed row on its own.
Can I trigger bulk renders from code?
Yes - the job endpoint takes the same batch, and the webhook tells you when to collect.