Overview
A hosted endpoint for the same compress job the CLI and library run — for anything that isn't already a Node process.
50 KB or less, at the highest quality possible — never exactly 50.000 KB.
The HTTP API is the fourth surface for that promise, alongside the website, the CLI, and the
library — and it shares the CLI’s own backend: POST /v1/compress runs the exact same
compressJob/runJob recipe over the exact same wasm codecs, deployed as a Cloudflare Worker at
api.imagekbreducer.com. Script it, the CLI, or the library against the same input and get back
the same bytes — for every input this endpoint accepts. It accepts fewer than the other two: no
HEIC, and lower byte and pixel ceilings. Limits has each refusal and its reason;
the parity note on the homepage covers the separate question of why
the browser is not byte-identical to any of them.
Use this when the compression has to happen from somewhere that isn’t already running Node — a
Rails, Django, or PHP backend; a mobile app’s server side; a CI system that can’t shell out to
npx. If your own code already runs on Node, the library is a function call
away and has no network hop at all.
One call
curl https://api.imagekbreducer.com/v1/compress \
-H "Authorization: Bearer $IKB_API_KEY" \
-F file=@photo.jpg \
-F target=50kb \
-o photo-compressed.jpg
file and target are the only required fields. file must be JPEG, PNG, or WebP — HEIC
and AVIF are refused with 415 unsupported-format, which is worth knowing before your first
call, because a photo straight off an iPhone is HEIC by default. Convert it first, or use the
CLI or the web app, which decode HEIC natively; see
Limits for why this endpoint can’t.
The response, on success, is the compressed image’s raw bytes with a Content-Type matching the
format it was encoded to, plus a handful of X-* headers describing what happened:
| Header | Meaning |
|---|---|
X-Original-Bytes |
size of the uploaded file |
X-Result-Bytes |
size of the compressed result — always at or under target |
X-Attempts |
how many encode attempts the search made |
X-Result-Width / X-Result-Height |
pixel dimensions of the result |
X-Warnings |
comma-separated warning codes, e.g. metadata-stripped,downscale-applied |
The whole surface
| Route | Auth | Purpose |
|---|---|---|
POST /v1/compress |
required | compress file to target, optionally pinning format and allow_downscale |
GET /v1/health |
none | liveness check — { ok: true, version: "…" } |
OPTIONS /v1/compress |
none | 204 with Allow: POST — not a CORS preflight response, see Authentication |
Full field-by-field detail lives in the reference below, generated from openapi.yaml.
Where to go next
Authentication
Bearer tokens, how they’re issued, and why there’s no CORS support.
Errors
Every status and error code this API can return, and what each means.
Limits
Byte, pixel, and encode-attempt ceilings — and what actually bounds a running job.
Privacy
What this endpoint does and doesn’t retain about a request.
This surface is new (v0.1.0) and single-endpoint by design — it exists to serve one job well,
not to expose the library’s full resize/crop/rotate/strip recipe set over HTTP. If you need
those, run the library or the CLI directly.