-
Notifications
You must be signed in to change notification settings - Fork 12
docs: pipeline-generated pages (?, Languages, Voice) #446
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,173 @@ | ||||||||||
| --- | ||||||||||
| title: "Query supported languages for a resource" | ||||||||||
| description: "Use GET /v3/languages to fetch which languages and features a specific DeepL API resource supports, then filter and use that data in your integration." | ||||||||||
| covers: [Languages] | ||||||||||
| --- | ||||||||||
|
|
||||||||||
| The `/v3/languages` endpoint tells you exactly which languages a given DeepL API resource supports, whether each language can be used as a source, target, or both, and which optional features (formality, glossaries, tag handling) are available per language. | ||||||||||
|
|
||||||||||
| This guide shows you how to query languages for a specific resource and use the response to drive language validation and feature detection in your integration. | ||||||||||
|
|
||||||||||
| <Info> | ||||||||||
| The `/v3/languages` endpoint replaces the deprecated `/v2/languages` endpoint. If you're currently using `/v2/languages`, see the [migration guide](/docs/languages/migrating-from-v2-languages) for differences and code examples. | ||||||||||
| </Info> | ||||||||||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Info box references a migration guide that may not exist The
Suggested change
|
||||||||||
|
|
||||||||||
| ## Prerequisites | ||||||||||
|
|
||||||||||
| - A DeepL API key. Find yours on your [account page](https://www.deepl.com/your-account/keys). | ||||||||||
| - If you're on the free plan, replace `https://api.deepl.com` with `https://api-free.deepl.com` in all examples below. | ||||||||||
|
|
||||||||||
| ## Step 1: Choose a resource | ||||||||||
|
|
||||||||||
| The `resource` parameter is required. It tells the endpoint which DeepL API product you're querying language support for: | ||||||||||
|
|
||||||||||
| | **Value** | **Product** | | ||||||||||
| |---|---| | ||||||||||
| | `translate_text` | Text translation (`/v2/translate`) | | ||||||||||
| | `translate_document` | Document translation (`/v2/document`) | | ||||||||||
| | `voice` | Speech transcription and translation (`/v3/voice`) | | ||||||||||
| | `write` | Text improvement (`/v2/write`) | | ||||||||||
| | `glossary` | Glossary management | | ||||||||||
| | `style_rules` | Style rules | | ||||||||||
| | `translation_memory` | Translation memories | | ||||||||||
|
|
||||||||||
| For this guide, we'll use `translate_text`. | ||||||||||
|
|
||||||||||
| ## Step 2: Fetch the language list | ||||||||||
|
|
||||||||||
| Make a `GET` request to `/v3/languages` with your chosen resource: | ||||||||||
|
|
||||||||||
| ```sh | ||||||||||
| curl -X GET 'https://api.deepl.com/v3/languages?resource=translate_text' \ | ||||||||||
| --header 'Authorization: DeepL-Auth-Key YOUR_API_KEY' | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| The response is a JSON array. Each entry describes one language and its capabilities for the requested resource: | ||||||||||
|
|
||||||||||
| Example response (truncated): | ||||||||||
|
|
||||||||||
| ```json | ||||||||||
| [ | ||||||||||
| { | ||||||||||
| "lang": "de", | ||||||||||
| "name": "German", | ||||||||||
| "status": "stable", | ||||||||||
| "usable_as_source": true, | ||||||||||
| "usable_as_target": true, | ||||||||||
| "features": { | ||||||||||
| "formality": { "status": "stable" }, | ||||||||||
| "glossary": { "status": "stable" }, | ||||||||||
| "tag_handling": { "status": "stable" } | ||||||||||
| } | ||||||||||
| }, | ||||||||||
| { | ||||||||||
| "lang": "en", | ||||||||||
| "name": "English", | ||||||||||
| "status": "stable", | ||||||||||
| "usable_as_source": true, | ||||||||||
| "usable_as_target": false, | ||||||||||
| "features": { | ||||||||||
| "glossary": { "status": "stable" }, | ||||||||||
| "tag_handling": { "status": "stable" } | ||||||||||
| } | ||||||||||
| }, | ||||||||||
| { | ||||||||||
| "lang": "en-US", | ||||||||||
| "name": "English (American)", | ||||||||||
| "status": "stable", | ||||||||||
| "usable_as_source": false, | ||||||||||
| "usable_as_target": true, | ||||||||||
| "features": { | ||||||||||
| "glossary": { "status": "stable" }, | ||||||||||
| "tag_handling": { "status": "stable" } | ||||||||||
| } | ||||||||||
| } | ||||||||||
| ] | ||||||||||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Step 3 output does not show example console output The Python snippet prints to stdout but no expected output is shown. Other steps show responses; consistency suggests showing the expected print output here (e.g. 'Source languages: 31 / Target languages: 33') so readers can verify they're on track. Suggested fix: Add a comment block or a separate code block after the snippet showing expected output, e.g.: |
||||||||||
| ``` | ||||||||||
|
|
||||||||||
| Notice that `en` and `en-US` are separate entries: `en` is source-only, and `en-US` is target-only. Some languages have regional or script variants like this — always check `usable_as_source` and `usable_as_target` rather than assuming a language code is valid in both roles. | ||||||||||
|
|
||||||||||
| <Warning> | ||||||||||
| Do not hardcode assumptions about language code format. Codes follow BCP 47 and can vary significantly — `de`, `en-US`, `zh-Hans` are all valid. Treat language codes as opaque identifiers and store them as strings. See the [language release process](/docs/resources/language-release-process) for details. | ||||||||||
| </Warning> | ||||||||||
|
|
||||||||||
| ## Step 3: Separate source and target languages | ||||||||||
|
|
||||||||||
| Filter the response by `usable_as_source` and `usable_as_target` to build your source and target language lists: | ||||||||||
|
|
||||||||||
| ```python | ||||||||||
| import urllib.request | ||||||||||
| import urllib.parse | ||||||||||
| import json | ||||||||||
|
|
||||||||||
| API_KEY = "YOUR_API_KEY" | ||||||||||
|
|
||||||||||
| # Fetch languages for text translation | ||||||||||
| url = "https://api.deepl.com/v3/languages?resource=translate_text" | ||||||||||
| req = urllib.request.Request( | ||||||||||
| url, | ||||||||||
| headers={"Authorization": f"DeepL-Auth-Key {API_KEY}"} | ||||||||||
| ) | ||||||||||
| with urllib.request.urlopen(req) as response: | ||||||||||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Step 4 comment logic for 'all other features' is stated as a rule but may be inaccurate The comment 'All other features (glossary, tag_handling) require both languages to support them' asserts a product rule inline. If this rule is wrong or changes, the code silently misbehaves. The guide says to see the API reference for full details, but the comment presents it as definitive. Either remove the assertion and defer to the reference, or cite the reference inline. Suggested fix: Change the comment to: '# For glossary and tag_handling, check both languages — see the API reference for the exact rules per resource.' and remove the implied guarantee that this covers all cases. |
||||||||||
| languages = json.loads(response.read()) | ||||||||||
|
|
||||||||||
| # Separate source and target languages | ||||||||||
| source_languages = [lang for lang in languages if lang["usable_as_source"]] | ||||||||||
| target_languages = [lang for lang in languages if lang["usable_as_target"]] | ||||||||||
|
|
||||||||||
| print(f"Source languages: {len(source_languages)}") | ||||||||||
| print(f"Target languages: {len(target_languages)}") | ||||||||||
|
|
||||||||||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Step 4 function does not handle missing lang_by_code keys The example calls Suggested fix: Add a guard before the call, e.g. |
||||||||||
| # Build a lookup by language code | ||||||||||
| lang_by_code = {lang["lang"]: lang for lang in languages} | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| ## Step 4: Check feature support for a language pair | ||||||||||
|
|
||||||||||
| Before making a translation request with an optional feature (formality, glossary, tag handling), check whether the relevant languages support it. Each language entry includes a `features` object listing which optional features it supports. Check this object for both source and target languages before using a feature in a request. For full details on which languages must support a feature for each resource, see the [API reference for `GET /v3/languages`](/api-reference/languages/retrieve-languages-by-resource). | ||||||||||
|
|
||||||||||
| The `features` dict on each language entry from Step 3 contains exactly the features that language supports — you can check this directly without any additional API calls: | ||||||||||
|
|
||||||||||
| ```python | ||||||||||
| # Requires lang_by_code from Step 3 | ||||||||||
|
|
||||||||||
| def feature_supported(source_lang, target_lang, feature_name): | ||||||||||
| """Return True if the feature is available for the given language pair.""" | ||||||||||
| # Formality only needs to be supported by the target language, | ||||||||||
| # because it affects how the output is phrased, not how the source is parsed. | ||||||||||
| if feature_name == "formality": | ||||||||||
| return feature_name in target_lang.get("features", {}) | ||||||||||
|
|
||||||||||
| # All other features (glossary, tag_handling) require both languages to support them. | ||||||||||
| source_ok = feature_name in source_lang.get("features", {}) | ||||||||||
| target_ok = feature_name in target_lang.get("features", {}) | ||||||||||
| return source_ok and target_ok | ||||||||||
|
|
||||||||||
|
|
||||||||||
| # Example: check if formality is supported for English → German | ||||||||||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Step 5 lacks an example response All other steps that make an API call (Steps 2, 3) show a response. Step 5 adds the Suggested fix: Add a truncated example JSON response showing at least one language entry with |
||||||||||
| source = lang_by_code.get("en") | ||||||||||
| target = lang_by_code.get("de") | ||||||||||
|
|
||||||||||
| print(feature_supported(source, target, "formality")) | ||||||||||
| # True — German supports formality as a target language | ||||||||||
|
|
||||||||||
| print(feature_supported(source, target, "glossary")) | ||||||||||
| # True — English and German both support glossary | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| ## Step 5: Include beta languages (optional) | ||||||||||
|
|
||||||||||
| By default, the endpoint returns only `stable` languages. To include `beta` languages, add `include=beta`: | ||||||||||
|
|
||||||||||
| ```sh | ||||||||||
| curl -X GET 'https://api.deepl.com/v3/languages?resource=translate_text&include=beta' \ | ||||||||||
| --header 'Authorization: DeepL-Auth-Key YOUR_API_KEY' | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| Each language and each feature entry carries a `status` field: `stable`, `beta`, or `early_access`. If you include beta languages, filter on this field before exposing them to end users or using them in production workflows. | ||||||||||
|
|
||||||||||
| ## Next steps | ||||||||||
|
|
||||||||||
| - See [Using the Languages API](/docs/languages/using-the-languages-api) for additional query patterns and examples | ||||||||||
| - Review the [API reference for `GET /v3/languages`](/api-reference/languages/retrieve-languages-by-resource) and [`GET /v3/languages/resources`](/api-reference/languages/retrieve-resources) | ||||||||||
| - If you're migrating from `/v2/languages`, see the [migration guide](/docs/languages/migrating-from-v2-languages) | ||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,177 @@ | ||||||||||||||||||
| --- | ||||||||||||||||||
| title: "Translate a Pre-Recorded Audio File" | ||||||||||||||||||
| description: "Submit a pre-recorded audio file for translation, poll for results, and download translated transcripts or audio using the Voice Translate Job API." | ||||||||||||||||||
| covers: [Translate Audio Files] | ||||||||||||||||||
| --- | ||||||||||||||||||
|
|
||||||||||||||||||
| The Voice Translate Job API translates pre-recorded audio files asynchronously. Unlike the real-time Voice API (which streams live audio over WebSocket), this API accepts an uploaded audio file and returns one or more translated outputs: plain text transcripts, SRT subtitles, or translated speech audio. Use it for podcasts, meeting recordings, video files, and other pre-recorded content. | ||||||||||||||||||
|
|
||||||||||||||||||
| This guide walks through the complete workflow: creating a job, uploading your audio file, polling for results, and downloading them. | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Prerequisites | ||||||||||||||||||
|
|
||||||||||||||||||
| - A DeepL API account with Voice Translate Job API access (currently closed alpha — contact your customer success manager to request access) | ||||||||||||||||||
| - `curl` for running the examples | ||||||||||||||||||
| - An audio file to translate (see [Supported Source Audio Formats](/api-reference/jobs-voice-translate/create-voice-translate-job#supported-source-audio-formats) for accepted formats) | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Overview of the workflow | ||||||||||||||||||
|
|
||||||||||||||||||
| Translating an audio file takes four steps: | ||||||||||||||||||
|
|
||||||||||||||||||
| 1. Create a job to tell the API what outputs you want | ||||||||||||||||||
| 2. Upload your audio file to the URL returned in step 1 | ||||||||||||||||||
| 3. Poll the job status until all targets are complete | ||||||||||||||||||
| 4. Download each completed result | ||||||||||||||||||
|
|
||||||||||||||||||
| Steps 1 and 2 must happen within 5 minutes of each other. After all results are downloaded, the job is deleted. | ||||||||||||||||||
|
|
||||||||||||||||||
| <Tip> | ||||||||||||||||||
| API Free users should use `https://api-free.deepl.com` in place of `https://api.deepl.com` in all requests below. | ||||||||||||||||||
| </Tip> | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Step 1: Create a job | ||||||||||||||||||
|
|
||||||||||||||||||
| Send a POST request to `/v1/jobs/voice/translate` describing your source file and the outputs you want. You must declare the source file's `content_length` (in bytes) and `content_type` before uploading — the API uses these to prepare the upload URL. | ||||||||||||||||||
|
|
||||||||||||||||||
| This example translates an English MP3 into a German plain-text transcript and a Spanish PCM audio file: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| curl -X POST https://api.deepl.com/v1/jobs/voice/translate \ | ||||||||||||||||||
| -H "Authorization: DeepL-Auth-Key YOUR_AUTH_KEY" \ | ||||||||||||||||||
| -H "Content-Type: application/json" \ | ||||||||||||||||||
| -d '{ | ||||||||||||||||||
| "source_file": { | ||||||||||||||||||
| "name": "podcast-episode-42.mp3", | ||||||||||||||||||
| "content_type": "audio/mpeg", | ||||||||||||||||||
| "content_length": 15728640 | ||||||||||||||||||
| }, | ||||||||||||||||||
| "parameters": { | ||||||||||||||||||
| "source_language": "en" | ||||||||||||||||||
| }, | ||||||||||||||||||
| "targets": [ | ||||||||||||||||||
| { "language": "de", "type": "text/plain" }, | ||||||||||||||||||
| { "language": "es", "type": "audio/pcm;encoding=s16le;rate=16000" } | ||||||||||||||||||
| ] | ||||||||||||||||||
| }' | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| A successful response returns `201` with a `job_id`, an `upload_url`, and a `signature`: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```json | ||||||||||||||||||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Upload URL used verbatim in Step 2 curl example The curl command in Step 2 hardcodes the full upload_url value from the Step 1 response example. This is fine for illustration, but the text before it says 'PUT your audio file directly to the upload_url' without making it explicit that the reader should substitute the actual URL returned in their response, not copy this literal URL. A brief note or variable placeholder would prevent copy-paste confusion.
Suggested change
|
||||||||||||||||||
| { | ||||||||||||||||||
| "job_id": "a74d88fb-ed2a-4943-a664-a4512398b994", | ||||||||||||||||||
| "signature": "eyJhbGciOiJIUzI1NiIs...", | ||||||||||||||||||
| "upload_url": "https://assets.deepl.com/collections/a74d88fb-ed2a-4943-a664-a4512398b994/assets/b1c2d3e4-f5a6-7890-abcd-ef1234567890" | ||||||||||||||||||
| } | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| Save the `job_id` — you'll need it to poll status and download results. The `upload_url` is where you send the audio file in the next step. | ||||||||||||||||||
|
|
||||||||||||||||||
| For all supported output types, see [Supported Output Formats](/api-reference/jobs-voice-translate/create-voice-translate-job#supported-output-formats). For available languages, see the reference page. | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Step 2: Upload the audio file | ||||||||||||||||||
|
|
||||||||||||||||||
| PUT your audio file directly to the `upload_url`. Set `Content-Type` to match the `content_type` you declared in step 1, and `Content-Length` to the exact byte size. | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| curl -X PUT "https://assets.deepl.com/collections/a74d88fb-ed2a-4943-a664-a4512398b994/assets/b1c2d3e4-f5a6-7890-abcd-ef1234567890" \ | ||||||||||||||||||
| -H "Content-Type: audio/mpeg" \ | ||||||||||||||||||
| -H "Content-Length: 15728640" \ | ||||||||||||||||||
| --data-binary @podcast-episode-42.mp3 | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| A successful upload returns `200` with an empty body. Processing begins automatically once the upload completes. | ||||||||||||||||||
|
|
||||||||||||||||||
| <Warning> | ||||||||||||||||||
| You have 5 minutes from job creation to complete the upload. If you miss this window, the job expires and you'll need to create a new one. | ||||||||||||||||||
| </Warning> | ||||||||||||||||||
|
|
||||||||||||||||||
| The `Content-Length` header must exactly match the `content_length` you declared when creating the job. A mismatch results in a `400` error. | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Step 3: Poll for results | ||||||||||||||||||
|
|
||||||||||||||||||
| GET the job status by `job_id`. Each target in the `results` array has its own `status` field and progresses independently. | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| curl https://api.deepl.com/v1/jobs/voice/translate/a74d88fb-ed2a-4943-a664-a4512398b994 \ | ||||||||||||||||||
| -H "Authorization: DeepL-Auth-Key YOUR_AUTH_KEY" | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| While processing, the response looks like this: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```json | ||||||||||||||||||
| { | ||||||||||||||||||
| "job_id": "a74d88fb-ed2a-4943-a664-a4512398b994", | ||||||||||||||||||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Poll interval recommendation has no upper bound rationale The guide recommends polling every 5-10 seconds but gives no guidance on when to stop if the job appears stuck or on maximum expected processing time. Developers building production integrations may implement infinite polling loops. A brief note on a reasonable timeout or maximum wait time would help. Suggested fix: Add a sentence after 'Poll every 5-10 seconds.' such as: 'Processing time varies with file length; a 1-hour recording may take several minutes. If the job has not completed after 30 minutes, treat it as failed and file a support request.' |
||||||||||||||||||
| "operation": "translate", | ||||||||||||||||||
| "product": "voice", | ||||||||||||||||||
| "parameters": { "source_language": "en" }, | ||||||||||||||||||
| "source_file": { | ||||||||||||||||||
| "name": "podcast-episode-42.mp3", | ||||||||||||||||||
| "content_type": "audio/mpeg", | ||||||||||||||||||
| "content_length": 15728640 | ||||||||||||||||||
| }, | ||||||||||||||||||
| "targets": [ | ||||||||||||||||||
| { "language": "de", "type": "text/plain" }, | ||||||||||||||||||
| { "language": "es", "type": "audio/pcm;encoding=s16le;rate=16000" } | ||||||||||||||||||
| ], | ||||||||||||||||||
| "results": [ | ||||||||||||||||||
| { "status": "processing" }, | ||||||||||||||||||
| { "status": "processing" } | ||||||||||||||||||
| ], | ||||||||||||||||||
| "created_at": "2026-10-01T01:03:03.444Z", | ||||||||||||||||||
| "updated_at": "2026-10-01T04:03:03.333Z" | ||||||||||||||||||
| } | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| Results are returned in the same order as the `targets` array from your create request. | ||||||||||||||||||
|
|
||||||||||||||||||
| Poll every 5-10 seconds. When a target's status changes to `complete`, its result object includes a `download_url` and a `signature`: | ||||||||||||||||||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Step 4 audio file extension guidance is informal and incomplete The note 'use a file extension that matches the output format (.wav for PCM, .mp3 for MPEG, and so on)' is informal guidance without a pointer to a format reference. 'And so on' leaves developers to guess for other formats like SRT. A link to the supported output formats list would make this actionable. Suggested fix: Replace 'and so on' with a link: 'For a full list of output types and their conventional extensions, see Supported Output Formats.' |
||||||||||||||||||
|
|
||||||||||||||||||
| ```json | ||||||||||||||||||
| { | ||||||||||||||||||
| "results": [ | ||||||||||||||||||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Download expiry window (1 hour) and upload window (5 minutes) sourcing not cross-referenced to reference docs The 1-hour download expiry and 5-minute upload window are stated as facts in the guide, but there is no cross-reference to a reference page or requirements page that confirms these limits. If the limits change, this guide may go stale. The 'Voice API Requirements' link in Handling Failures covers rate/size limits but may not cover these time windows. Suggested fix: Add a parenthetical link after each time limit pointing to the canonical source, e.g. 'within 1 hour (see Voice API Requirements)' — or confirm the requirements page covers these windows and relies on it as the single source of truth. |
||||||||||||||||||
| { | ||||||||||||||||||
| "status": "complete", | ||||||||||||||||||
| "download_url": "https://assets.deepl.com/collections/a74d88fb/assets/c3d4e5f6", | ||||||||||||||||||
| "signature": "eyJhbGciOiJIUzI1NiIs..." | ||||||||||||||||||
| }, | ||||||||||||||||||
| { | ||||||||||||||||||
| "status": "failed", | ||||||||||||||||||
| "error": { "message": "processing failed" } | ||||||||||||||||||
| } | ||||||||||||||||||
| ] | ||||||||||||||||||
| } | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| Individual targets can reach `complete` or `failed` status independently. Don't wait for all targets before downloading completed ones — a job can have a mix of statuses at the same time. | ||||||||||||||||||
|
|
||||||||||||||||||
| For the full status lifecycle (`pending` → `uploaded` → `processing` → `complete`), see the [Get Job Status](/api-reference/jobs-voice-translate/get-voice-translate-job-status#result-status-lifecycle) reference. | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Step 4: Download results | ||||||||||||||||||
|
|
||||||||||||||||||
| GET each completed result from its `download_url`. No authentication header is required for the download — the URL itself is access-controlled. | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| curl -o german-transcript.txt \ | ||||||||||||||||||
| "https://assets.deepl.com/collections/a74d88fb/assets/c3d4e5f6" | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| For audio targets, use a file extension that matches the output format (`.wav` for PCM, `.mp3` for MPEG, and so on). | ||||||||||||||||||
|
|
||||||||||||||||||
| <Warning> | ||||||||||||||||||
| Download results within 1 hour of the upload completing. After this window, results expire and the job is deleted. Once a result is marked `downloaded`, assets are queued for deletion. | ||||||||||||||||||
| </Warning> | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Handling failures | ||||||||||||||||||
|
|
||||||||||||||||||
| If a target's status is `failed`, the `error.message` field describes what went wrong. A failure on one target doesn't affect the others — you can still download any that reached `complete`. | ||||||||||||||||||
|
|
||||||||||||||||||
| If the source file itself is invalid (wrong format, corrupted, or over 3 hours long), all targets will fail. Source audio over 3 hours is rejected even if the file is under 1 GB. For longer recordings, split the source into separate files and submit each as its own job. | ||||||||||||||||||
|
|
||||||||||||||||||
| For rate limits, file size limits, and concurrent job limits, see [Voice API Requirements](/docs/voice/voice-api-requirements). | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Next steps | ||||||||||||||||||
|
|
||||||||||||||||||
| - Check [Supported Source Audio Formats](/api-reference/jobs-voice-translate/create-voice-translate-job#supported-source-audio-formats) and [Supported Output Formats](/api-reference/jobs-voice-translate/create-voice-translate-job#supported-output-formats) for the full list of accepted inputs and producible outputs | ||||||||||||||||||
| - See the [Create Job](/api-reference/jobs-voice-translate/create-voice-translate-job) and [Get Job Status](/api-reference/jobs-voice-translate/get-voice-translate-job-status) endpoint references for complete request and response schemas | ||||||||||||||||||
| - For live audio, see the [Real-Time Voice Quickstart](/docs/voice/real-time-voice-quickstart) | ||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Frontmatter description could be more specific about the outcome
The description 'fetch which languages and features a specific DeepL API resource supports, then filter and use that data in your integration' is accurate but somewhat generic on the second half. It would be clearer if it named the concrete outcomes (source/target separation, feature detection).