◆ POST /v1/image

Web-safe images in one API call.

Resize, convert, compress and strip metadata — chained in a single request. A cheap, simple image API for developers who don't want to run their own pipeline.

1,000 images/month free. Images are processed and discarded — never stored.

resize → webp → strip
# one call: 800px wide, WebP q80, EXIF/GPS stripped
curl -X POST https://api.purlo.dev/v1/image \
  -H "Authorization: Bearer purlo_YOUR_KEY" \
  -F 'operations={"resize":{"w":800},"format":"webp","quality":80,"strip":true}' \
  -F "image=@photo.jpg" \
  -o out.webp

One chainable pipeline

Four operations, one request

You don't need seven single-purpose tools. Send one operations object; Purlo applies them in a fixed, documented order and returns the finished image.

Resize

Fit to width/height with fit modes. Never upscales.

Convert

Output webp, avif, jpeg or png.

Compress

quality 1–100 via mozjpeg & friends.

Strip

Drops EXIF/GPS; keeps the ICC colour profile.

Copy, paste, ship

Runnable in every language

The same call — resize to 800px, WebP at quality 80, strip metadata — in the language you already use.

curl
curl -X POST https://api.purlo.dev/v1/image \
  -H "Authorization: Bearer purlo_YOUR_KEY" \
  -F 'operations={"resize":{"w":800},"format":"webp","quality":80,"strip":true}' \
  -F "image=@photo.jpg" \
  -o out.webp
Node 18+ / browser
const form = new FormData();
form.append('operations', JSON.stringify({
  resize: { w: 800 }, format: 'webp', quality: 80, strip: true,
}));
form.append('image', fileBlob, 'photo.jpg');

const res = await fetch('https://api.purlo.dev/v1/image', {
  method: 'POST',
  headers: { Authorization: 'Bearer purlo_YOUR_KEY' },
  body: form,
});
const out = new Uint8Array(await res.arrayBuffer());
PHP (curl)
$ch = curl_init('https://api.purlo.dev/v1/image');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer purlo_YOUR_KEY'],
    CURLOPT_POSTFIELDS => [
        'operations' => '{"resize":{"w":800},"format":"webp","strip":true}',
        'image'      => new CURLFile('photo.jpg'),
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
file_put_contents('out.webp', curl_exec($ch));
Python (requests)
import json, requests

ops = {"resize": {"w": 800}, "format": "webp", "quality": 80, "strip": True}

with open("photo.jpg", "rb") as image:
    r = requests.post(
        "https://api.purlo.dev/v1/image",
        headers={"Authorization": "Bearer purlo_YOUR_KEY"},
        data={"operations": json.dumps(ops)},
        files={"image": image},
    )
open("out.webp", "wb").write(r.content)

Prefer a client? npm install @purlo/cli — a zero-dependency library and purlo CLI.

Privacy by default

Your users' images are never stored

Purlo is stateless. Every upload is processed in memory or a temp path and deleted the moment the response is sent. We keep accounts, API keys and usage counts — never image data.

Read the privacy note

Simple, volume-based

Pricing that stays out of the way

Start free, upgrade when you outgrow it, cancel any time from the self-service portal. Prices in GBP.

Free
£0
1,000 images / mo
Get a key
Starter
£5 / mo
5,000 images / mo
Popular Growth
£15 / mo
25,000 images / mo
Scale
£40 / mo
100,000 images / mo

Hit your limit and you get a clear 429 with an upgrade link — no surprise overage bills.

Five minutes to your first call

Get a free API key

Enter your email, click the magic link, and your key is issued. No card, 1,000 images a month.