HiAPI
Blog

Tutorial

How to Use Recraft Creative Upscale API: curl, Python and a Real Run

One image_url field, a 1254 px input back at 4096 px, and what the task actually returned.

Oct 23, 2026 5
How to Use Recraft Creative Upscale API: curl, Python and a Real Run

TL;DR

  • recraft/creative-upscale enlarges an image and redraws its texture and detail. The request body is one field, image_url. There is no prompt and no scale setting.
  • It runs on the unified /v1/tasks flow: POST to get a taskId, poll GET /v1/tasks/<taskId>, download from data.output[0].url.
  • In our run a 1254×1254 PNG came back as a 4096×4096 WebP of about 19.8 MB after roughly 60 seconds. Budget for the wait and the file size.

What you need

A hiapi API key from the dashboard, and a publicly reachable image URL. The model page lists the input limits: PNG recommended, up to 20 MB, each side 256–4096 px, up to 16 MP.

If you need text, logos or product detail to stay exactly as they are, use Recraft Crisp Upscale instead. Creative Upscale redraws, so small elements can change.

Minimal curl request

export HIAPI_KEY=sk-your-key

curl -s https://www.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "recraft/creative-upscale",
    "input": { "image_url": "https://example.com/old-illustration.png" }
  }'

The response is a task handle:

{"code":200,"data":{"taskId":"tk-hiapi-01M5K8J899THH6XJK99TAZ4VSD"},"message":"success"}

Poll it until data.status is success:

curl -s https://www.hiapi.ai/v1/tasks/tk-hiapi-01M5K8J899THH6XJK99TAZ4VSD \
  -H "Authorization: Bearer $HIAPI_KEY"

Python: submit, poll, save

import os, time, requests

BASE = "https://www.hiapi.ai"
HEADERS = {"Authorization": f"Bearer {os.environ['HIAPI_KEY']}"}

def upscale(image_url: str, out_path: str) -> str:
    r = requests.post(f"{BASE}/v1/tasks", headers=HEADERS, timeout=30, json={
        "model": "recraft/creative-upscale",
        "input": {"image_url": image_url},
    })
    r.raise_for_status()
    task_id = r.json()["data"]["taskId"]

    deadline = time.time() + 300
    while time.time() < deadline:
        time.sleep(5)
        try:
            d = requests.get(f"{BASE}/v1/tasks/{task_id}", headers=HEADERS, timeout=30).json()["data"]
        except requests.RequestException:
            continue  # transient network error: keep polling the SAME taskId
        if d["status"] == "success":
            url = d["output"][0]["url"]
            with open(out_path, "wb") as f:
                f.write(requests.get(url, timeout=120).content)
            return task_id
        if d["status"] in ("fail", "failed"):
            raise RuntimeError(f"task {task_id} failed: {d}")
    raise TimeoutError(f"task {task_id} still running; re-poll it, do not resubmit")

upscale("https://example.com/old-illustration.png", "upscaled.webp")

Two details matter in production. First, never resubmit on a timeout: every submit creates a new billable task, so keep the taskId and re-poll it. Second, save the file immediately; output URLs carry an expireAt and the host is a temporary one.

Production notes

  • Use a callback for batches. Instead of polling you can pass callback: {"url": "...", "when": "final"} in the task body and let hiapi call you when the task ends. Treat the taskId as the dedupe key.
  • Polling interval of 5 s is enough. One task took about a minute, so polling faster only adds requests.
  • Validate the URL before you submit. The platform rejects malformed URLs up front (see below), but an unreachable https:// URL is a different failure and is better caught on your side with a quick HEAD request.

What we saw in a real run

We ran one real request with the example input image from the model page (a 1254×1254 PNG of a mountain cabin).

Item Observed
Submit response {"code":200,"data":{"taskId":"tk-hiapi-01M5K8J899THH6XJK99TAZ4VSD"}}
Status sequence handling → archiving → success
Time from created to completed 61 seconds (1792721625 → 1792721686)
Output one image, WebP, https://temp.hiapi.ai/.../...-0.webp with an expireAt about 7 days out
Input size 1254×1254 PNG, 2.7 MB
Output size 4096×4096 WebP, about 19.8 MB

Things worth knowing from that run:

  1. archiving has no output yet. The task reports completed and status: "archiving" for a few polls while the result is moved to storage. Only status == "success" carries output[0].url, so do not read the URL when you first see a completed timestamp.
  2. The result is not a clean 2×. The 1254 px input became 4096 px, about 3.3× per side. The model page shows the same pair and exposes no scale field, so plan for the output being decided by the model, not by you. If you need exactly 2×, Crisp Upscale is the endpoint with that contract.
  3. Output files are large. 19.8 MB for one image is more than the 20 MB input limit would let you feed straight back in, so do not chain a second pass on the output without resizing.
  4. Detail is redrawn, not just sharpened. The model page's own note on this pair says composition, light and colors are largely kept while logs, stonework and railing are redrawn, and some small elements, such as a tree by the porch, change. Review output before replacing a brand asset.
  5. A bad URL fails fast. Sending "image_url": "not-a-url" returned HTTP 400 immediately: {"code":400,"data":null,"error_code":"INVALID_REQUEST","message":"invalid input: image_url: 'not-a-url' does not match pattern '^https?://'"}. The pattern is the only check we exercised; we did not test the 256 px minimum or the 16 MP ceiling.

We ran one task, so the 61 s figure is a single sample, not a benchmark.

Creative Upscale or Crisp Upscale?

Both take a single image_url and no prompt. They differ in what they do to the pixels and in price.

Creative Upscale Crisp Upscale
Model id recraft/creative-upscale recraft/crisp-upscale
Behavior Enlarges and redraws texture and detail Doubles width and height, keeps content and lettering
Best for Old illustrations, small or low-res art Product photos, posters with text, design assets
Price Much higher per image; see pricing See the Crisp pricing article

The per-image price of Creative Upscale is far above Crisp's (compare the live numbers on the pricing page), so use it only when you actually want detail regenerated. For general resolution workflows across models, see Increase image resolution with hiapi.

Related

FAQ

Do I need a prompt? No. The model page describes a single image input with no prompt or other settings, and our request used only image_url.

Can I choose the output size? Not through the API. There is no scale field; our 1254 px input came back at 4096 px.

Will text and logos survive? Not guaranteed. Detail is regenerated and small elements can change, so use Crisp Upscale for lettered assets.

What output format do I get? A WebP in our run, delivered from a temporary URL that expires, so download it right away.

How long does it take? About a minute for our single run; build your client for waits of that order.

Related articles

View all articles →

Start building with persistent AI artifacts

Get your API key and call image, video and audio models through one task-based API.

Read the API docs