API v1
API Reference — Optimize Images over HTTP
Endpoint reference for the OptimizeYourImage API: POST a JPEG, PNG, WebP, HEIC or HEIF file and get synchronous image bytes with store=none (no persistent image storage), or JSON with a result URL using store=temp or store=cdn.
Performance & quality benchmark →Optimize an image
Send a multipart request to POST /v1/images/optimize with an API key in the Bearer authorization header. With store=none (the default), a successful response contains optimized image bytes; store=temp and store=cdn return JSON with a result URL.
curl --request POST \
--url https://backend.optimizeyourimage.com/v1/images/optimize \
--header "Authorization: Bearer oyi_live_your_key" \
--header "Idempotency-Key: 8f32b13e-7aa8-4d65-b332-34e29a3629bc" \
--form "[email protected]" \
--form "output_format=webp" \
--form "quality=80" \
--output optimized.webpRequest fields
| Field | Accepted values | Default |
|---|---|---|
| file | JPEG, PNG, WebP, HEIC, or HEIF; 20 MB and 25 MP maximum. Send either file or source_url, not both | One of file / source_url |
| source_url | Public http(s) URL the API fetches instead of an upload. Default ports only, no credentials, up to 3 redirects, same 20 MB / 25 MP limits. Private and internal addresses are refused. The URL is fetched in memory and never logged or stored | One of file / source_url |
| output_format | webp, avif, jpeg, png | webp |
| quality | Integer from 1 to 100 | 80 |
| max_width | Positive integer; images are never enlarged | Original |
| max_height | Positive integer; aspect ratio is preserved | Original |
| preserve_metadata | true or false; keeps EXIF for JPEG output only (orientation normalized), other outputs strip metadata | false |
| store | store=none returns raw bytes without persistent image storage; store=temp returns JSON with a 2-hour download link (access expiry is separate from physical deletion through storage lifecycle cleanup); store=cdn returns JSON with a public URL and publishes on cdn.optimizeyourimage.com and is retained until user deletion, Terms enforcement, or plan/subscription lifecycle cleanup; it counts against your storage quota (list with GET /v1/images/cdn, remove with DELETE /v1/images/cdn/{file}) | none |
| name | store=cdn only: choose the published file name for a stable URL (letters, digits, hyphen, underscore; the output-format extension is appended). Re-publishing the same name needs overwrite=true, otherwise 409 | Random name |
| overwrite | true replaces the existing object under the same name and URL — quota is charged as the size difference; edge caches may continue serving the old version until cache expiry or invalidation | false |
Limits and credits
- One successful image consumes one credit; validation and processing failures do not.
- Only the primary still image is processed from HEIC/HEIF containers.
- Requests have a 30-second deadline. With store=none, source and output images are not persistently stored; opt-in modes retain only optimized results as described above. Operational metadata and idempotency fingerprints may be retained as described in the Privacy Policy.
- Use a unique Idempotency-Key when a request may be retried. A completed key prevents a second charge, but returns 409 rather than replaying the completed response.
Success response
With store=none, the response body is the raw optimized image. The headers below describe this byte response. With store=temp or store=cdn, the response is application/json with a result URL; parse it as JSON instead of saving the response as image bytes. Temporary link expiry is not a physical deletion deadline; storage lifecycle cleanup is separate and no fixed deletion deadline is guaranteed.
| Header | Meaning |
|---|---|
| Content-Type | The actual JPEG, PNG, WebP, or AVIF media type. |
| Content-Disposition | A sanitized suggested output filename. |
| X-Request-Id | Safe identifier to include in a support request. |
| X-Input-Format | The format detected from the uploaded bytes. |
| X-Output-Format | The encoder that produced the response body. |
| X-Original-Size | Source image size in bytes — compute savings without keeping the source around. |
| X-Credits-Remaining | Available, unexpired credits after this successful image. |
Node.js
const body = new FormData();
body.set("file", new Blob([await fs.readFile("photo.png")]), "photo.png");
body.set("output_format", "avif");
body.set("quality", "80");
const response = await fetch("https://backend.optimizeyourimage.com/v1/images/optimize", {
method: "POST",
headers: {
Authorization: "Bearer " + process.env.OYI_API_KEY,
"Idempotency-Key": crypto.randomUUID(),
},
body,
});
if (!response.ok) throw new Error(await response.text());
await fs.writeFile("optimized.avif", Buffer.from(await response.arrayBuffer()));Python
import os
import requests
with open("photo.jpg", "rb") as image:
response = requests.post(
"https://backend.optimizeyourimage.com/v1/images/optimize",
headers={"Authorization": f"Bearer {os.environ['OYI_API_KEY']}"},
files={"file": ("photo.jpg", image, "image/jpeg")},
data={"output_format": "webp", "quality": 80},
timeout=35,
)
response.raise_for_status()
with open("optimized.webp", "wb") as output:
output.write(response.content)Errors
Errors use application/problem+json. A depleted balance returns 402, rate limiting returns 429 with Retry-After and X-RateLimit-* headers, an oversized input returns 413, unsupported formats return 415, and malformed images return 422. Every response includes a request identifier for support and tracing. Each error's type field links to its page in the problem-type reference.
OpenAPI specification
A machine-readable OpenAPI 3.1 document for this API is published at /openapi.json. Use it for client generation, request validation, or importing into tools like Postman and Insomnia.
Keys and billing
Sign in with Google or a magic link, then use the developer dashboard to create and revoke keys, inspect credits and usage, open hosted Polar checkout, or enter the customer portal. The authenticated supporting endpoints are POST /v1/api-keys, GET /v1/api-keys, DELETE /v1/api-keys/:id, POST /v1/billing/checkout, and POST /v1/billing/portal. API keys are shown once and stored only as hashes.