Image Upscale API Tutorial with Node.js and Python
Step by step with the Image Upscale API: turn an image into a data URI, submit a job, check status, then download the PNG. Includes Node.js and Python code and the full error code list.

This guide shows how to use the Image Upscale API from start to finish, until the result is saved on disk: turn an image into a data URI, submit a job, check its status, then download the result. Code samples are available in Node.js and Python.
What You'll Need
- An API key from dashboard.apiindonesia.id. New accounts get a bonus of 3,000 credits, enough to try the 2x tier.
- A PNG, JPEG or WebP image of at most 1 MB and at most 1 MP (for example 1000×1000 or 1200×800).
The Short Version
| Step | Endpoint | Cost |
|---|---|---|
| 1. Submit a job | POST /api/v1/image/upscale/{2x|4x|8x} |
250 / 1,000 / 4,000 credits |
| 2. Check status | GET /api/v1/image/jobs/{job_id} |
Free |
| 3. Download the result | GET /api/v1/image/jobs/{job_id}/file |
Free |
Base URL: https://use.apiindonesia.id. Every request uses the x-api-key header.
Upscaling runs asynchronously. The submit call answers right away with 202 Accepted and a job_id, then you check the status every few seconds. In our test, a 2x job for an 800×600 photo finished in about 6 seconds.
Step 1: Turn the Image Into a Data URI
The API only accepts images as a data URI (data:image/jpeg;base64,...). Plain http URLs are rejected on purpose, so you don't need to host the image anywhere.
Full Example: Node.js (18+)
import { readFile, writeFile } from 'node:fs/promises'
const API = 'https://use.apiindonesia.id/api/v1/image'
const headers = { 'x-api-key': process.env.API_INDONESIA_KEY }
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
async function upscale(path, tier = '2x') {
// 1. Data URI
const bytes = await readFile(path)
const mime = path.endsWith('.png') ? 'image/png' : path.endsWith('.webp') ? 'image/webp' : 'image/jpeg'
const image = `data:${mime};base64,${bytes.toString('base64')}`
// 2. Submit the job
const submit = await fetch(`${API}/upscale/${tier}`, {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json' },
body: JSON.stringify({ image }),
})
const job = await submit.json()
if (submit.status !== 202) throw new Error(`${job.error.code}: ${job.error.message}`)
// 3. Poll the status until it finishes
let status
do {
await sleep(3000)
status = (await (await fetch(`${API}/jobs/${job.data.job_id}`, { headers })).json()).data
} while (status.status === 'pending')
if (status.status === 'failed') throw new Error(`${status.error.code}: ${status.error.message}`)
// 4. Download the result (PNG), within 1 hour
const file = await fetch(status.download_url, { headers })
await writeFile(`upscaled-${tier}.png`, Buffer.from(await file.arrayBuffer()))
return status.result // { width, height }
}
console.log(await upscale('produk.jpg', '2x'))
Full Example: Python
import base64, os, time, requests
API = "https://use.apiindonesia.id/api/v1/image"
HEADERS = {"x-api-key": os.environ["API_INDONESIA_KEY"]}
def upscale(path, tier="2x"):
mime = "image/png" if path.endswith(".png") else "image/webp" if path.endswith(".webp") else "image/jpeg"
with open(path, "rb") as f:
image = f"data:{mime};base64,{base64.b64encode(f.read()).decode()}"
submit = requests.post(f"{API}/upscale/{tier}", json={"image": image}, headers=HEADERS)
body = submit.json()
if submit.status_code != 202:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
job_id = body["data"]["job_id"]
while True:
time.sleep(3)
status = requests.get(f"{API}/jobs/{job_id}", headers=HEADERS).json()["data"]
if status["status"] != "pending":
break
if status["status"] == "failed":
raise RuntimeError(f"{status['error']['code']}: {status['error']['message']}")
result = requests.get(status["download_url"], headers=HEADERS)
with open(f"upscaled-{tier}.png", "wb") as f:
f.write(result.content)
return status["result"]
print(upscale("produk.jpg", "2x"))
Example Status Response
{
"success": true,
"data": {
"id": "2fa711a4-deca-42df-90c2-fde8e528de17",
"status": "succeeded",
"tier": "2x",
"credits_charged": 250,
"source": { "width": 800, "height": 600 },
"result": { "width": 1600, "height": 1200 },
"download_url": "https://use.apiindonesia.id/api/v1/image/jobs/2fa711a4-deca-42df-90c2-fde8e528de17/file",
"download_expires_at": "2026-10-23T09:34:55.583Z",
"error": null
}
}
Error Codes You Need to Handle
| Status | Code | Meaning |
|---|---|---|
| 400 | INVALID_IMAGE |
Not a valid PNG/JPEG/WebP data URI |
| 400 | IMAGE_TOO_LARGE |
More than 1 MB or more than 1 MP |
| 402 | INSUFFICIENT_CREDITS |
Not enough credit balance |
| 403 | TIER_REQUIRES_TOPUP |
The 4x/8x tiers require an account that has topped up before |
| 403 | BONUS_UPSCALE_LIMIT |
The 4 jobs included with the signup bonus have been used |
| 410 | RESULT_EXPIRED |
More than 1 hour has passed, submit the image again |
| 502 | UPSTREAM_UNAVAILABLE |
The processor is having trouble, no charge is made |
Rejected requests don't deduct credits, and jobs that fail after being accepted are refunded in full.
Tips
- Compress to JPEG or WebP first if your PNG is over 1 MB. For upscaling, JPEG at quality 90 is good enough.
- Save the result to your own storage. Results are only available for 1 hour and we don't keep a copy.
- Batch: send one request per image and store its
job_id. Checking the status is free.
FAQ
Why doesn't the API accept image URLs? So our servers can't be pointed at fetching arbitrary URLs. Images are sent as a data URI, which also means you don't need to host the image anywhere.
How long does one upscale job take?
Usually a few seconds. In our test, an 800×600 photo on the 2x tier finished in about 6 seconds. Check the status every 3 seconds as given by poll_after_seconds.
What happens if I download too late?
After 1 hour, the download endpoint answers 410 RESULT_EXPIRED and you need to submit the image again.
What format comes back? PNG, at the size of the chosen tier scale: 2x, 4x or 8x the input size.
Start Now
Get an API key at dashboard.apiindonesia.id/register, take a look at the Image Upscale API product page, and read the use case in Image Upscale API for Marketplace Product Photos.
