---
title: "GET /orders/{order} — Get Order"
url: https://lumean.app/en/developers/docs/api/get-orders-order
locale: en
description: "Get Order"
generated: 2026-10-17
operationId: order.show
method: GET
path: "/orders/{order}"
scopes: [orders.read]
spec_version: 0.0.1
---

# GET /orders/{order}

**Get Order**

Returns one order in full.

**Includes:**
- Status and result (`result.files[]` — the main output files).
- `result.service_files[]` — auxiliary files (subtitles `.srt`/`.vtt`/`.lrc`,
  alignment) for TTS orders. A flat array of paths, downloaded through
  `POST /storage/url` just like the main files. Absent for `sfx`/`music`.
- The template and service used. `template.config` holds the settings this order runs
  with: the template configuration at creation time with `config_override` applied;
  editing or deleting the template does not change it (orders created before late
  September 2026 have no snapshot — there it is the current template configuration
  with `config_override`).
- `items[]` — the order's chunks.

> A failed order (`failed`/`compensated`) returns `result: null` — no error detail is
> exposed here. `result.user_message` is usually `null`: it is a pass-through field
> from the worker, not a guaranteed status text.

**Required key permission:** `orders.read`.

- Required scope: `orders.read`

## Request

```bash
curl -X GET 'https://api.lumean.app/api/public/orders/{order}' \
  -H 'Accept: application/json' \
  -H 'X-API-KEY: YOUR_API_KEY'
```

## Parameters

| Field | In | Type | Req. | Description |
| --- | --- | --- | --- | --- |
| `order` | path | `string` | required | Order UUID — 36 characters shaped like `9f8b2c1a-4d3e-4f5a-8b9c-0d1e2f3a4b5c`, not a number. Take it from the `id` field: `POST /orders` returns it on creation and `GET /orders` lists it. Someone else’s order will not open with your key — you get a `404`. default: `9f8b2c1a-4d3e-4f5a-8b9c-0d1e2f3a4b5c` |

## Request body

No body.

## Responses

### 200 — Success. The payload is in `data`.

**Response fields**

| Field | Type | Req. | Description |
| --- | --- | --- | --- |
| `success` | `boolean` | required | 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` | required | 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` | `Order` | required | The full order, including its chunks in `items` and file paths in `result`. |
| `data.id` | `string` | required | Order UUID. Use it in `/orders/{order}/…` paths and when calling `POST /orders/{order}/retry`. |
| `data.user_id` | `integer` | required | ID of the order owner. For orders created with an API key this is always the key owner — a key never sees someone else’s order. |
| `data.name` | `string` | required | Order name: the downloaded file name and the ZIP archive name are derived from it. |
| `data.template` | `Template` | — | The template the order was created from. Present only for orders that have a `template_id`; template-less orders (`sfx`/`music` created by `task_type`) omit it. Its `config` holds the settings THIS order runs with: the template configuration at the moment the order was created, with `config_override` applied on top; editing the template later does not change it. In the `GET /orders` list `config` is `null` — the full configuration comes from `GET /orders/{order}`. The template may have been deleted since: it is still shown here, but `GET /templates/{template}` returns `404` and a new order with that `template_id` returns `422`. Orders created before this API version (late September 2026) have no snapshot: their `config` is the current template configuration with `config_override` applied, and editing the template changes it. |
| `data.template.id` | `string` | required | Template UUID. Put it into `template_id` when creating an order. |
| `data.template.user_id` | `integer` | required | ID of the template owner. |
| `data.template.slug` | `string` | required | Short public identifier used for sharing. `null` on a template that was never shared. |
| `data.template.name` | `string` | required | Template name — for humans only; it does not affect generation. |
| `data.template.service_key` | `string` | required | Code of the service whose schema validates `config`: `elevenlabs`, `lumimg`, and so on. |
| `data.template.service` | `Service \| null` — nullable | required | The template’s service for reference: name and pricing, without configuration schemas. `null` means no service with that code exists any more. |
| `data.template.config` | `object` | required | 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.template.is_public` | `boolean` | required | Whether the template is published in the shared catalogue. |
| `data.template.folder_id` | `string` | required | UUID of the folder holding the template, or `null` for the root. The folder tree is visible in `GET /templates/browse`. |
| `data.template.created_at` | `string` — date-time — nullable | required | When the template was created, ISO 8601. |
| `data.template.updated_at` | `string` — date-time — nullable | required | When the template last changed, ISO 8601. |
| `data.template_id` | `string` | required | UUID of the template used, or `null` when the order was created without one. |
| `data.task_type` | `TaskType` — `tts` · `image` · `txt2img` · `remix` · `image_edit` · `voice_clone` · `sfx` · `music` · `voice_search` | required | Task type — it determines what goes into `task_data` and what comes back in `result`. |
| `data.status` | `OrderStatus` — `created` · `pending` · `in_progress` · `completed` · `result_delivered` · `failed` · `compensated` · `cancelled` · `partially_completed` | required | Current state of the order. Terminal values are `completed`, `failed`, `cancelled` and `compensated` — there is nothing to poll for after those. `partially_completed` means some chunks succeeded and some failed: the finished files are already downloadable, and the failed fragments can be requeued via `POST /orders/{order}/items/retry-failed`. |
| `data.price_units` | `integer` | required | The amount locked for the order, in LMC minor units. Do not display this number as-is: the real value is `price_units / 10^precision`, where `precision` comes from the asset alongside. A display-ready value sits in the neighbouring decimal field. |
| `data.price_formatted` | `number` — nullable | required | The same amount as `price_units`, expressed in whole LMC and ready to display. `null` until the cost is settled. |
| `data.currency_asset` | `Asset` | required | The amount's asset is always LMC. Its `precision` is what converts minor units into the real value. |
| `data.currency_asset.id` | `integer` | required | Internal identifier of the asset. |
| `data.currency_asset.code` | `string` | required | Asset code: `LUMC` is the internal currency, `TOKEN` the generation tokens. |
| `data.currency_asset.kind` | `AssetKind` — `money` · `unit` | required | Kind of asset: money or consumable units. It decides whether an amount counts as a payment or as quota consumption. |
| `data.currency_asset.precision` | `integer` | required | Number of decimal places. **The load-bearing field:** every integer amount in this asset is divided by `10^precision` to obtain the real value. Do not assume the divisor is 100. |
| `data.currency_asset.name` | `string` | required | Display name of the asset, in the account language. |
| `data.currency_asset.deleted_at` | `string` — date-time — nullable | required | When the asset was retired, ISO 8601. `null` while it is in use. |
| `data.currency_asset.created_at` | `string` — date-time — nullable | required | When the asset was created, ISO 8601. |
| `data.currency_asset.updated_at` | `string` — date-time — nullable | required | When the asset last changed, ISO 8601. |
| `data.total_tokens` | `integer` — nullable | required | The order's full cost in tokens: the original chunks plus every retry and regeneration. This is a quota unit, not money. |
| `data.total_duration_ms` | `integer` — nullable | required | Total length of the produced audio in milliseconds. This is the result's duration, not the time spent generating it. |
| `data.task_data` | `object` — nullable | required | The task input exactly as the server accepted it: text, references to uploaded files, resolved settings. The set of keys depends on `task_type`. |
| `data.result` | `object` — nullable | required | Execution result. `files[]` holds the primary files; `service_files[]` holds auxiliary ones (subtitles `.srt`/`.vtt`/`.lrc`, alignment) for TTS orders. Paths are **absolute** and ready to pass to `POST /storage/url`. `null` while the order is unfinished, and also for a failed order: the public surface does not expose error internals. |
| `data.created_at` | `string` — date-time — nullable | required | When the order was created, ISO 8601. |
| `data.updated_at` | `string` — date-time — nullable | required | When the order last changed, ISO 8601. It advances on every status transition, which makes it a cheap “something happened” signal. |
| `data.files_expire_at` | `string` — nullable | required | Retention of the order's files. `files_expire_at` is the deletion moment (`null` when the order has not finished yet, or the files are already gone); `files_expired` means nothing is left to download. |
| `data.files_expired` | `boolean` | required | `true` means retention has elapsed and the files are already deleted: no link can be issued, and the order has to be created again. |
| `data.retention` | `object` | required | Retention deadlines by file level. For a stitched order the per-fragment tracks are removed earlier than the result itself. |
| `data.retention.chunks` | `object` | required | Lifetime of the per-fragment tracks — pause editing, re-stitching and per-fragment regeneration all operate on them. |
| `data.retention.chunks.expires_at` | `string` | required | When the per-fragment tracks disappear, ISO 8601. Until then pause editing, re-stitching and per-fragment regeneration remain available. `null` means the order has not finished yet (the countdown has not started) or the fragments are already gone. |
| `data.retention.chunks.expired` | `boolean` | required | `true` means the per-fragment tracks are gone: editing and re-stitching are rejected. The finished result may still be available — check `retention.files`. |
| `data.retention.chunks.expires_early` | `boolean` | required | `true` means the fragments will disappear before the result (the order is stitched into a separate file). `false` means the fragments are the result, and both levels expire together. |
| `data.retention.chunks.reason` | `string` — `chunks_purged` · `storage_expired` · `null` — nullable | required | Why the fragments are unavailable: `chunks_purged` — removed on their own schedule while the result is still there; `storage_expired` — every file of the order is gone. `null` means the fragments are available. |
| `data.retention.files` | `object` | required | Lifetime of every file of the order, including the result. Mirrors the top-level `files_expire_at` / `files_expired` fields. |
| `data.retention.files.expires_at` | `string` — nullable | required | When every file of the order will be deleted, ISO 8601. The same value as `files_expire_at` — the top-level field is kept for compatibility. |
| `data.retention.files.expired` | `boolean` | required | Same as `files_expired`: nothing is left to download. |
| `data.eta_seconds` | `integer` — nullable | required | Estimated time remaining, in seconds — present only while the order is running. `null` once it is finished, and before it starts. |
| `data.eta_at` | `string` — date-time — nullable | required | Expected completion moment, ISO 8601 — the same forecast as `eta_seconds`, expressed as an absolute time. |
| `data.completed_chunks` | `integer` — nullable | required | How many source chunks are already finished. Retries and regenerations are excluded — counting them would push progress past 100%. |
| `data.total_chunks` | `integer` — nullable | required | How many source chunks the order has in total. Zero means the split has not happened yet. |
| `data.progress_percent` | `integer` — nullable | required | Completion percentage, 0–100 — derived from `completed_chunks` and `total_chunks`, so there is no need to compute it yourself. |
| `data.stitching` | `boolean` | required | `true` means the audio is being stitched and the result is not final yet. This also happens with `status = completed`: after a fragment is regenerated the final track is rebuilt, and until stitching ends `result` points to the previous track. Download the result once `stitching = false`. |
| `data.paragraphs` | `array<object>` — nullable | required | Per-paragraph summary: index, fragment count, aggregate status and progress. `null` means the order uses ordinary mode — use `items[]` instead. To get paragraphs, create the order with `config_override.generation_mode = paragraph` (see that field for details). |
| `data.paragraphs[].paragraph_index` | `integer` | required | Zero-based index of the paragraph. |
| `data.paragraphs[].chunks_count` | `integer \| number` | required | How many chunks the paragraph was split into. |
| `data.paragraphs[].completed_chunks` | `string \| integer` | required | How many of the paragraph’s chunks are already finished. |
| `data.paragraphs[].status` | `string` | required | Aggregate status of the paragraph: derived from its chunks’ statuses rather than stored separately. It uses its own, shorter vocabulary: `pending`, `in_progress`, `failed`, `completed` — a chunk blocked by moderation also reads as `failed`. Only the original chunks count, so a successful retry of a failed fragment does NOT change the paragraph status: check the fragment itself in `items[]`. |
| `data.paragraphs[].progress_percent` | `integer` | required | Paragraph completion percentage, 0–100. |
| `data.paragraphs[].result_file` | `string` — nullable | required | The whole paragraph stitched into one audio file: an absolute path, or a structure carrying path and size. Download it via `POST /storage/url`, same as the other order files. `null` means two different things depending on `chunks_count`: with `chunks_count = 1` the paragraph has no file of its own and never will — the paragraph *is* that single fragment, so take its `result_file` from `items[]` under the same `paragraph_index`; with `chunks_count > 1` the stitch has not happened yet — a multi-chunk paragraph gets its file ONLY after stitching, never in advance. |
| `data.items` | `array<OrderItem>` | — | The order’s chunks. Present in the detailed `GET /orders/{order}` response; the list endpoint `GET /orders` omits the field — use `GET /orders/{order}/items` instead. |
| `data.items[].id` | `string` | required | Chunk UUID. Use it in `/orders/{order}/items/{item}/…` paths. |
| `data.items[].order_id` | `string` | required | UUID of the order this chunk belongs to. |
| `data.items[].item_type` | `string` | required | What the record is: `chunk` is an original fragment, `retry` a free re-run of a failed one, `regeneration` a paid redo of a finished one. Retries and regenerations are separate records sharing the same `chunk_index`: the full attempt history is kept, and the last one is what the result plays. |
| `data.items[].chunk_index` | `integer` — nullable | required | Zero-based position of the fragment within the order. It defines the order in which the final file is assembled. |
| `data.items[].paragraph_index` | `string` | required | The paragraph this fragment belongs to — filled in only for the original fragments of a paragraph-mode order. It is `null` both in ordinary mode and on retry or regeneration records: those carry no paragraph link of their own and inherit it from the parent fragment via `parent_item_id`. The mode is switched on by the `generation_mode` key in the order's `config_override`. |
| `data.items[].parent_item_id` | `string` | required | UUID of the source chunk — present on `retry` and `regeneration` records. `null` on an original chunk. |
| `data.items[].original_text_length` | `integer` | required | Length of the text the fragment was created with. It is the ceiling for `text` in `regenerate`. |
| `data.items[].current_text_length` | `integer` | required | Length of the fragment’s current text: after a regeneration it differs from `original_text_length`. |
| `data.items[].price_units` | `integer` | required | Cost of the fragment in **tokens** — not money. The monetary amount lives on the order itself, in its own `price_units` field (LMC there, tokens here; the names match, the units do not). |
| `data.items[].consumed_units` | `integer` | required | How many tokens were actually charged for this fragment. Zero while the fragment is unfinished. |
| `data.items[].remaining_locked` | `integer` | required | How many tokens are still reserved for the fragment. Drops to zero once the fragment finishes or is cancelled. |
| `data.items[].status` | `string` | required | Fragment state: `pending` waits for a worker, `processing` is in flight, `completed` is done, `failed` hit a technical error, and `policy_flagged` was rejected by the content policy. The difference between the last two dictates the fix: `failed` is cured by retrying as is, whereas `policy_flagged` requires rewording — retrying the same text is rejected again. |
| `data.items[].result_file` | `object \| string \| null` — nullable | required | The finished fragment’s file: an absolute path, or a structure carrying path and size. Download it via `POST /storage/url`, same as order files. `null` until the fragment is ready. |
| `data.items[].duration_ms` | `integer` — nullable | required | Duration of the produced audio in milliseconds — the length of the recording, not the generation time. `null` for non-audio tasks. |
| `data.items[].attempt_number` | `integer` | required | Attempt number for this fragment, starting at 1. It grows with every retry. |
| `data.items[].can_retry` | `boolean` | required | Whether a free retry is allowed right now. It already accounts for status, task type and exhausted attempts, so you need not re-check the conditions. |
| `data.items[].can_regenerate` | `boolean` | required | Whether a paid regeneration is allowed right now. Available for finished fragments only. |
| `data.items[].created_at` | `string` — date-time — nullable | required | When the fragment was created, ISO 8601. |
| `data.items[].updated_at` | `string` — date-time — nullable | required | When the fragment last changed, ISO 8601. |
| `data.items[].failure_reason` | `string` — nullable | — | Machine-readable failure reason — present only on `failed` and `policy_flagged`. Everything else gets `null`. |
| `data.tokens_from_quota` | `integer` — nullable | — | How many of the spent tokens were covered by the subscription quota. `null` means the quota covered nothing. |
| `data.tokens_from_payg` | `integer` — nullable | — | How many tokens were paid for out of the LMC balance, beyond the quota. `null` means there was no top-up. |
| `data.tokens_spent` | `integer` — nullable | — | The sum of the two fields above: how many tokens were charged for the order (quota + top-up). Orders covered by an unlimited subscription and free versions are excluded — an unlimited order has `null` here; the generated volume is `total_tokens`. Retries are excluded — they are not billed again. |
| `data.queue_position` | `integer` — nullable | — | Position in the queue — only for voice-search tasks (`voice_search`), which are processed one at a time. Other task types omit the field. |
| `data.queue_wait_seconds` | `integer` — nullable | — | Estimated wait in the voice-search queue, in seconds. An estimate, not a promise — recomputed on every response. |

**Example**

```json
{
  "success": true,
  "message": "Order loaded successfully.",
  "data": {
    "id": "9f8b2c1a-4d3e-4f5a-8b9c-0d1e2f3a4b5c",
    "user_id": 501,
    "template": {
      "id": "7e2a4c1d-8b3f-4a5e-9c6d-1f2e3a4b5c6d",
      "user_id": 501,
      "slug": null,
      "name": "Narrator Voice (EN)",
      "service_key": "elevenlabs",
      "service": {
        "id": 3,
        "code": "elevenlabs",
        "name": "ElevenLabs",
        "display_name": "ElevenLabs TTS",
        "payg_access": "everyone",
        "billing_mode": "pay_as_you_go",
        "unit_asset_id": 5,
        "unit_asset": {
          "id": 5,
          "code": "tts_units",
          "kind": "unit",
          "precision": 0,
          "name": "TTS Units",
          "deleted_at": null,
          "created_at": "2026-01-10T09:00:00+00:00",
          "updated_at": "2026-01-10T09:00:00+00:00"
        },
        "required_entitlement_id": null,
        "units_per_call": null,
        "units_per_char": 1,
        "units_per_image": null,
        "units_per_second": null,
        "min_billable_chars": 1,
        "lumcoin_per_token": 10,
        "lumc_precision": 2,
        "price_lumc_minor": null,
        "unit_size": 1,
        "uses_money_first_pricing": false,
        "rate_unit": "char",
        "display_category": "voice",
        "is_premium": false,
        "display_order": 1,
        "metadata": null,
        "is_active": true,
        "created_at": "2026-01-10T09:00:00+00:00",
        "updated_at": "2026-01-10T09:00:00+00:00"
      },
      "config": {
        "tts_settings": {
          "model_id": "eleven_multilingual_v2",
          "voice_id": "21m00Tcm4TlvDq8ikWAM",
          "mode": "mode_v1",
          "language_code": null,
          "advanced_voice_settings": true,
          "voice_settings": {
            "stability": 0.5,
            "similarity_boost": 0.75,
            "use_speaker_boost": true
          }
        }
      },
      "is_public": false,
      "folder_id": null,
      "created_at": "2026-06-01T10:00:00+00:00",
      "updated_at": "2026-06-01T10:00:00+00:00"
    },
    "template_id": "7e2a4c1d-8b3f-4a5e-9c6d-1f2e3a4b5c6d",
    "task_type": "tts",
    "status": "completed",
    "price_units": 420,
    "total_tokens": 420,
    "task_data": {
      "text": "Welcome to our platform! This narration greets every new listener.",
      "total_length": 420
    },
    "result": {
      "user_message": null,
      "files": [
        "storage/501/orders/9f8b2c1a-4d3e-4f5a-8b9c-0d1e2f3a4b5c/output/final/result.mp3"
      ],
      "service_files": [
        "storage/501/orders/9f8b2c1a-4d3e-4f5a-8b9c-0d1e2f3a4b5c/output/final/service/subtitles.srt",
        "storage/501/orders/9f8b2c1a-4d3e-4f5a-8b9c-0d1e2f3a4b5c/output/final/service/subtitles.vtt",
        "storage/501/orders/9f8b2c1a-4d3e-4f5a-8b9c-0d1e2f3a4b5c/output/final/service/result.json"
      ]
    },
    "created_at": "2026-07-17T12:00:00+00:00",
    "updated_at": "2026-07-17T12:02:50+00:00",
    "eta_seconds": null,
    "eta_at": null,
    "completed_chunks": 2,
    "total_chunks": 2,
    "progress_percent": 100,
    "items": [
      {
        "id": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
        "order_id": "9f8b2c1a-4d3e-4f5a-8b9c-0d1e2f3a4b5c",
        "item_type": "chunk",
        "chunk_index": 0,
        "parent_item_id": null,
        "original_text_length": 240,
        "current_text_length": 240,
        "price_units": 240,
        "consumed_units": 240,
        "remaining_locked": 0,
        "status": "completed",
        "result_file": {
          "path": "storage/501/orders/9f8b2c1a-4d3e-4f5a-8b9c-0d1e2f3a4b5c/output/chunks/0/result.mp3",
          "storage": "s3",
          "name": "chunk_0.mp3",
          "size": 512340,
          "mime_type": "audio/mpeg",
          "size_formatted": "500.33 KB"
        },
        "attempt_number": 1,
        "can_retry": false,
        "can_regenerate": true,
        "created_at": "2026-07-17T12:00:05+00:00",
        "updated_at": "2026-07-17T12:02:10+00:00"
      },
      {
        "id": "e5f6a7b8-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
        "order_id": "9f8b2c1a-4d3e-4f5a-8b9c-0d1e2f3a4b5c",
        "item_type": "chunk",
        "chunk_index": 1,
        "parent_item_id": null,
        "original_text_length": 180,
        "current_text_length": 180,
        "price_units": 180,
        "consumed_units": 180,
        "remaining_locked": 0,
        "status": "completed",
        "result_file": {
          "path": "storage/501/orders/9f8b2c1a-4d3e-4f5a-8b9c-0d1e2f3a4b5c/output/chunks/1/result.mp3",
          "storage": "s3",
          "name": "chunk_1.mp3",
          "size": 398210,
          "mime_type": "audio/mpeg",
          "size_formatted": "388.88 KB"
        },
        "attempt_number": 1,
        "can_retry": false,
        "can_regenerate": true,
        "created_at": "2026-07-17T12:00:05+00:00",
        "updated_at": "2026-07-17T12:02:45+00:00"
      }
    ]
  }
}
```

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

**Response fields**

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

**Example**

```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.

**Response fields**

| Field | Type | Req. | Description |
| --- | --- | --- | --- |
| `message` | `string` | required | Error overview. |

**Example**

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

### 404 — Not found, or not reachable with this key.

**Response fields**

| Field | Type | Req. | Description |
| --- | --- | --- | --- |
| `success` | `boolean` | required | Always `false` in error responses. |
| `message` | `string` | required | Error text in the key's language (set through the `X-Locale` header). |
| `reason` | `string` | — | Machine-readable reason — present on business refusals (for example, `invalid_order_status`); other errors omit it. Branch on it, not on the message text. |
| `error_code` | `string` | — | The same machine-readable code as in `reason` — a second name for the field. Arrives together with `reason`; the values always match. |

**Example**

```json
{
  "success": false,
  "message": "Resource not found."
}
```

---

- This page in the browser: https://lumean.app/en/developers/docs/api/get-orders-order
- Full machine-readable reference: https://api.lumean.app/docs/llm.md
