> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ninjachat.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Pipelines

> Chain up to five chat, image, and video steps into one durable async job — billed once, polled once.

Chain up to **five chat, image or video steps** in one asynchronous job. Reference earlier outputs with `{{stepId.field}}`, for example to write a scene, illustrate it, then animate the image.

## Create a pipeline

```bash theme={null}
curl https://www.ninjachat.ai/api/v1/pipelines \
  -H "Authorization: Bearer $NINJACHAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "steps": [
      {
        "id": "script",
        "type": "chat",
        "model": "claude-sonnet-4.6",
        "params": { "input": "Describe a lighthouse at dawn in one vivid sentence." }
      },
      {
        "id": "still",
        "type": "image",
        "model": "flux-2-pro",
        "params": { "prompt": "{{script.output}}", "aspect_ratio": "16:9" }
      },
      {
        "id": "clip",
        "type": "video",
        "model": "veo-3.1-fast",
        "params": { "prompt": "{{script.output}}", "image_url": "{{still.url}}" }
      }
    ]
  }'
```

The response returns a pipeline `id` and its initial state. Poll it:

```bash theme={null}
curl https://www.ninjachat.ai/api/v1/pipelines/$PIPELINE_ID \
  -H "Authorization: Bearer $NINJACHAT_API_KEY"
```

Register a [webhook](/observability) instead of polling and you receive
`pipeline.completed` when the job finishes.

## Steps

| Field                                     | Notes                                                        |
| ----------------------------------------- | ------------------------------------------------------------ |
| `id`                                      | Your name for the step. Referenced by later steps.           |
| `type`                                    | `chat`, `image`, or `video`.                                 |
| `model`                                   | Any model ID servable for that type — see [Models](/models). |
| `params.input` / `params.system`          | Chat steps.                                                  |
| `params.prompt`                           | Image and video steps.                                       |
| `params.aspect_ratio`, `params.image_url` | Image and video steps.                                       |

Steps run **sequentially**, so a template may only reference an earlier step.

| Template            | Produced by                               |
| ------------------- | ----------------------------------------- |
| `{{stepId.output}}` | `chat` steps — the completion text        |
| `{{stepId.url}}`    | `image` and `video` steps — the asset URL |

Referencing a later step, an unknown field, or `{{x.output}}` on an image step
is rejected at validation time with a message naming the offending step, before
anything is billed.

## Billing

The **whole pipeline is reserved up front** — the sum of each step's ordinary
standalone price — before any provider work begins. Steps settle as they
complete, and anything unsettled is refunded automatically if the pipeline
fails. You are never charged for steps that did not run.

## Durability

Pipeline state is stored server-side, so execution survives a dropped
connection or a serverless timeout. Polling the job or letting the sweeper run
will continue a pipeline whose original driver died — you do not need to retry
or rebuild state on your side.
