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.webp

Request fields

FieldAccepted valuesDefault
fileJPEG, PNG, WebP, HEIC, or HEIF; 20 MB and 25 MP maximum. Send either file or source_url, not bothOne of file / source_url
source_urlPublic 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 storedOne of file / source_url
output_formatwebp, avif, jpeg, pngwebp
qualityInteger from 1 to 10080
max_widthPositive integer; images are never enlargedOriginal
max_heightPositive integer; aspect ratio is preservedOriginal
preserve_metadatatrue or false; keeps EXIF for JPEG output only (orientation normalized), other outputs strip metadatafalse
storestore=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
namestore=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 409Random name
overwritetrue 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 invalidationfalse

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.

HeaderMeaning
Content-TypeThe actual JPEG, PNG, WebP, or AVIF media type.
Content-DispositionA sanitized suggested output filename.
X-Request-IdSafe identifier to include in a support request.
X-Input-FormatThe format detected from the uploaded bytes.
X-Output-FormatThe encoder that produced the response body.
X-Original-SizeSource image size in bytes — compute savings without keeping the source around.
X-Credits-RemainingAvailable, 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.