API Documentation
The PuffPix API lets you compress PNG, JPG, WebP, GIF and SVG images programmatically — the same engine that powers the web tool. Send a file, get back a compressed version. No SDK required.
An API key is included with every Starter and Pro plan. Find yours in the usage dashboard.
Authentication
Pass your API key with every request using either of these methods:
Option A — POST field
curl -X POST https://puffpix.com/api.php \
-F "images[][email protected]" \
-F "api_key=YOUR_API_KEY"
Option B — HTTP header
curl -X POST https://puffpix.com/api.php \
-H "X-Api-Key: YOUR_API_KEY" \
-F "images[][email protected]"
Requests without a valid API key are processed as the free plan (5 MB limit, 20 images/day, browser session-scoped).
Quickstart
Three steps: upload → get the JSON response → download the compressed file.
# 1. Compress a file
curl -s -X POST https://puffpix.com/api.php \
-F "images[][email protected]" \
-F "api_key=YOUR_API_KEY" \
-F "quality=75" | jq .
# Response includes a downloadUrl — fetch the result:
curl -O "https://puffpix.com/compressed/{session}/{token}.jpg"
async function compressImage(file, apiKey) {
const fd = new FormData();
fd.append('images[]', file);
fd.append('api_key', apiKey);
fd.append('quality', '75');
const res = await fetch('https://puffpix.com/api.php', { method: 'POST', body: fd });
const data = await res.json();
const result = data[0];
if (result.error) throw new Error(result.error);
// Download the compressed file
const link = document.createElement('a');
link.href = 'https://puffpix.com/' + result.downloadUrl;
link.download = result.suggestedName;
link.click();
console.log(`Saved ${result.saving}% — ${result.originalSize} → ${result.newSize} bytes`);
}
<?php
function compressImage(string $filePath, string $apiKey): array {
$ch = curl_init('https://puffpix.com/api.php');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => [
'images[]' => new CURLFile($filePath),
'api_key' => $apiKey,
'quality' => 75,
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) throw new RuntimeException("HTTP $status");
$result = json_decode($body, true)[0];
if (!empty($result['error'])) throw new RuntimeException($result['error']);
return $result;
}
$result = compressImage('/path/to/photo.jpg', 'YOUR_API_KEY');
// Fetch and save the compressed file
$url = 'https://puffpix.com/' . $result['downloadUrl'];
$data = file_get_contents($url);
file_put_contents('/path/to/output/' . $result['suggestedName'], $data);
echo "Saved {$result['saving']}%\n";
POST /api.php
Compress one or more images in a single request. Files are processed in parallel on the server and results are returned as a JSON array — one object per file, in the same order as the upload.
| Field | Description | |
|---|---|---|
| images[] | required | One or more image files. Use images[] for each file in the multipart body. |
| api_key | optional | Your API key. Alternatively pass as X-Api-Key header. Omit to use free-plan limits. |
| quality | optional | Output quality, 10–95. Default 72. Higher = larger file, better quality. |
| engine | optional | gd (default) or pro. Pro engine uses pngquant + mozjpeg for smaller output. Pro and trial plans only. |
| output_format | optional | auto (default), jpg, png, webp, or gif. Use to convert format on compression. |
| maxdim | optional | Resize the image so neither dimension exceeds this value (pixels). 0 = no resize. Aspect ratio preserved. |
| strip_exif | optional | 1 (default) strips EXIF metadata. 0 preserves it (JPG only). |
| max_filesize_kb | optional | Target output size in KB. PuffPix iterates quality downward until the file fits. Pro plan only. Minimum 50 KB, maximum 2000 KB. |
Parameters
quality
Controls the compression/quality trade-off. Recommended values:
- 85–95 — near-lossless, minimal size reduction
- 72–80 — balanced (default is 72)
- 60–70 — aggressive, noticeable on photos with fine detail
- 10–59 — maximum compression, visible artefacts on complex images
For PNG files, quality controls the pngquant palette reduction (Pro) or GD compression level (standard). PNG is lossless by nature, so very low quality values affect colour depth rather than artefact level.
engine
gd uses PHP's built-in GD library — fast and widely compatible. pro uses:
- pngquant for PNG — palette quantisation giving 60–80% smaller files
- mozjpeg for JPG — better DCT encoding, typically 10–20% smaller than GD at the same quality
- cwebp for WebP — Google's reference encoder
The pro engine is silently downgraded to gd if your plan doesn't include it.
output_format
Convert to a different format on the fly. When auto, the output matches the input format. Converting to WebP typically gives the best file sizes for photos and graphics intended for web use.
Response format
The API always returns Content-Type: application/json with a JSON array. Each element corresponds to one uploaded file.
✓ Successful compression
[
{
"name": "photo.jpg", // original filename
"outName": "a3f9c12b44e8.jpg", // token-based server filename
"suggestedName": "photo.jpg", // recommended save-as name
"originalSize": 204800, // bytes
"newSize": 89200, // bytes
"saving": 56.4, // percent saved (float)
"downloadUrl": "compressed/{sid}/{token}.jpg",
"sizeWarning": false // true if max_filesize_kb target couldn't be reached
}
]
✕ Error on one file
[
{
"name": "photo.jpg",
"error": "File exceeds your plan's size limit."
}
]
The downloadUrl is relative to https://puffpix.com/. Prepend the base URL to fetch the file. Files are auto-deleted after 30 minutes. Download promptly.
Batch requests
You can upload multiple files in one request by appending multiple images[] fields. Results are returned in the same order. If one file fails, the others are not affected.
curl -X POST https://puffpix.com/api.php \
-F "images[][email protected]" \
-F "images[][email protected]" \
-F "images[][email protected]" \
-F "api_key=YOUR_API_KEY"
Errors
Each file result in the array has either a downloadUrl (success) or an error string (failure). The HTTP status is always 200 — check the per-file error field.
| Error message | Cause |
|---|---|
| Invalid API key. | Key not found in database or inactive. |
| Your subscription has expired. | Renewal required. Renew here. |
| Daily limit reached. | You've hit your plan's daily quota. Resets at midnight UTC. |
| This key is active on too many devices. | 3-device limit reached. Contact support to reset. |
| File exceeds your plan's size limit. | File is too large for your plan tier (5 MB free / 25 MB Starter / 100 MB Pro). |
| Not a supported image | File is not a recognized PNG, JPG, WebP, GIF or SVG. |
| Free limit reached — upgrade for unlimited compressions. | 20 compressions/day reached on the free plan. Upgrade. |
"upgrade_required": true so you can branch on it programmatically.
Plan limits
| Limit | Free | Starter | Pro |
|---|---|---|---|
| Max file size | 5 MB | 25 MB | 100 MB |
| Images per day | 20 | 200 | Unlimited |
| Formats | PNG, JPG, WebP, GIF, SVG | PNG, JPG, WebP, GIF, SVG | PNG, JPG, WebP, GIF, SVG |
| Pro engine (pngquant / mozjpeg) | — | — | ✓ (also on trial) |
| Devices per key | — | 3 | 3 |
| API key | — | ✓ | ✓ |
Free-plan requests are additionally session-scoped (tied to a browser PHP session). For server-to-server use, always include an API key.
Rate limits
Daily limits reset at midnight UTC. There is no per-minute or per-second rate limit — you can upload a large batch in one request.
- Each file in a batch counts as one image against your daily quota.
- Your key can be used from up to 3 devices (fingerprinted by User-Agent + Accept-Language). Exceeding this triggers the "too many devices" error.
- Compressed files are automatically deleted 30 minutes after creation. Download before then.
If you need a higher daily limit or more than 3 devices, contact us — custom plans are available.
More code examples
Convert JPG to WebP
curl -X POST https://puffpix.com/api.php \
-F "images[][email protected]" \
-F "api_key=YOUR_API_KEY" \
-F "output_format=webp" \
-F "quality=80"
Resize and compress in one step
curl -X POST https://puffpix.com/api.php \
-F "images[][email protected]" \
-F "api_key=YOUR_API_KEY" \
-F "maxdim=1920" \
-F "quality=78"
Node.js with form-data
import FormData from 'form-data';
import fetch from 'node-fetch';
import fs from 'fs';
async function compress(filePath, apiKey) {
const form = new FormData();
form.append('images[]', fs.createReadStream(filePath));
form.append('api_key', apiKey);
form.append('quality', '75');
const res = await fetch('https://puffpix.com/api.php', { method: 'POST', body: form });
const data = await res.json();
return data[0];
}
const result = await compress('./photo.jpg', process.env.PUFFPIX_API_KEY);
console.log(`-${result.saving}% (${result.newSize} bytes)`);
// Download the result
const download = await fetch('https://puffpix.com/' + result.downloadUrl);
fs.writeFileSync('./photo-compressed.jpg', Buffer.from(await download.arrayBuffer()));
Python
import requests, os
def compress(file_path, api_key, quality=75):
with open(file_path, 'rb') as f:
res = requests.post(
'https://puffpix.com/api.php',
data={'api_key': api_key, 'quality': quality},
files={'images[]': f}
)
result = res.json()[0]
if 'error' in result:
raise ValueError(result['error'])
return result
result = compress('photo.jpg', os.environ['PUFFPIX_API_KEY'])
print(f"Saved {result['saving']}%")
# Download the compressed file
r = requests.get('https://puffpix.com/' + result['downloadUrl'])
with open(result['suggestedName'], 'wb') as f:
f.write(r.content)
Ready to start compressing?
100 free credits, no credit card. Or jump straight to a paid plan from €3.50/mo.