Skip to main content

Set Rail

Compose a Spec's pipeline rail so it can run via POST /v1/pipelines without the UI. Replace the ordered stages and their per-stage config in one PUT call.

Set the Spec composed pipeline rail. This is what makes a Spec runnable from the API: once a rail is set, POST /v1/pipelines compiles it and runs your documents through it, no UI required. The PUT replaces the stored rail wholesale, so send the full ordered list each time. Passing an empty array clears the rail.

A minimal runnable rail is a single extraction stage: {"rail":[{"type":"schema","name":"Extraction"}]}. From there you compose the stages you need in order. The compiler maps registry to transfer, schema to extraction, resolve to resolution (one phase per active policy), valid to a positional validation checkpoint, and assembly to a post-run compose.

Stages that need configuration carry it under json. A resolve stage carries json.policy_ids (the Data Policies it runs). A valid stage carries json.stage_ids (the member validation-stage ids, configured via the validation-stages endpoints) and an optional json.target_phases. An assembly stage carries json.grouping_field and json.anchor_field. The rail accepts at most 50 stages.

Two write-boundary behaviors matter for integrations. First, stage ids: any stage sent without an id gets one assigned before the rail is persisted (s-<type>, deduplicated), and the response echoes the rail with ids filled in — the Spec editor selects stages by id, so this keeps a programmatically composed rail editable in the UI. Second, extraction model settings are Talonic-managed: a rail write that would change the extraction stage's json.settings.model or json.settings.input_mode is rejected with 403 forbidden. Round-tripping an exported rail with those settings unchanged stays legal.

PUT/v1/schemas/{id}/rail

Body parameters

rail*arrayOrdered array of stage objects (max 50). An empty array clears the rail.
rail[].type*stringStage kind: one of source, registry, schema, resolve, valid, assembly, deliver, reconcile, sanitize, triage.
rail[].idstringOptional stage handle (max 64 characters). Assigned server-side (s-<type>, deduplicated) when omitted, so the stored rail is always UI-editable.
rail[].namestringOptional display name (max 200 characters).
rail[].substringOptional sub-label (max 100 characters).
rail[].jsonobjectPer-stage config. resolve carries policy_ids; valid carries stage_ids and optional target_phases; assembly carries grouping_field and anchor_field.

Set a minimal runnable rail

curl -X PUT https://api.talonic.com/v1/schemas/a1b2c3d4-e5f6-7890-abcd-ef1234567890/rail \
  -H "Authorization: Bearer $TALONIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"rail":[{"type":"schema","name":"Extraction"}]}'

Request body (full rail)

{
  "rail": [
    { "type": "schema", "name": "Extraction" },
    {
      "type": "resolve",
      "name": "Resolution",
      "json": { "policy_ids": ["b2c3d4e5-f6a7-8901-bcde-f23456789012"] }
    },
    {
      "type": "valid",
      "name": "Totals checkpoint",
      "json": {
        "stage_ids": ["f1e2d3c4-b5a6-7890-abcd-ef1234567890"],
        "target_phases": ["resolve"]
      }
    },
    {
      "type": "assembly",
      "name": "Compose",
      "json": { "grouping_field": "contract_number", "anchor_field": "document_kind" }
    }
  ]
}

Response

Returns { "rail": [...] } echoing the rail you set, with server-assigned stage ids filled in. After setting a rail, compile and run it with POST /v1/pipelines followed by POST /v1/pipelines/:id/start.

Response

{
  "rail": [
    { "type": "schema", "name": "Extraction", "id": "s-schema" }
  ]
}
A valid stage references validation stages by their ids in json.stage_ids. Create those stages first with POST /v1/schemas/{id}/validation-stages, then reference the returned ids here.

Errors

Error responses

400validation_errorInvalid body, an unrecognized stage type, or more than 50 stages.
401unauthorizedMissing or invalid API key.
403forbiddenThe write would change the extraction stage's model or input-mode settings, which only Talonic staff can edit in the Spec editor. Resend with those settings unchanged.
404not_foundNo Spec (schema) with this ID exists for your organization.
429rate_limitedToo many requests. Retry after the period indicated in the Retry-After header.

Frequently asked questions

How do I run a Spec without the UI?+
Set a rail with PUT /v1/schemas/{id}/rail, then call POST /v1/pipelines (which compiles the rail) and POST /v1/pipelines/:id/start. A minimal runnable rail is a single extraction stage.
What is the smallest valid rail?+
A single extraction stage: {"rail":[{"type":"schema","name":"Extraction"}]}. Add resolve, valid, and assembly stages as you need them.
How does a valid stage know what to check?+
It carries json.stage_ids, the ids of validation stages you created via the validation-stages endpoints, plus an optional json.target_phases. It validates the output of the stage immediately before its rail position.
Why does my rail write return 403 forbidden?+
The write would change the extraction stage's json.settings.model or json.settings.input_mode, which are Talonic-managed. GET the current rail, carry those settings over unchanged (or omit them exactly as stored), and resend — an unchanged round-trip of an exported rail is always legal.