---
title: "Quickstart: from zero to mp3"
url: https://lumean.app/de/developers/docs/start
locale: de
description: "Five steps from an empty terminal to a downloaded file — voice, template, order, waiting, link."
updated: 2026-09-04
source_locale: en
sources: [get-voices-elevenlabs-library, post-templates, post-orders, get-orders-order, post-storage-url]
errors: ["403", "402", "422", "429"]
spec_version: 0.0.1
---

# Quickstart: from zero to mp3

Speech synthesis in Lumean is a pipeline of five links, and each link takes an ID from the
previous one's response: voice → template → order → waiting → file. No link can be skipped: the
voice is set **only** through a template (there is no `orders.voice_id` field), and the result
is delivered **only** as a temporary link from `POST /storage/url` — the order holds paths, not
URLs.

```text
Конвейер публичного API: от ключа до ссылки на готовый файл

  1. Ключ        X-API-KEY            заголовок в каждом запросе
        ↓
  2. Права       orders.write         пресет ключа решает, что он может
        ↓
  3. Голос       GET /voices          берём voice_id из каталога
        ↓
  4. Шаблон      POST /templates      voice_id кладётся в config.tts_settings
        ↓                             (поля orders.voice_id НЕ существует)
  5. Заказ       POST /orders          201 created, БЕЗ результата
        ↓
  6. Чанки       GET /orders/{order}   статус и items, пока не терминальный
        ↓
  7. Файлы       result.files[]        это ПУТИ в хранилище, а не URL
        ↓
  8. Ссылка      POST /storage/url     путь → временная ссылка на скачивание
```

## What you need first

An API key with the `voices.read`, `templates.write`, `orders.write`, and `orders.download`
scopes. You create it in [My API keys](/developers); every request uses the same header,
`X-API-KEY`.

> [!WARNING]
> The built-in **`automation` preset does not include `templates.write`** (only
> `templates.read`), so you cannot complete this walkthrough with it: step 2 will return `403`.
> Use the `full` preset, or add `templates.write` manually when you create the key.

> [!CAUTION]
> Step 3 creates a **real order**: it consumes your subscription quota and is billed like any
> other. You can cancel an order after it is created (`POST /orders/{order}/cancel`), but what was
> spent on completed chunks is not refunded — start with one short phrase, not a book chapter.

Рецепт «first-tts» пошагово: https://lumean.app/de/developers/docs/start#r-first-tts

## The full script

A ready-made run from voice to file. You need `curl` and `jq`; substitute your own `KEY`.

```bash
#!/usr/bin/env bash
set -euo pipefail

BASE=https://api.lumean.app/api/public
KEY=<your_api_key>
AUTH=(-H "X-API-KEY: $KEY" -H "Content-Type: application/json")

# 1. Voice: take the first voice_id from the ElevenLabs public library.
#    External provider catalogs are wrapped in data.voices[]; pages start at ZERO.
VOICE_ID=$(curl -s "$BASE/voices/elevenlabs/library?page=0&page_size=20" \
  -H "X-API-KEY: $KEY" | jq -r '.data.voices[0].voice_id')

# 2. A TTS template with this voice. tts_settings.mode is required,
#    language_code (ISO-639-1) is optional.
TEMPLATE_UUID=$(curl -s -X POST "$BASE/templates" "${AUTH[@]}" -d '{
  "service_key": "elevenlabs",
  "name": "My TTS",
  "config": {
    "tts_settings": {
      "mode": "mode_v1",
      "model_id": "eleven_multilingual_v2",
      "voice_id": "'"$VOICE_ID"'",
      "advanced_voice_settings": true,
      "voice_settings": {
        "stability": 0.5, "similarity_boost": 0.75,
        "use_speaker_boost": true, "speed": 1.0
      }
    }
  }
}' | jq -r '.data.id')

# 3. An order from the template. The text goes in top-level input_text, NOT in task_data.
ORDER_UUID=$(curl -s -X POST "$BASE/orders" "${AUTH[@]}" -d '{
  "template_id": "'"$TEMPLATE_UUID"'",
  "input_text": "Привет! Это тестовая озвучка через Lumean API."
}' | jq -r '.data.id')
# → status: "created" — this response has no result, and it cannot have one

# 4. Wait until it is ready. Terminal statuses: completed, result_delivered,
#    failed, compensated, cancelled. partially_completed is NOT terminal.
while :; do
  STATUS=$(curl -s "$BASE/orders/$ORDER_UUID" -H "X-API-KEY: $KEY" | jq -r '.data.status')
  echo "status: $STATUS"
  case "$STATUS" in
    completed|partially_completed|result_delivered) break ;;
    failed|cancelled|compensated) echo "order failed"; exit 1 ;;
  esac
  sleep 5
done

# 5. File: result.files[] are PATHS. Exchange the path for a temporary link and download it.
PATHNAME=$(curl -s "$BASE/orders/$ORDER_UUID" -H "X-API-KEY: $KEY" \
  | jq -r '.data.result.files[0]')
URL=$(curl -s -X POST "$BASE/storage/url" "${AUTH[@]}" \
  -d '{ "path": "'"$PATHNAME"'", "download": true }' | jq -r '.data.url')
curl -sL "$URL" -o result.mp3
```

## What is easy to get wrong here

| Pitfall | How it actually works |
| --- | --- |
| Looking for `voice_id` in the order body | The voice lives in the **template's** `config.tts_settings.voice_id`; `POST /orders` has no such field |
| Putting the text in `task_data.text` | For template-based TTS, the text goes in the top-level `input_text` |
| Treating `data.result.files[]` as links | They are paths; a link is issued by `POST /storage/url`, and it is short-lived |
| Waiting for `completed` forever | `partially_completed` is not a terminal status: some chunks are done, others are waiting for your decision |
| Pagination of provider catalogs | For ElevenLabs and HeyGen, `page` is counted **from zero**; for regular API lists, from one |
| Leaving the file “for later” | Order storage is purged according to retention (by default, 7 days after a terminal status), while the order keeps showing the paths, now dead |

## If you get an error instead of `201`

Three codes come up at step 3 more often than others, and each one is handled differently.

### 402 — 402 — payment required

| Что произошло | Что делать |
| --- | --- |
| The order was not created and no money was charged. The code is returned by `POST /orders` and `POST /orders/{order}/retry` — they go through the same billing flow. The body always contains `reason`, and that is what determines whether this is an error or an offer to top up. | Branch on `reason`, not on `message`: message wording changes without notice and is not an error code. Do not retry blindly: a retry without confirmation returns a fresh 402 with a new `quote_token`, while a blind retry WITH confirmation charges money without the user knowing. |

`Retry-After`: нет. Разбор: https://lumean.app/de/developers/docs/errors/402

`402` is not a rejection but a payment fork: `payg_topup_required` brings the top-up price and a
`quote_token`, which you must send back together with `confirm_payg_topup: true`. A blind retry
here is either useless or charges money without the user's knowledge — see
[LMC, quotas and PAYG](/developers/docs/guide/billing).

`429` is five different limits under one code; they are told apart by `reason` and by the
presence of `Retry-After` ([Limits and the 429 code](/developers/docs/guide/limits)). A `422` without
`errors` but with `reason` is a domain rejection: the request shape is not the problem, and
repeating the same body will get the same response.

## Next steps

- [Keys, scopes and headers](/developers/docs/guide/authentication) — eleven scopes, a wildcard, and three presets.
- [The asynchronous order model](/developers/docs/guide/async) — nine statuses and what counts as completion.
- [Realtime](/developers/docs/guide/realtime) — the same statuses as events, without polling.
- [Templates](/developers/docs/guide/templates) — service config and `GET /templates/config-options`.
- [Voiceover text](/developers/docs/guide/text) — pauses, markup, and which of it is not billed.
- [Files, links and storage](/developers/docs/guide/files) — subtitles in `result.service_files[]`
  and retention.
- [Conventions](/developers/docs/guide/conventions) — the response envelope and 422 outside it.
- [Pagination](/developers/docs/guide/pagination) — two page numbering bases.
- [Voices](/developers/docs/guide/voices) — three catalogs and where to get a `voice_id`.
- [Limits and the 429 code](/developers/docs/guide/limits) — five limits under one code.
- [Tokens, quotas, LMC and PAYG](/developers/docs/guide/billing) — what you pay for and with what.
- [Retries and idempotency](/developers/docs/guide/retries) — four different kinds of “retry”.
- Scenario operations: [POST /orders](/developers/docs/api/post-orders),
  [POST /templates](/developers/docs/api/post-templates),
  [POST /storage/url](/developers/docs/api/post-storage-url).

---

- Diese Seite im Browser: https://lumean.app/de/developers/docs/start
- Vollständige maschinenlesbare Referenz: https://api.lumean.app/docs/llm.md
