REST API reference

Upscale images from your own code. Authenticate with an API key, post one file, get the enlarged PNG back on the same request, and read the cost from the response headers.

Last updated

The API runs the same upscale engine as the browser tool, over the same core module, so the limits are the same wherever you call from. One request does one image and answers with the enlarged PNG directly: no job id to poll, no download URL to follow, no copy of your upload stored anywhere.

The base URL in these examples is https://imageupscaler.tools.

Authentication

Create a key in the dashboard under API keys. The key is shown exactly once, at creation. Only a SHA-256 hash of it is stored, so nobody can recover a lost key for you and you will need to mint a new one.

Send it as a bearer token:

Authorization: Bearer sk_your_key_here

An x-api-key: sk_your_key_here header works too. A missing, unknown, or revoked key returns 401. A suspended account returns 403.

Upscale an image

POST /api/v1/upscale
Content-Type: multipart/form-data
Field Required Description
image yes The image to upscale. JPG, PNG, or WebP. file is accepted as an alias.
factor yes 2 or 4. The output is the input dimensions times this factor, exactly.
model yes fast, quality, or anime.
curl -X POST https://imageupscaler.tools/api/v1/upscale \
  -H "Authorization: Bearer $API_KEY" \
  -F "[email protected]" \
  -F "factor=2" \
  -F "model=fast" \
  -o upscaled.png

The response body is the PNG itself, with Content-Type: image/png and a Content-Disposition filename of upscaled-<width>x<height>.png. The numbers you need to account for a call ride in headers, so a client does not have to decode the image to learn them:

curl -X POST https://imageupscaler.tools/api/v1/upscale \
  -H "x-api-key: $API_KEY" \
  -F "[email protected]" \
  -F "factor=4" \
  -F "model=anime" \
  -D headers.txt \
  -o upscaled.png

grep -i '^x-upscale-' headers.txt

A 4x anime call prints:

X-Upscale-Model: anime
X-Upscale-Factor: 4
X-Upscale-In-Dims: 600x400
X-Upscale-Out-Dims: 2400x1600
X-Upscale-Ms: 8123
X-Upscale-Free: false
X-Upscale-Credits: 2
X-Upscale-Remaining: 98

X-Upscale-Free says whether the call came out of the daily allowance instead of credits. X-Upscale-Credits is what it cost. X-Upscale-Remaining is what is left, in free upscales today or monthly credits. Every plan has a monthly credit cap, so the header always carries a number.

Errors

Every error is JSON with an error sentence you can show a user and a code you can branch on.

Status code Meaning
400 invalid_request, missing_image, invalid_parameter The request was not multipart, image was missing, or factor/model was outside the allowlist.
401 unauthorized No key, an unknown key, or a revoked key.
403 suspended The account is suspended.
413 input_too_large, plan_input_cap, plan_output_cap The file, the input, or the projected output is over a cap. The sentence names the exact limit.
415 unsupported_image, animated_image The bytes are not JPG, PNG, or WebP, or they are an animation the worker would flatten.
429 rate_limited, out_of_credits, free_daily_limit Too many requests, no credits left, or the day's free allowance is used up.
502 worker_bad_output An internal error: the enlargement did not match the requested size, so it was refused rather than returned.
503 metering_unavailable, worker_unavailable A dependency is down. Try again shortly.

Two things are worth being explicit about, because they are the point of the error design:

  • The caps are checked from the input header before inference. A request that cannot be delivered, such as a 4x whose output would exceed your plan's output cap, is refused in milliseconds and costs nothing.
  • A 429 is never charged. The per-key rate limit runs before any credit is reserved, and a credit or free-allowance refusal is decided before the work starts and refunded if the work cannot finish. Nothing that came back 429 moved your balance.

Rate limit

Each API key may make 60 requests in any 60-second window. Over that, the request is refused with 429 and code rate_limited before it is charged:

{
  "error": "Rate limit exceeded: 60 requests per 60 seconds per API key. Try again in 37 seconds.",
  "code": "rate_limited"
}

Every response carries the state so a client can slow down before it is refused rather than only learning the limit from the refusal:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 37

X-RateLimit-Reset is the number of seconds until the window resets, which is also the Retry-After value sent with a 429.

Credits and limits

Upscaling is free within the daily free allowance, and metered in credits on a paid plan. The schedule is fixed by the factor: a 2x costs 1 credit and a 4x costs 2 credits. A 4x is twice the work of a 2x, so it is twice the price.

  • Re-sending the same image at the same factor costs nothing. The charge is keyed by the image content and the factor, so a repeat call is a free re-download and the balance does not move.
  • A 429 costs nothing. It is a refusal, not a receipt.
  • The free tier is 3 upscales a day per IP with no signup. A FREE-plan key shares that per-IP allowance.

Limits that decide the response, all enforced from the input header:

Limit Free Paid
Input pixels 2 MP 25 MP
Output pixels 8 MP 64 MP

A single upload is 50 MB at most, which the engine applies the same way on every plan.

See /pricing for the current plans and credit packs. The browser tool at / has the same limits and the same rules, so a call that works there works here.