Endpoint reference¶
POST /v1/image¶
The one chainable pipeline endpoint. Send an image, describe what to do to it, get the processed image back.
POST https://api.purlo.dev/v1/image
Authorization: Bearer <api_key>
Content-Type: multipart/form-data
Local dev: http://localhost:3000/v1/image.
Input¶
Provide the image one of two ways:
| Form | How |
|---|---|
| Upload | multipart/form-data field named image (the file). |
| URL | A url field (form field or JSON body) pointing at the image to fetch. |
Either way, also send an operations field: a JSON object (as a string, in the
multipart body) describing the pipeline. If you provide neither image nor
url, the request fails with 400 no_image.
Only http and https URLs are fetched, and the fetch is SSRF-guarded —
see Errors & limits for what gets
rejected and why.
operations¶
{
"resize": { "w": 800, "h": null, "fit": "inside" },
"format": "webp",
"quality": 80,
"strip": true
}
All four keys are optional. Unknown top-level keys (or unknown keys inside
resize) are rejected with 400 invalid_operations.
| Key | Type | Default | Notes |
|---|---|---|---|
resize |
object { w, h, fit } |
omitted = no resize | See below. |
format |
string: jpeg | png | webp | avif |
keeps the input's format | Output container/codec. |
quality |
integer 1–100 | 80 |
Passed to the format encoder (mozjpeg for jpeg, standard quality/quantisation knobs for png/webp/avif). |
strip |
boolean | true |
Removes EXIF/GPS metadata. The ICC colour profile is always kept, even when stripping, so colours don't shift. Set false to keep all original metadata. |
resize¶
| Field | Type | Default | Notes |
|---|---|---|---|
w |
positive integer or null |
null |
Target width in pixels. |
h |
positive integer or null |
null |
Target height in pixels. |
fit |
string | "inside" |
One of inside, outside, cover, contain, fill. |
- At least one of
worhis required ifresizeis present. - Both are capped at a maximum dimension (10,000px by default — see Errors & limits); requesting larger fails validation.
- Resize never enlarges. If your requested size is bigger than the source image, Purlo downscales-or-keeps but never scales up past the original. You can't use resize to blow a small image up into a large one.
Order of operations¶
Operations always apply in this fixed order, regardless of key order in your JSON:
resizeformat+quality(convert and compress together)strip(metadata handling)
This is a documented, stable contract — chain confidently.
Response¶
Success (200): the processed image, as raw bytes, with:
Content-Type: image/webp (matches the output format)
X-Purlo-Output-Format: webp
X-Purlo-Output-Bytes: 42110
X-Purlo-Operations: resize,format=webp,quality=80,strip
X-Purlo-Quota-Limit: 1000
X-Purlo-Quota-Remaining: 999
| Header | Meaning |
|---|---|
X-Purlo-Output-Format |
The format actually written (jpeg/png/webp/avif). |
X-Purlo-Output-Bytes |
Size of the response body in bytes. |
X-Purlo-Operations |
Summary of which operations ran, e.g. resize,format=webp,quality=80,strip. |
X-Purlo-Quota-Limit |
Your plan's monthly image quota. |
X-Purlo-Quota-Remaining |
Images remaining this month, after this request. |
Error: JSON, see Errors & limits.