UPSCALR API
A REST API for image upscaling. Submit an image, track the job until it finishes, then download a result up to four times the size of the original.
Base URL
https://upscalr.app/api/v1All endpoints are versioned under /v1 and served over HTTPS only. Requests and responses are JSON, except image upload (multipart form data) and image download (a redirect to the file).
How it works
Every upscale is an asynchronous job. You create one with a single request, and the API answers immediately with a job id while the work happens in the background. Most jobs finish within a few seconds. You can watch a job in two ways:
- Poll: retrieve the job every second or two until its status is
succeededorfailed. - Webhooks: register an endpoint and we POST to you the moment a job finishes. No polling loop to maintain.
When the job succeeds, download the result through a short-lived signed URL.
Your first request
One request creates a job. Keep your key in an environment variable. See API key setup.
curl -X POST https://upscalr.app/api/v1/upscale \
-H "Authorization: Bearer $UPSCALR_API_KEY" \
-F image=@photo.png \
-F target=4kResponse · 202 Accepted
{
"id": "cmrw0iqm8000bdcs3um6ii7fa",
"object": "job",
"status": "queued",
"target": "4k",
"credits": 3,
"created_at": "2026-07-25T09:30:00Z"
}The full walkthrough (polling, downloading, retries) is in the quickstart.
Endpoints
/upscaleCreate an upscale job from a file or URL.GET/jobs/{id}Retrieve a job's current state.GET/jobsList your jobs, newest first.GET/jobs/{id}/resultDownload the upscaled image.DELETE/jobs/{id}Cancel an unfinished job and reclaim its credits.Each row links to its reference page with parameters, example requests in three languages, and every response code.
Authentication
Every request carries an API key as a bearer token. Keys start with usk_, are shown once at creation, and are managed from Dashboard → API keys. A missing or revoked key returns 401 unauthorized. Details are in API key setup.
curl https://upscalr.app/api/v1/jobs \
-H "Authorization: Bearer $UPSCALR_API_KEY"Output sizes
The target parameter picks the output size. Despite the k naming these are multipliers of the original: a 400×300 source with target=4k comes back at 1600×1200. Larger targets cost more credits.
| Parameter | Type | Description |
|---|---|---|
| 2k | 3 credits | Twice the original size. The default. |
| 3k | 6 credits | Three times the original size. |
| 4k | 9 credits | Four times the original size. |
Not every image accepts every value. If the requested target is refused by the engine, we fall back to the largest it will take for that image, and the job reports the target actually used.
Supported inputs
| Parameter | Type | Description |
|---|---|---|
| Formats | JPEG, PNG, WebP, AVIF | Detected from the file bytes, not the declared content type. |
| Max file size | 10 MB | Larger uploads are rejected with 413 payload_too_large. |
| Delivery | file or URL | Send the bytes as multipart form data, or JSON with a publicly reachable image_url. |
Credits
Jobs are paid for in credits from your account balance, reserved on submit and refunded automatically if the job fails or is cancelled. You only pay for successful output. Every job response carries a credits field with the exact amount. Full rules in Pricing & credits.
Rate limits
Requests are limited per key, per minute: 60 by default, more on paid plans. Every response reports the window through X-RateLimit-* headers, and a 429 tells you exactly how long to wait via Retry-After. Details and backoff snippets in API limits.
Errors
Conventional HTTP status codes, and every error body carries a stable machine-readable error.code plus a human-readable message. Branch on the code, not the message. Every status and how to handle it is in the errors reference.
{
"error": {
"code": "insufficient_credits",
"message": "This job needs 3 credits and you have 1."
}
}Idempotency
Send an Idempotency-Key header on submissions and retries become free: repeating a request with the same key returns the original job instead of creating and charging a second one. Use it anywhere your infrastructure might retry. Details are on the upscale reference.
Versioning
The version is in the path. Everything under /v1 keeps its current shape: we may add fields and endpoints, but existing fields will not change meaning or disappear. Breaking changes ship as /v2, and v1 keeps working.