---
title: Colorize a black-and-white photo
url: https://base_url.placeholder/docs/ops/colorize
group: Concepts
---

# Colorize a black-and-white photo

`colorize` gives a monochrome photograph colour. It is the simplest op in the [catalogue](https://base_url.placeholder/docs/ops) to call — an image in, nothing to tune — and like every AI op it runs as a [job](https://base_url.placeholder/docs/jobs) with a price you can ask for first.

## What it does

The model reads the scene — skin, sky, foliage, fabric — and writes a colour version of it as a new asset. Nothing you send names a colour: the decisions are which image and which model, and the catalogue names the default. The monochrome original is untouched.

Reach for it for archives, scanned prints and film frames, and for anything a person will look at rather than measure. Do not reach for it when you need a _particular_ colour — that is [edit](https://base_url.placeholder/docs/ops/edit) with an instruction. Going the other way is free: `grayscale` is deterministic, costs no credits on a paid plan, and has a [synchronous form](https://base_url.placeholder/docs/sync).

## Call it

One op, six surfaces, one vocabulary: the `op` name below is the same string everywhere — the SDKs' named helpers only spell it in their language's case, `ops.colorize` in JavaScript — because every surface enumerates `GET /api/v1/ops` instead of carrying its own list. The request is the catalogue's own `example` for this op, so it is the one the service has checked.

#### JavaScript

```js
// pnpm add imagestep
const job = await client.ops.colorize("ast_1a2b", { wait: true });
const [out] = await client.jobs.outputs(job);
```

#### Python

```python
# pip install imagestep
job = client.ops.colorize("ast_1a2b", wait=True)
[out] = client.jobs.outputs(job)
```

#### CLI

```sh
imagestep jobs submit --op colorize --asset-ids ast_1a2b --wait
```

#### curl

```sh
# "wait" holds the response until the job is done (60 s at most): 200 with the finished job,
# or 202 with the handle — then GET /api/v1/jobs/<id>?wait=30 waits again
curl -sS -X POST https://api.imagestep.dev/api/v1/jobs \
  -H "Authorization: ApiKey $IMAGESTEP_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"op":"colorize","assetIds":["ast_1a2b"],"wait":30}'
```

#### MCP

```text
# tool call
transform  {"op":"colorize","asset_ids":["ast_1a2b"]}
```

#### n8n

```json
{
  "nodes": [
    {
      "parameters": {
        "resource": "op",
        "operation": "run",
        "op": "colorize",
        "inputMode": "assetIds",
        "assetIds": "ast_1a2b"
      },
      "name": "ImageStep",
      "type": "n8n-nodes-imagestep.imageStep",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    }
  ],
  "connections": {}
}
```

The [n8n](https://base_url.placeholder/docs/n8n) tab is a workflow to paste onto the canvas: the **colorize** entry of the node's Op dropdown, which is filled from the same catalogue. Full references: [SDKs](https://base_url.placeholder/docs/sdk), [CLI](https://base_url.placeholder/docs/cli), [MCP](https://base_url.placeholder/docs/mcp), [REST](https://base_url.placeholder/docs/api).

## Parameters, model and price

The entry as the catalogue stood when this page was built; `GET https://api.imagestep.dev/api/v1/ops/colorize` has it live — the same entry the SDKs, the MCP server and the n8n node enumerate. The rows are fields of the request body. `parameters` goes to the model: its keys are the model's own, listed under `parameters` for each model in `GET /api/v1/ai-models`, and a key the model does not declare, or a value outside its options or bounds, is `400 invalid_param` naming it.

### colorize

ai job type ai-edit · input scaled to ≤ 2048 px on the long edge

Colour a black-and-white photo.

| Parameter | Type | What it does |
| --- | --- | --- |
| model | string | A model whose categories include 'colorize' — GET /api/v1/ai-models lists them. Any other model is 400 invalid_param, with the ones that fit in details.allowed. default replicate/piddnad/ddcolor |

AI op: per-item USD from the model's price; credits are charged per item. Price a batch with POST /api/v1/jobs?dryRun=true before spending. Default model replicate/piddnad/ddcolor: $0.0013 per item.

That is how it is priced. What one request costs — another model, a bigger scale factor, forty images — is the [dry run](https://base_url.placeholder/docs/jobs#price), which prices the exact body you are about to send without creating anything.

## In a workflow

Colourising is usually the last AI step of an archive pipeline and the first thing a person wants to compare against the original. Keep both, label them together, and let a webhook tell your flow when the batch is done.

```json
{
  "name": "Archive colour",
  "slug": "archive-colour",
  "description": "Faces first, then colour — the scans untouched.",
  "steps": [
    {
      "op": "restore_face"
    },
    {
      "op": "colorize"
    }
  ]
}
```

#### JavaScript

```js
import { readFile } from "node:fs/promises";

const preset = await client.presets.create(JSON.parse(await readFile("archive-colour.json", "utf8")));
console.log(preset.slug, preset.version); // "archive-colour" 1
```

#### Python

```python
import json

preset = client.presets.create(json.load(open("archive-colour.json")))
print(preset["slug"], preset["version"])  # "archive-colour" 1
```

#### CLI

```sh
imagestep preset create -f archive-colour.json -o json
```

#### curl

```sh
curl -s https://api.imagestep.dev/api/v1/presets -H "Authorization: ApiKey $IMAGESTEP_API_KEY" -H "Content-Type: application/json" -d @archive-colour.json
```

#### MCP

```text
# tool call — an agent has no disk to read, so the document travels in the call
save_preset  {"name":"Archive colour","slug":"archive-colour","description":"Faces first, then colour — the scans untouched.","steps":[{"op":"restore_face"},{"op":"colorize"}]}
```

#### JavaScript

```js
const job = await client.presets.run("archive-colour", ["<scan-id>"], { wait: true });
const outputs = await client.jobs.outputs(job);
```

#### Python

```python
job = client.presets.run("archive-colour", ["<scan-id>"], wait=True)
outputs = client.jobs.outputs(job)
```

#### CLI

```sh
imagestep jobs submit --preset-id archive-colour --asset-ids <scan-id> --wait -o json
```

#### curl

```sh
# price it first with ?dryRun=true; "wait" holds the response until a one-item job is done (60 s at most)
curl -s https://api.imagestep.dev/api/v1/jobs -H "Authorization: ApiKey $IMAGESTEP_API_KEY" -H "Content-Type: application/json" \
  -d '{"presetId":"archive-colour","assetIds":["<scan-id>"],"wait":30}'
```

#### MCP

```text
# tool call
run_preset  {"preset":"archive-colour","asset_ids":["<scan-id>"]}
```

No polling on a batch: register a [webhook](https://base_url.placeholder/docs/webhooks#register) once and let `job.completed` continue the flow when it lands.

In [n8n](https://base_url.placeholder/docs/n8n) the same two steps are the ImageStep node twice, or once with the preset; the [ImageStep Trigger](https://base_url.placeholder/docs/n8n#trigger) is the webhook end of it. To show a before and after, [publish](https://base_url.placeholder/docs/assets#publish) both assets — the original keeps its own id and URL.

## Limits

The default model is handed at most 2048 px on the long edge, so that is the largest result: a scan above it comes back scaled down to it, the original kept as it was. Expect plausible, not faithful: the model has no way to know that the dress was blue. Heavy grain, low contrast and damage push it toward washed-out results, which is why [restore_face](https://base_url.placeholder/docs/ops/restore-face) usually goes first. Nothing here names a colour, so when a result is wrong the lever is `edit`, with words.

## FAQ

**Can I tell it what colour something is?**

Not through colorize — it takes no prompt and nothing that names a colour. When the colour matters, use edit with an instruction ("the coat is dark green"), which is a prompt-driven op.

**Are the colours historically accurate?**

No. The model infers plausible colour from what the scene looks like; it has no knowledge of the particular coat, car or uniform. Label the output as colourised.

**What happens if I colorize a colour photo?**

Nothing useful. Run it on monochrome input; a colour image comes back changed for no reason and still costs an item.

**Restore the faces first, or colorize first?**

Restore first. restore_face works from the detail the scan still has, and colouring beforehand gives it invented colour to repair.

**Is there a free way to do the opposite?**

Yes — grayscale is a deterministic op: no credits on a paid plan, exact every time, and it runs synchronously if you only want the bytes back.
