Search

Search HiAPI models, tools, and resources.

Back to blog
Tutorial5 min read

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.

hiapiRecraftAPI IntegrationImage Upscaling

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).

ItemObserved
Submit response{"code":200,"data":{"taskId":"tk-hiapi-01M5K8J899THH6XJK99TAZ4VSD"}}
Status sequencehandling → archiving → success
Time from created to completed61 seconds (1792721625 → 1792721686)
Outputone image, WebP, https://temp.hiapi.ai/.../...-0.webp with an expireAt about 7 days out
Input size1254×1254 PNG, 2.7 MB
Output size4096×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 UpscaleCrisp Upscale
Model idrecraft/creative-upscalerecraft/crisp-upscale
BehaviorEnlarges and redraws texture and detailDoubles width and height, keeps content and lettering
Best forOld illustrations, small or low-res artProduct photos, posters with text, design assets
PriceMuch higher per image; see pricingSee 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.

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.

Generate it with HiAPI

Choose a model, enter your prompt, and see the result.

HiAPI Blog

Related articles

HiAPI

Generate it with HiAPI

Start generating