---
title: "POST /templates — Create Template"
url: https://lumean.app/de/developers/docs/api/post-templates
locale: de
description: "Create Template"
generated: 2026-10-17
operationId: template.store
method: POST
path: /templates
scopes: [templates.write]
spec_version: 0.0.1
---

# POST /templates

**Create Template**

Creates a generation template. The response (`201`) carries the finished template —
put its `id` into `template_id` when creating orders.

`config` is validated against the schema of the service named in `service_key`. Take
the accepted keys, value lists and ranges from
`GET /templates/config-options?service=<code>`; anything outside the schema is
rejected with `422`.

**Required key permission:** `templates.write`.

- Benötigtes Recht: `templates.write`

## Anfrage

```bash
curl -X POST 'https://api.lumean.app/api/public/templates' \
  -H 'Accept: application/json' \
  -H 'X-API-KEY: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
  "service_key": "elevenlabs",
  "name": "Диктор — женский, спокойный",
  "config": {
    "tts_settings": {
      "mode": "mode_v1",
      "model_id": "eleven_multilingual_v2",
      "voice_id": "EXAVITQu4vr4xnSDxMaL",
      "language_code": "ru",
      "advanced_voice_settings": true,
      "voice_settings": {
        "stability": 0.5,
        "similarity_boost": 0.75,
        "use_speaker_boost": true,
        "speed": 1
      }
    }
  }
}'
```

## Parameter

Keine Parameter.

## Request-Body

`config` is validated against the schema of the service named in `service_key`. Allowed
keys, value lists and ranges come from `GET /templates/config-options?service=<code>`;
anything outside the schema is rejected with `422`.

Content-Type: `application/json`

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `service_key` | `string` | Pflicht | Code of the service the template is built for: a short latin string — `elevenlabs`, `heygen`, `lumimg`, `sfx`, `music`. The codes available to you are listed by `GET /usage` in its `service_code` field; this choice determines what `config` will accept. |
| `name` | `string` — ≤ 255 Zeichen | Pflicht | Template name, up to 255 characters. Shown in `GET /templates` and in the web interface. |
| `config` | `object` | Pflicht | Generation settings. The structure depends on `service_key`; the accepted keys, ranges and value lists come from `GET /templates/config-options?service=<code>` — take them from there instead of guessing. A minimal valid `config` for `elevenlabs`: `{"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}}}` ### Fine voice settings need a flag Which `voice_settings` reach the speech engine depends on the model and on the `tts_settings.advanced_voice_settings` flag (defaults to `false`): \| Model \| Without the flag \| With the flag \| \| --- \| --- \| --- \| \| `eleven_v3`, `eleven_v3_beta` \| `stability` \| all five \| \| `eleven_v4`, `eleven_v4_exp` \| `stability`, `similarity_boost` \| all five \| \| others \| all five \| all five \| Values that do not reach the engine are stored on the template and pass validation, but do not affect the audio. There is no error: it just looks like "the setting does not work" — most often with `speed` on v3/v4. `voice_settings.stability` carries a dependency of the same kind: on models of the `eleven_v3` family its step is 0.5, so only `0`, `0.5` and `1` are accepted. ### Stitching prosody across chunks Long text is split into chunks, and each one is synthesised by its own request — which is why the pitch can jump at the joins. Two optional boolean flags ask the engine to take the neighbours into account: `tts_settings.prev_next_text` sends the neighbouring chunk text, `tts_settings.request_ids` sends the ids of the neighbouring generations. Both default to `false`. They only affect how the joins sound; pricing and chunking are unchanged. **Only ONE of them may be enabled.** Sending both is a `422`: given both the text and the ids, the engine uses the ids only and ignores the text, so "both on" would be a silently disabled `prev_next_text`. ### Text normalization `tts_settings.apply_text_normalization` has three modes: `auto` (the engine decides on its own whether to normalize, for example spelling out numbers), `on` (always normalize), `off` (skip it). Defaults to `auto`. |
| `folder_id` | `string` — uuid — nullable | — | UUID of one of your folders. Omitted — the template is created at the root. |
| `is_public` | `boolean` | — | Publish the template in the shared catalogue. Defaults to `false` — visible only to you. |

**Beispiel**

```json
{
  "service_key": "elevenlabs",
  "name": "Диктор — женский, спокойный",
  "config": {
    "tts_settings": {
      "mode": "mode_v1",
      "model_id": "eleven_multilingual_v2",
      "voice_id": "EXAVITQu4vr4xnSDxMaL",
      "language_code": "ru",
      "advanced_voice_settings": true,
      "voice_settings": {
        "stability": 0.5,
        "similarity_boost": 0.75,
        "use_speaker_boost": true,
        "speed": 1
      }
    }
  }
}
```

## Body-Szenarien

### TTS template (ElevenLabs)

A minimal valid config. Allowed models, voices and ranges come from GET /templates/config-options?service=elevenlabs.

```json
{
  "service_key": "elevenlabs",
  "name": "Диктор — женский, спокойный",
  "config": {
    "tts_settings": {
      "mode": "mode_v1",
      "model_id": "eleven_multilingual_v2",
      "voice_id": "EXAVITQu4vr4xnSDxMaL",
      "language_code": "ru",
      "advanced_voice_settings": true,
      "voice_settings": {
        "stability": 0.5,
        "similarity_boost": 0.75,
        "use_speaker_boost": true,
        "speed": 1
      }
    }
  }
}
```

## Antworten

### 201 — Template created. Put its `id` into `template_id` when creating orders.

**Antwortfelder**

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `success` | `boolean` | Pflicht | Success flag. Branch on the HTTP status code instead: any 2xx response carries `true` here, while an error comes back in a different shape that need not contain this field at all. |
| `message` | `string` | Pflicht | A human-readable note in the account language. Fine to show to a user; do not parse it — the wording changes without notice and is not an error code. |
| `data` | `Template` | Pflicht | The template just created. Put its `id` into `template_id` when creating an order. |
| `data.id` | `string` | Pflicht | Template UUID. Put it into `template_id` when creating an order. |
| `data.user_id` | `integer` | Pflicht | ID of the template owner. |
| `data.slug` | `string` | Pflicht | Short public identifier used for sharing. `null` on a template that was never shared. |
| `data.name` | `string` | Pflicht | Template name — for humans only; it does not affect generation. |
| `data.service_key` | `string` | Pflicht | Code of the service whose schema validates `config`: `elevenlabs`, `lumimg`, and so on. |
| `data.service` | `Service \| null` — nullable | Pflicht | The template’s service for reference: name and pricing, without configuration schemas. `null` means no service with that code exists any more. |
| `data.config` | `object` | Pflicht | Generation settings: voice, model, speed and so on — the set of keys is defined by the service. Look up allowed values in `GET /templates/config-options?service=<code>`; anything outside the schema is rejected with `422`. Inside an order (`template` in `GET /orders/{order}`) this is the order’s own settings — the snapshot taken at creation with `config_override` applied, not the template’s current configuration (for orders created before late September 2026 — the current template configuration with `config_override`). |
| `data.is_public` | `boolean` | Pflicht | Whether the template is published in the shared catalogue. |
| `data.folder_id` | `string` | Pflicht | UUID of the folder holding the template, or `null` for the root. The folder tree is visible in `GET /templates/browse`. |
| `data.created_at` | `string` — date-time — nullable | Pflicht | When the template was created, ISO 8601. |
| `data.updated_at` | `string` — date-time — nullable | Pflicht | When the template last changed, ISO 8601. |

**Beispiel**

```json
{
  "success": true,
  "message": "Template created",
  "data": {
    "id": "3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f",
    "user_id": 501,
    "slug": "2f3a4b5c-6d7e-4f8a-9b0c-1d2e3f4a5b6c",
    "name": "Ad Voice (RU)",
    "service_key": "elevenlabs",
    "config": {
      "tts_settings": {
        "model_id": "eleven_multilingual_v2",
        "voice_id": "pNInz6obpgDQGcFmaJgB",
        "mode": "mode_v1",
        "language_code": "ru",
        "advanced_voice_settings": true,
        "voice_settings": {
          "stability": 0.6,
          "similarity_boost": 0.7,
          "use_speaker_boost": true
        }
      }
    },
    "is_public": false,
    "folder_id": null,
    "created_at": "2026-07-17T15:30:00+00:00",
    "updated_at": "2026-07-17T15:30:00+00:00"
  }
}
```

### 401 — The key is missing, unknown, disabled or expired.

**Antwortfelder**

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `success` | `boolean` | Pflicht | Always `false` in error responses. |
| `message` | `string` | Pflicht | Error text in the key's language (set through the `X-Locale` header). |
| `data` | `null` — nullable | Pflicht | Always `null` when the request is rejected before processing. |

**Beispiel**

```json
{
  "success": false,
  "message": "API key is missing. Provide it in the X-API-KEY header.",
  "data": null
}
```

### 403 — The key lacks the required permission, or the object belongs to another user.

**Antwortfelder**

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `success` | `boolean` | Pflicht | Always `false` in error responses. |
| `message` | `string` | Pflicht | Error text in the key's language (set through the `X-Locale` header). |

**Beispiel**

```json
{
  "success": false,
  "message": "This API key does not have permission to perform this action."
}
```

### 422 — Validation error. Offending fields are listed in `errors`.

**Antwortfelder**

| Feld | Typ | Pflicht | Beschreibung |
| --- | --- | --- | --- |
| `message` | `string` | Pflicht | Errors overview. |
| `errors` | `object` | Pflicht | A detailed description of each field that failed validation. |
| `errors.*` | `array<string>` — beliebige Schlüssel | — |  |

**Beispiel**

```json
{
  "message": "string",
  "errors": {
    "key": [
      "string"
    ]
  }
}
```

---

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