# Upscale an image to 4K

> Enlarge an image to 4K (3840 px on its long edge) for print and zoom. An image that is already 4K comes back as it is. Delivered as one image file.

**Endpoint:** `POST https://api.refabric.com/v1/tasks/image.upscale` · **Task:** `image.upscale` · **Scope:** `tasks:run` · **Category:** Production prep

Send a design, a photo or any earlier result and get it back at 4K (3840 px on its long edge), ready for print, close zoom or a tech pack. An image that is already 4K is not enlarged again — it comes back as its own pixels, with a warning in `summary` that says so.

## Quick start

```python
import os
import time
import requests

headers = {"Authorization": f"Key {os.environ['REFABRIC_API_KEY']}"}

job = requests.post(
    "https://api.refabric.com/v1/tasks/image.upscale",
    headers=headers,
    json={
        "image": "art:6d9a01",
    },
).json()
print(job["job_id"])

while True:
    status = requests.get(job["status_url"], headers=headers).json()
    if status["lifecycle"] == "terminal":
        break
    time.sleep(5)

print(requests.get(job["result_url"], headers=headers).json())
```

```javascript
const headers = {
  Authorization: `Key ${process.env.REFABRIC_API_KEY}`,
  "Content-Type": "application/json",
};

const job = await fetch("https://api.refabric.com/v1/tasks/image.upscale", {
  method: "POST",
  headers,
  body: JSON.stringify({
    "image": "art:6d9a01"
  }),
}).then((r) => r.json());
console.log(job.job_id);

let status = job;
while (status.lifecycle !== "terminal") {
  await new Promise((r) => setTimeout(r, 5000));
  status = await fetch(job.status_url, { headers }).then((r) => r.json());
}

console.log(await fetch(job.result_url, { headers }).then((r) => r.json()));
```

```bash
curl -X POST "https://api.refabric.com/v1/tasks/image.upscale" \
  -H "Authorization: Key $REFABRIC_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Prefer: wait=60" \
  -d '{"image":"art:6d9a01"}'
```

## Input schema

- `image` (string, _required_, pattern: ^(https://|art:|file:).+$) — The image to enlarge to 4K (3840 px on its long edge), as one string: a URL, a file from an earlier result (`art:…` or its url) or an upload (`file:…`). An image that is already 4K comes back as it is, not charged.
  Example: `art:6d9a01`

## Required-fields example

```json
{
  "image": "art:6d9a01"
}
```

## Full example

```json
{
  "image": "art:6d9a01"
}
```

## Output schema

- `files` (array<object>, _optional_) — One image file: the image at 4K, as a PNG. When the image was already 4K the file holds its own pixels, in its own format (`media_type` says which), and nothing is charged.
- `summary` (object, _optional_) — Sent only when the image was already 4K: its `warnings` then say so, and that nothing was charged.
  - `warnings` (array<object>, _optional_) — `{code: "already_4k"}` when the image was already 4K: the file is a new file with the image's own pixels, and nothing was charged.

## Response example

```json
{
  "job_id": "7a1c2e3f00004000800000000000001c",
  "lifecycle": "queued",
  "status_url": "http://v3-api.refabric.com/v1/jobs/7a1c2e3f00004000800000000000001c",
  "result_url": "http://v3-api.refabric.com/v1/jobs/7a1c2e3f00004000800000000000001c/result",
  "cancel_url": "http://v3-api.refabric.com/v1/jobs/7a1c2e3f00004000800000000000001c/cancel"
}
```

## Result example

```json
{
  "job_id": "7a1c2e3f00004000800000000000001c",
  "files": [
    {
      "file": "art:6d9a02",
      "url": "https://files.example.com/image.upscale/1.png",
      "media_type": "image/png",
      "task": "image.upscale",
      "job_id": "7a1c2e3f00004000800000000000001c",
      "created_at": "2026-10-01T09:31:12Z"
    }
  ],
  "has_more": false
}
```

An image that is already 4K is not enlarged again: it comes back as one file holding its own pixels, with an `already_4k` warning in `summary`.

## Built for

- Print-ready files
- Zooming into fabric and detail
- Final images for a tech pack or a lookbook

## What you get

- One image file at 4K (3840 px on its long edge).
- A `summary` with an `already_4k` warning when the image was already 4K; then nothing is charged.

## Specs

- **Input formats:** Images, each one string: a URL, an upload (`file:…`) or a file from an earlier result (`art:…`). Upload types and sizes: `GET /v1/meta` `limits.upload`.
- **Input count:** `image`: one
- **Output format:** Files: each one line with its `url` and its `media_type`, in the job's result.
- **Outputs per job:** One file per job.

## Errors

- `field_not_accepted`
- `invalid_request`
- `not_found`
- `permission_denied`
- `insufficient_credits`
- `processing_failed`

## Related

- `image.generate` — It runs before: its result is this input.
- `pattern.generate` — It runs before: its result is this input.
- `photoshoot.create` — It runs before: its result is this input.

## For agents and code generation

- https://api.refabric.com/v1/tasks/image.upscale/llms.txt
- https://api.refabric.com/v1/tasks/image.upscale/openapi.json
- GET https://api.refabric.com/v1/tasks/image.upscale
