Loading...
Async
Getting started with asynchronous jobs
This guide details asynchronous translation options supported by Lexel Translate along with recommendations on when and how to implement asynchronous translation in your product.
What is asynchronous translation
Asynchronous translation provides a non-blocking method that splits job creation and job processing into two separate steps, rather than the single processing step in synchronous translation. The caller creates the job with POST /api/v1/translate/async and receives a response indicating job creation; the actual translation is then processed in the background by one or more workers. Once the translation request has completed, it can be accessed by either polling the status endpoint or receiving a completion webhook, then fetching the result.
Asynchronous translation is the right tool for workloads when at least one of the following is true:
- The translation request must not block the caller
- You need callback delivery or polling status
- The translation request exceeds synchronous request limits
- The translation request is not time-sensitive
Creating an asynchronous job
Asynchronous translation requests follow a structure similar to synchronous translation requests sent to POST /api/v1/translate under request.request_id and request.input.items. Single and batch payloads are both accepted. Each item takes an optional id (recommended for batch), txt, and per-item src or tgt, with root-level defaults as the fallback. Additional job-level controls include:
job.callbackUrlorjob.webhookProfileId, allowing the user to specify either a callback URL or a webhook profile.job.resultTtlSeconds, allowing a user-specified result retention window; defaults to 24 hours, and values above 7 days are rejected with a400.
If neither callback option is supplied, the job uses the enabled default webhook profile for the active scope when one exists. The full field list is in the asynchronous docs.
The create response includes statusUrl, resultUrl, and cancelUrl, so callers do not need to construct the paths themselves.
Job creation runs on API key or session auth; the authentication docs cover the headers, and keys are managed from the API keys docs. Per-item src and tgt values use the canonical language tags documented in the languages reference. You can try job creation, status polling, and result retrieval in the playground before writing code.
Tracking asynchronous job status
An asynchronous job exposes six states and nothing else: queued, running, completed, completed_with_errors, failed, and canceled. Callers poll the status endpoint and webhooks fire on completion. The four job routes are documented in the asynchronous docs:
POST /api/v1/translate/asynccreates a job and returns202 AcceptedwithjobId, the initialqueuedstatus, and status, result, and cancel URLs.GET /api/v1/translate/async/:jobIdreads the aggregated parent status, lifecycle timestamps, and per-item counters.GET /api/v1/translate/async/:jobId/resultfetches the final logical translation result.POST /api/v1/translate/async/:jobId/cancelcancels queued work; cancel-state conflicts return409.
The status response carries createdAt, startedAt, completedAt, resultExpiresAt, and a summary object with queuedItems, runningItems, completedItems, failedItems, and canceledItems. That model is the contract, so keep it stable and every caller keeps working.
How asynchronous jobs are processed
Asynchronous translation jobs are divided into one or more units, each handled independently, depending on the number of items in a job as well as the text length and split_input flag. Each unit is executed and retried independently by its worker, meaning:
- a failed unit retries without retrying the entire job. One bad file does not impact the rest of the batch.
- parallelization is safe, because units have no dependencies.
- progress reporting is useful, because there is something to count.
- per-item errors stay visible, so the failed item is named instead of folded into a single failed job.
Failure and retry behavior
When a unit fails, that unit retries without retrying the rest of the job. The summary counters show the split between completedItems and failedItems while the job runs. A terminal failure without a usable stored result returns 422, and the error field on the status response carries the reason.
For reproducible output, pin a stored glossary version with glossary_version_id on job items; the glossaries docs cover stored terminology selection and immutable versions.
Polling, webhooks, and results
Once a job finishes, there are two options to get the results. The first option is to continuously poll GET /api/v1/translate/async/:jobId until the status reaches a terminal state. Alternatively, webhooks offer a more computationally efficient method in which a completion notification is sent back the caller.
Polling intervals should scale with the job. A small batch may take a second while a large document job may take minutes. Pick an interval that fits the expected duration, and switch to webhooks for callers who cannot afford a polling loop. You can also check the summary counters for the actual progress.
Webhook profiles are managed through the webhook routes. Management is session-only: API key callers can reference an existing webhookProfileId from job creation but cannot manage profiles through API key auth. On completion, Lexel POSTs a JSON body to the resolved callback URL with headers including content-type: application/json, x-lexel-event: translation.job.completed, x-lexel-delivery-id, and x-lexel-signature-sha256 when signing is configured. Failed deliveries are retried until delivery succeeds or the job callback state records a terminal error.
Results are automatically deleted after a retention window. The result endpoint returns 410 Gone for an expired result, so fetch within the retention window and plan storage on your side.
What to monitor
Track failedItems and callback.deliveredAt on the status endpoint. failedItems above zero names the item that needs attention, and callback.deliveredAt tells you whether completion delivery actually landed. The callback.deliveryFailed and callback.attempts fields make delivery failures visible instead of silent. Rate limit and quota failures return 429 and are covered in the errors and rate limits docs.
Character accounting works the same as the synchronous route: results report usage.input_characters, and the usage docs describe how characters are counted and how to inspect consumption over time for a key, organization, or account.
Next steps
Explore adjacent implementation guides once this path is in place.

Documents
Getting started with document translation
This guide describes options to translate documents using Lexel Translate, along with recommendations and considerations for best-practice implementation.

Quickstart
API Quickstart
This guide covers the essential steps to get started with synchronous translation using the API, followed by high-level guidance on when to consider batch translation and document translation.

Migration
Migrating from Google, DeepL, or Microsoft Translator
This guide covers the compatibility routes offered by Lexel Translate for Google, DeepL, and Microsoft Translator, along with guidance on migrating to the native contract for additional features.
Not sure where to start?
Tell us about your integration and we'll point you at the right route.