New to the API?
Start with our Quickstart Guide — convert your first image in 30 seconds
API Documentation
Convert images programmatically. Free, fast, no signup.
Quick Start
Create an account at /account/signup/ (free, email only)
Include it as X-API-Key header or ?api_key= parameter
POST your image to /api/v1/convert
Authentication
Two methods (use either):
Header: X-API-Key: kp_your_key_here
Query: ?api_key=kp_your_key_here
Anonymous requests work but have lower rate limits.
See API Key terms for usage policies and responsibilities.
Browser Integration
When calling the API from browser JavaScript without an API key, you must include a CSRF token to prevent cross-site request forgery.
When is CSRF required?
| Scenario | CSRF Required? |
|---|---|
| Browser POST/PUT/PATCH/DELETE without API key | Yes |
Any request with X-API-Key header |
No (bypassed) |
| GET requests | No (exempt) |
| Server-to-server requests (curl, Python, etc.) | No (use API key) |
3-step flow
Fetch GET /api/v1/csrf-token to set the csrftoken cookie
Read the cookie value: document.cookie → csrftoken=...
Include X-CSRFToken: <value> in your POST/PUT/PATCH/DELETE headers
JavaScript example
// Step 1: Get the CSRF cookie (one-time)
await fetch('/api/v1/csrf-token');
// Step 2: Read the cookie
function getCsrfToken() {
const c = document.cookie.split('; ')
.find(r => r.startsWith('csrftoken='));
return c ? c.split('=')[1] : '';
}
// Step 3: Include in your requests
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('output_format', 'jpg');
const response = await fetch('/api/v1/convert', {
method: 'POST',
headers: { 'X-CSRFToken': getCsrfToken() },
body: formData,
});
Tip: If you're building a server-side integration, skip CSRF entirely and use an API key instead. CSRF is only needed for browser-based JavaScript without authentication.
CORS Policy
The API uses a split CORS policy based on authentication method. CORS headers are only added to /api/* paths.
API Key Requests (Any Origin)
Requests with an X-API-Key header or ?api_key= parameter are allowed from any origin. No CORS restrictions apply. This lets third-party websites and applications call the KoalaPic API directly from browser JavaScript.
Anonymous Browser Requests (Restricted)
Requests without an API key are restricted to allowed origins (koalapic.com). These requests include Access-Control-Allow-Credentials: true for CSRF cookie support. See Browser Integration above.
Exposed Headers
The following custom headers are accessible to JavaScript on cross-origin requests:
X-RateLimit-Limit-Minute,X-RateLimit-Limit-Day,X-RateLimit-TierX-Download-Limit-Remaining-IP,X-Download-Limit-Remaining-TokenX-API-Version,Deprecation,Sunset,Retry-After
Example: Third-Party Integration
// Call KoalaPic API from your own website using an API key
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('output_format', 'webp');
const response = await fetch('https://koalapic.com/api/v1/convert', {
method: 'POST',
headers: { 'X-API-Key': 'kp_your_api_key_here' },
body: formData,
});
// No CORS restrictions — works from any domain!
Preflight Caching
OPTIONS preflight responses are cached for 1 hour (Access-Control-Max-Age: 3600), minimizing round trips for browsers.
Rate Limits
| Per Minute | Per Day | |
|---|---|---|
| With API Key | 30 | 500 |
| Anonymous | 10 | 50 |
Response headers: X-RateLimit-Limit-Minute, X-RateLimit-Limit-Day, Retry-After (on 429)
See Rate Limit terms for fair use policies and escalation details.
Endpoints
/api/v1/convert
Convert an image to a different format.
Parameters (multipart/form-data)
file
required
— Image file (max 50 MB)
output_format
required
— jpg, png, webp, avif, heic, tiff, gif, bmp, svg, pdf, ico
quality
optional
— 1-100, default 85 (applies to JPG, WEBP, AVIF, HEIC)
tiff_compression
optional
— tiff_lzw (default), raw, tiff_deflate. Only for TIFF output.
gif_colors
optional
— 2-256, default 256. Only for GIF output.
gif_dither
optional
— true (default) or false. Floyd-Steinberg dithering for GIF.
svg_trace_mode
optional
— polygon (default) or spline. Only for SVG output.
pdf_dpi
optional
— 72–600 (default 150). Rendering resolution for PDF input.
pdf_page_range
optional
— e.g. "1-3, 5, 8-10". Empty = all pages. Only for PDF input.
crop_x
optional
— Crop X offset in pixels. All four crop params required together.
crop_y
optional
— Crop Y offset in pixels.
crop_width
optional
— Crop width in pixels.
crop_height
optional
— Crop height in pixels.
preview_id
optional
— UUID from POST /preview. Use instead of file for two-step crop flow.
edit_rotate
optional
— Clockwise rotation 0-359°. 90° increments are lossless.
edit_filter
optional
— Named filter preset (e.g. grayscale, sepia, vintage). See GET /filters.
edit_brightness
optional
— Brightness 0.0-3.0 (1.0=unchanged). Also: edit_contrast, edit_saturation, edit_sharpness, edit_blur, edit_flip_horizontal, edit_flip_vertical, edit_auto_enhance.
Success: Binary file (converted image)
Error: { "error": "message" }
curl -X POST https://koalapic.com/api/v1/convert \
-H "X-API-Key: kp_your_key_here" \
-F "file=@photo.heic" \
-F "output_format=jpg" \
-F "quality=90" \
--output photo.jpg
import httpx
response = httpx.post(
"https://koalapic.com/api/v1/convert",
headers={"X-API-Key": "kp_your_key_here"},
files={"file": open("photo.heic", "rb")},
data={"output_format": "jpg", "quality": "90"},
)
if response.status_code == 200:
with open("photo.jpg", "wb") as f:
f.write(response.content)
print(f"Converted! Size: {len(response.content)} bytes")
else:
print(f"Error: {response.json()['error']}")
import fs from "fs";
const form = new FormData();
form.append("file", fs.createReadStream("photo.heic"));
form.append("output_format", "jpg");
form.append("quality", "90");
const res = await fetch("https://koalapic.com/api/v1/convert", {
method: "POST",
headers: { "X-API-Key": "kp_your_key_here" },
body: form,
});
if (res.ok) {
const buf = await res.arrayBuffer();
fs.writeFileSync("photo.jpg", Buffer.from(buf));
console.log("Converted!");
} else {
const err = await res.json();
console.error(err.error);
}
/api/v1/convert/url/batch
Convert multiple images from URLs in a single batch request.
Parameters (JSON body)
urls
required
— Array of image URLs (1–50, must start with http:// or https://)
output_format
default: jpg
— Target format (jpg, png, webp, avif, etc.)
quality
default: 85
— Output quality 1–100 (lossy formats only)
webhook_url
optional
— Webhook URL for completion events (requires API key auth)
Success: { "job_id": "...", "conversions": [...] }
Workflow: Poll with GET /v1/jobs/{'{'}job_id{'}'} or stream via SSE. Download all results as ZIP.
curl -X POST https://koalapic.com/api/v1/convert/url/batch \
-H "X-API-Key: kp_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"urls": [
"https://example.com/photo1.jpg",
"https://example.com/photo2.png"
],
"output_format": "webp",
"quality": 80
}'
const res = await fetch("https://koalapic.com/api/v1/convert/url/batch", {
method: "POST",
headers: {
"X-API-Key": "kp_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
urls: [
"https://example.com/photo1.jpg",
"https://example.com/photo2.png",
],
output_format: "webp",
quality: 80,
}),
});
const { job_id, conversions } = await res.json();
console.log(`Job ${job_id}: ${conversions.length} conversions started`);
// Poll for completion
const status = await fetch(
`https://koalapic.com/api/v1/jobs/${job_id}`,
{ headers: { "X-API-Key": "kp_your_key_here" } }
).then(r => r.json());
// Download ZIP when complete
if (status.status === "completed") {
window.location = `https://koalapic.com/api/v1/download/batch/${job_id}`;
}
/api/v1/formats
List all supported format conversion pairs. No authentication required.
Response
{
"input_formats": ["heic", "webp", "avif", "tiff", "bmp", "svg", "gif", "png", "jpg", "cr2", "cr3", "nef", "arw", "dng"],
"output_formats": ["jpg", "png", "webp", "avif", "heic", "tiff", "gif", "bmp", "svg", "pdf", "ico"],
"pairs": [
{ "input": "heic", "output": "jpg" },
...
]
}
curl https://koalapic.com/api/v1/formats
/api/v1/status
Service health status. No authentication required.
Response
{
"status": "ok",
"services": {
"database": "ok",
"redis": "ok",
"huey": "ok"
}
}
curl https://koalapic.com/api/v1/status
/api/v1/rate-limit
Check your current rate limit status and usage.
Response (authenticated)
{
"authenticated": true,
"limits": {
"per_minute": 30,
"per_day": 500
},
"usage": {
"today_requests": 42,
"today_conversions": 38
}
}
curl -H "X-API-Key: kp_..." https://koalapic.com/api/v1/rate-limit
/api/v1/filters
List available image filter presets for the edit_filter parameter.
Returns a sorted array of filter objects with id and name fields.
curl https://koalapic.com/api/v1/filters
/api/v1/preview
Upload an image to get a browser-viewable preview and dimensions. Used for building crop UIs with non-browser formats (HEIC, RAW, TIFF).
Parameters (multipart/form-data)
file
required
— Image file (max 50 MB)
Response
{
"preview_id": "a1b2c3d4-...",
"preview_url": "/api/v1/preview/a1b2c3d4-.../image",
"width": 4032,
"height": 3024,
"format": "heic",
"file_size": 3200000,
"is_browser_renderable": false
}
Two-step crop flow: Upload via POST /preview, then convert via POST /convert with preview_id + crop parameters. Previews expire after 1 hour.
# Upload for preview
curl -X POST https://koalapic.com/api/v1/preview \
-H "X-CSRFToken: ..." \
-F "file=@photo.heic"
# Crop using preview_id (no re-upload)
curl -X POST https://koalapic.com/api/v1/convert \
-H "X-API-Key: kp_your_key_here" \
-F "preview_id=a1b2c3d4-..." \
-F "output_format=jpg" \
-F "crop_x=100" \
-F "crop_y=200" \
-F "crop_width=800" \
-F "crop_height=600"
Converting PDFs
Upload a PDF to POST /api/v1/convert and KoalaPic renders each page as a separate image. The response returns a job ID for polling progress.
# Convert PDF pages 1-3 to PNG at 300 DPI
curl -X POST https://koalapic.com/api/v1/convert \
-H "X-API-Key: kp_your_key_here" \
-F "file=@document.pdf" \
-F "output_format=png" \
-F "pdf_dpi=300" \
-F "pdf_page_range=1-3"
# Response (202):
# { "job_id": "...", "total_pages": 10, "requested_pages": 3, "conversions": [...] }
# Poll job status
curl -H "X-API-Key: kp_..." \
https://koalapic.com/api/v1/jobs/JOB_ID
# Download all pages as ZIP
curl -H "X-API-Key: kp_..." \
https://koalapic.com/api/v1/download/batch/JOB_ID --output pages.zip
- PDF-to-PDF conversion is not supported
- PDF files cannot be included in batch uploads
- Maximum 200 pages per PDF (20 for bots)
- DPI range: 72–600 (default: 150)
Error Handling
All errors return JSON: { "error": "Human-readable message" }
| Code | Meaning |
|---|---|
| 400 | Bad request (invalid file or format) |
| 401 | Invalid or missing API key |
| 413 | File too large (max 50 MB) |
| 415 | Unsupported file type |
| 429 | Rate limit exceeded (check Retry-After header) |
| 500 | Server error (our team is notified) |
Versioning
The API uses URL path versioning. The current version is
v1,
accessed at /api/v1/.
Version Lifecycle
| Status | Meaning | Response Headers |
|---|---|---|
active |
Fully supported. Recommended for new integrations. | X-API-Version: v1 |
deprecated |
Still fully functional, but a newer version is available. Migrate when convenient. |
Deprecation: trueSunset: <date>Link: ...rel="successor-version"
|
retired |
No longer available. Returns 410 Gone. |
N/A (410 response with migration guide link) |
Retirement Policy
We support API versions indefinitely. When a new version launches, older versions are marked
deprecated
but continue working. Retirement only happens after explicit announcement — there are no automatic shutoffs.
Detecting Deprecation
Monitor the Deprecation
response header. If present, your version has a newer successor. The
Link
header points to the migration guide.
Deprecation: true
Sunset: Wed, 01 Jan 2027 00:00:00 GMT
Link: </api/v2/docs/>; rel="successor-version",
</api/v1/migration/v2>; rel="migration-guide"
Version Endpoints
| Endpoint | Description |
|---|---|
GET /api/versions |
List all API versions and their status |
GET /api/v1/changelog |
Structured changelog for this version |
GET /api/v1/migration/{'{'}target{'}'} |
Migration guide to a target version (when available) |
Supported Formats
Input
HEIC, HEIF, WEBP, AVIF, TIFF, BMP, SVG, GIF, PNG, JPG, CR2, CR3, NEF, ARW, DNG
Output
JPG, PNG, WEBP, AVIF, HEIC, TIFF, GIF, BMP, SVG, PDF, ICO
Data Retention
API-created data follows these retention periods:
- Conversion files: 1 hour (automatically deleted)
- Conversion metadata (authenticated): 1 year
- Conversion metadata (anonymous): 30 days
- API usage logs: 90 days
- Webhook delivery logs: 7 days
See our Privacy Policy for the complete retention schedule.
Data Processing Agreement (DPA)
If your organization processes personal data through the KoalaPic API, GDPR Article 28 requires a Data Processing Agreement between you (the data controller) and KoalaPic (the data processor).
Our DPA covers:
- Scope and purpose of data processing
- Technical and organizational security measures
- Sub-processor disclosures
- Data breach notification procedures
- Data subject rights assistance
- International data transfer safeguards
View the full DPA · Download PDF
For a countersigned copy, contact support@koalapic.com.
SDKs & Integrations
No official SDK yet — the API is a simple multipart POST. Works with any HTTP client: curl, httpx, requests, fetch, axios.
Need Help?
- Interactive API Explorer — Try API calls in your browser (Swagger UI)
- Create an account — Free, email-only sign up
- Help Center — Step-by-step guides and tutorials
- Check service status — Real-time system health