---
title: "Upload and start an audio job"
method: POST
path: "/v1/files/generate"
tags: ["narrador files"]
---

# Upload and start an audio job

`POST /v1/files/generate`

## Request

- Base URL: `https://api.narrador.io`
- URL: `https://api.narrador.io/v1/files/generate`
- Auth: one of:
  - HTTP bearer
  - API key in header `x-api-key`

One-step narrador files flow: send a document as multipart (`file` field), JSON `url`, or JSON `text`. Creates the storage object and starts the same job as `POST /v1/files/jobs`. Poll `GET /v1/files/jobs/{jobId}` and `GET /v1/files/jobs/{jobId}/result`. Requires a `nrd_files_` key.

## Request body

- FilesGenerateJson: Provide exactly one of `url` or `text`. Optional `voiceId`/`accent` (both or neither). When omitted, narrador detects document language when possible (else `en-us`) and picks the first premium public voice for that language (deterministic catalog order), or the first economy voice in the same language if none. Unsupported detected languages or missing catalog voices finish with `failed_file_processing`; pass `voiceId` and `accent` explicitly. JSON bodies on `/v1/files` allow up to 2 MB (enough for 500,000 UTF-8 characters in `text`); larger payloads receive HTTP 413.
  - `url` string, uri: Public http(s) URL to fetch server-side (max 50 MB).
  - `text` string
  - `fileName` string
  - `voiceId` string, uuid
  - `accent` 'af-za' | 'am-et' | 'ar-ae' | 'ar-eg' | 'ar-iq' | 'ar-kw' | 'ar-ma' | 'ar-qa' | 'ar-sa' | 'az-az' | 'bn-bd' | 'bn-in' | 'cmn-cn' | 'ja-jp' | 'jv-id' | 'kk-kz' | 'km-kh' | 'ko-kr' | 'mn-mn' | 'my-mm' | 'ne-np' | 'ps-af' | 'si-lk' | 'so-so' | 'th-th' | 'vi-vn' | 'zh-cn' | 'zh-hk' | 'zh-tw' | 'yue-cn' | 'bg-bg' | 'bs-ba' | 'ca-es' | 'cs-cz' | 'da-dk' | 'de-de' | 'el-gr' | 'et-ee' | 'eu-es' | 'fi-fi' | 'fr-be' | 'fr-ca' | 'fr-ch' | 'fr-fr' | 'ga-ie' | 'hr-hr' | 'hu-hu' | 'hy-am' | 'is-is' | 'it-it' | 'lt-lt' | 'lv-lv' | 'nb-no' | 'nl-be' | 'nl-nl' | 'pl-pl' | 'pt-br' | 'pt-pt' | 'ro-ro' | 'ru-ru' | 'sk-sk' | 'sl-si' | 'sq-al' | 'sr-rs' | 'sv-se' | 'tr-tr' | 'uk-ua' | 'en-au' | 'en-ca' | 'en-gb' | 'en-hk' | 'en-ie' | 'en-in' | 'en-ke' | 'en-nz' | 'en-sg' | 'en-us' | 'en-za' | 'es-ar' | 'es-cl' | 'es-co' | 'es-cr' | 'es-cu' | 'es-do' | 'es-ec' | 'es-es' | 'es-mx' | 'es-pe' | 'es-pr' | 'es-py' | 'es-us' | 'es-ve' | 'gu-in' | 'hi-in' | 'kn-in' | 'ml-in' | 'mr-in' | 'pa-in' | 'ta-in' | 'ta-lk' | 'ta-my' | 'te-in' | 'fa-ir' | 'fil-ph' | 'he-il' | 'id-id' | 'ms-my' | 'mt-mt' | 'sw-ke' | 'ur-pk' | 'zu-za'
  - `callbackUrl` string, uri: Optional https URL on a public host for a single terminal job webhook (see Files job webhooks).

## Response `201`

Job created

- FilesJobCreated
  - `jobId` string, uuid
  - `projectId` string, uuid
  - `status` 'idle' | 'processing' | 'processed' | 'failed_file_processing' | 'generating' | 'failed_audio_generation' | 'completed'

## Other responses

- `400`: Invalid JSON/multipart body (Zod validation), or URL fetch failed.
- `401`: Unauthorized — missing or invalid API key (wrong prefix, revoked, or expired).
- `403`: Forbidden — API key scope does not match the endpoint (e.g. `nrd_x_` key on a narrador files route), insufficient narrador credits for a synchronous operation (e.g. narrador X generate), or other entitlement failure. narrador files jobs that run out of credits finish asynchronously with job status `not-enough-credits` instead of HTTP 403.
- `413`: JSON request body larger than **2mb** (Express body-parser limit on `/v1/files`). Response is the default HTML error page (`PayloadTooLargeError: request entity too large`), not `{ "error": "…" }`. Multipart `POST /v1/files/generate` uses separate file-size limits.
- `429`: Too many requests — API key verification rate limit exceeded (60 requests per 60 seconds per key).

---

[API](https://skmtc.dev/narrador/apis/narrador-api.md) · [All operations](https://skmtc.dev/narrador/apis/narrador-api/llms.txt) · [OpenAPI document](https://skmtc.dev/narrador/apis/narrador-api/revisions/e9f026c76832?raw)
