|
Documentation
Book a DemoPlatform
PlatformMCPCLIAPI
Workflows
GuidesChangelog

Welcome

  • Overview
  • Authentication
  • Errors & status codes
  • Webhook signatures

Localization

  • Overview
  • Create jobs
  • Lock non-translatable keys
  • Track a job group
  • Get a single job
  • List jobs
  • Webhook delivery
  • Live progress (WebSocket)

Pipeline

  • Overview
  • Pre-localization AI edit
  • Human review
  • AI review (post-edit)
  • Rephrase for natural copy
  • Back-translation check
  • Configure the pipeline
  • Observe pipeline runs

Provisioning

  • Overview
  • Create a provisioning job
  • Source types
  • What the AI extracts
  • Webhook delivery
  • Live progress (WebSocket)

Synchronous

  • Localize
  • Recognize

Engine management

  • Engine Suggestions

Observe pipeline runs

Every enabled pipeline stage leaves one record on the job, so you can read what ran instead of trusting that it did.

You turned on a few pipeline stages – maybe pre-edit to clean the source and back-translation to catch drift – and a job came back completed_with_warnings. Which stage fell through? Did the human reviewer ever pick it up, or did it time out? What did the extra stages cost? A pipeline that runs several AI and human steps per locale is exactly the kind of thing that turns into a black box: output comes out, and you take it on faith that the stages in between did their work.

They don't ask you to take it on faith. Every enabled stage writes one record to the job's steps[] array – which stage, what status, what cost, when it started and finished. You read what each stage did; you don't trust that it ran. That is the whole job of this page.

New to the pipeline? Start with the Pipeline overview.

On this page

  • Where the records live
  • The steps array
  • Mapping a stepId to a stage
  • Step status: completed, failed, skipped
  • How a step failure becomes a job warning

Where the records live#

The steps[] array is a field on the localization job. You don't fetch it separately – it arrives whenever you read the job:

text
GET /jobs/localization/:jobId

Authenticate with your API key in the X-API-Key header. The full endpoint, the job-status values, and the outputData payload are covered on the single-job page; this page is about one field on that response – the per-stage trail – and what it tells you.

So the rule is simple: every job you read already carries its own audit log. A job with no pipeline enabled shows a single record, because core localization always runs. Turn on two optional stages and you get three records. The array grows with the pipeline, one entry per stage, in the order the stages ran.

The steps array#

Each entry in steps[] is the record of one stage. These are the fields you read to audit a run – which stage, with what outcome, at what cost, and when:

json
"steps": [
  {
    "stepId": "preEdit",
    "type": "action",
    "status": "completed",
    "errorMessage": null,
    "costUsd": 0.0012,
    "externalRefType": null,
    "externalRefId": null,
    "externalRefUrl": null,
    "createdAt": "2026-03-16T10:30:01.000Z",
    "startedAt": "2026-03-16T10:30:01.000Z",
    "completedAt": "2026-03-16T10:30:02.000Z"
  },
  {
    "stepId": "localize",
    "type": "action",
    "status": "completed",
    "errorMessage": null,
    "costUsd": 0.0184,
    "externalRefType": null,
    "externalRefId": null,
    "externalRefUrl": null,
    "createdAt": "2026-03-16T10:30:02.000Z",
    "startedAt": "2026-03-16T10:30:02.000Z",
    "completedAt": "2026-03-16T10:30:05.000Z"
  }
]
FieldDescription
stepIdWhich pipeline stage this record is for. See the mapping table below.
typeThe kind of step. action for an automated stage.
statuscompleted, failed, or skipped for this stage – independent of the job's status.
errorMessageWhy this stage failed. null unless status is failed.
costUsdWhat this stage cost, in USD – a JSON number, or null.
externalRefType, externalRefId, externalRefUrlA pointer to an external record for stages that hand work to a third party – the human review stage. null for fully automated stages.
createdAt, startedAt, completedAtWhen the stage was created, picked up, and finished.

Each record also carries an outputData field – the content that stage produced, in the same shape as the job's outputData. That payload is the translation, not the audit trail, so it's documented on the single-job page alongside the job-level outputData; the fields above are the ones you read to see what the pipeline did.

Two things these records give you that a single outputData blob can't. First, cost is itemized per stage, not only totaled per job – so when you enable back-translation and the bill moves, you can read exactly which stage moved it. Second, timing is per stage – a humanEdit record whose startedAt and completedAt are hours apart tells you the wait was the human, not the engine.

Read steps by stepId, not by position

The records appear in execution order, but don't index into the array by position – which stages ran depends on which you enabled, so position is not stable across jobs. Find a stage by its stepId (steps.find(s => s.stepId === "humanEdit")). The set of stepId values is fixed; the set present on any given job is whatever you turned on.

Mapping a stepId to a stage#

Each stepId names one pipeline stage. This is the lookup table from the value in the record to the stage it represents and the page that documents what that stage does:

stepIdStage
preEditPre-localization AI edit
localizeCore localization
humanEditPost-localization human review
postEditPost-localization AI review
rephraseRephrase for natural copy
backTranslationBack-translation check

localize is the one stepId that appears on every job, pipeline or not – it is the core translate step, and it always runs. The other five appear only when you've enabled that stage on the engine or in the request.

Step status: completed, failed, skipped#

Each step carries its own status, set independently of the job and of every other step. Three values:

Step statusMeaning
completedThe stage ran and produced its output.
failedThe stage ran and errored. errorMessage says why.
skippedThe stage did not run to completion this time, even though it was enabled.

completed and failed read the way you'd expect. skipped is the one worth pausing on, because it is not the same as "disabled". A stage you never turned on produces no record at all. A skipped record means the stage was enabled but was passed over for a reason the pipeline defines – the clearest case is human review: if the review window closes with no human response, that stage is marked skipped and the AI translation carries forward as final. The record is still there, so the skip is visible rather than silent.

A step status is not the job status

A failed step does not always mean a failed job. Most optional stages are non-critical: when one fails, its record reads failed, the engine carries the last good output forward, and the job still finishes with full outputData. The job status that results – completed_with_warnings – is explained on the single-job page. The step status tells you what happened to one stage; the job status tells you whether you got a translation.

How a step failure becomes a job warning#

When a non-critical stage fails, the failure shows up in two places at once, and they are two views of the same event. The steps[] record reads failed with an errorMessage – that's the detailed view. The same failure also surfaces as one entry in the job's top-level warnings array – that's the summary view your status-handling code branches on:

json
{
  "id": "ljb_A1b2C3d4E5f6G7h8",
  "status": "completed_with_warnings",
  "outputData": { "title": "Hallo" },
  "warnings": [
    { "step": "backTranslation", "message": "Back-translation check did not complete" }
  ],
  "steps": [
    { "stepId": "localize", "type": "action", "status": "completed", "errorMessage": null, "costUsd": 0.0184, "completedAt": "2026-03-16T10:30:05.000Z" },
    { "stepId": "backTranslation", "type": "action", "status": "failed", "errorMessage": "Back-translation check did not complete", "costUsd": 0.0031, "completedAt": "2026-03-16T10:30:11.000Z" }
  ]
}

Each warnings entry is { step, message }, where step is the same stepId you'd find in the failed record. So the two arrays line up: warnings is the short list of what went wrong, and steps[] is where you go for the detail behind each one. Read warnings to decide whether to flag the locale for a human; read the matching steps[] record when you want the errorMessage, the cost, and the timing behind it.

This is the mechanism behind completed_with_warnings: the core translation succeeded, so you have usable outputData, but at least one non-critical stage left a failed record and a matching warning. Treat the output as shippable and the warnings as a quality signal worth surfacing. Only a job status of failed means there is no translation to read – and that decision, with the full job-status table, lives on the single-job page.

Aggregate stage health is a separate surface

steps[] answers "what did the pipeline do on this job." When you want the trend across many jobs – how often pre-edit fails, how often back-translation corrects a translation – that's an aggregate question, and it's answered on the Reports page, not in a per-job response. Per-job records here; rollups there.

Next steps#

Get a single job
The full job response these steps live on, plus the job-status values to branch on
Configure the pipeline
Decide which stages run, per engine or per request - and so which steps you'll see
Reports
Aggregate stage success rates and throughput across every job

Was this page helpful?

Max PrilutskiyMax Prilutskiy·Updated 3 days ago·7 min read