---
title: "Compress an image"
method: POST
path: "/images"
tags: ["Images"]
---

# Compress an image

`POST /images`

## Request

- Base URL: `https://www.iminify.com/api/v1`
- URL: `https://www.iminify.com/api/v1/images`
- Auth: HTTP bearer

Send the image itself as a multipart `file`, or its address as `url` and Iminify fetches it. The answer comes straight back with the status `queued` and a `Location` header; the compression runs in the background, usually for a few seconds, so poll the image until its status is `completed`, `already-optimized`, `failed` or `cancelled`. Each image counts one against your daily images and your compressions a minute, whether it came through here or through the website.

The file goes through the same checks as an upload on the website: a format Iminify reads (PNG, JPG, JPEG, WEBP, GIF, HEIC, HEIF, TIFF, TIF), your plan's file size, a name of at most 128 bytes, and at most 64 megapixels, before and after any resize. An animated WebP or PNG can't be resized: with `width`, `height` or `scale` it is refused with `animation_not_resizable`, and one sent without them, in its own format, comes back with every frame. An address has to be public `http` or `https`: Iminify fetches it from its own servers, refuses private networks on the address and on every redirect, follows up to five redirects and gives up after 30 seconds. A file larger than your plan's size is refused, and Iminify keeps no more of it than that size. The file is named after the address. Iminify fetches up to 2 addresses for you at a time; one more sent before those finish is refused with `rate_limited`.

## Request body

- object: The image, as a file or as the address to fetch it from, and the settings to compress it with.
  - `url` string, uri, required: The public address of the image to fetch. Send either this or `file`.
  - `level` 'none' | 'lossless' | 'ultra' | 'smart'
  - `format` 'auto' | 'webp' | 'avif' | 'png' | 'jpg'
  - `keep_metadata` boolean: Keep the EXIF metadata (camera, date, location) in the optimized copy. Off by default, which strips it; the orientation is applied to the pixels first, so a photo never comes back on its side.
  - `width` integer, nullable: Resize to this width in pixels. Alone, the height follows the aspect ratio. With `height` too, the image is resized to exactly that size, and its proportions change if they differ. Up to 65535.
  - `height` integer, nullable: Resize to this height in pixels, the same way as `width`. Up to 65535.
  - `scale` integer, nullable: Resize to this percentage of the original, 1 to 100. Cannot be combined with `width` or `height`.
  - `alt_text` boolean: Write an alt text and a suggested file name for the image with AI. On by default; send `false` to leave it out. A small copy of the image goes to Anthropic, whose Claude model writes both, and they arrive a few seconds after the image finishes. Each one counts against your daily AI alt texts; once those are used up the image still compresses, without one. See [Alt text and file names](/docs/images#alt-text-and-file-names).
  - `alt_text_language` 'en' | 'es' | 'fr' | 'de' | 'it' | 'pt' | 'nl' | 'pl' | 'sv' | 'tr' | 'ru' | 'uk' | 'ar' | 'fa' | 'he' | 'hi' | 'id' | 'vi' | 'th' | 'ja' | 'ko' | 'zh-Hans' | 'zh-Hant': The language to write the alt text in, as one of these tags: `en` (English), `es` (Spanish), `fr` (French), `de` (German), `it` (Italian), `pt` (Portuguese), `nl` (Dutch), `pl` (Polish), `sv` (Swedish), `tr` (Turkish), `ru` (Russian), `uk` (Ukrainian), `ar` (Arabic), `fa` (Persian), `he` (Hebrew), `hi` (Hindi), `id` (Indonesian), `vi` (Vietnamese), `th` (Thai), `ja` (Japanese), `ko` (Korean), `zh-Hans` (Simplified Chinese), `zh-Hant` (Traditional Chinese). The suggested file name follows it when the language is written in the Latin alphabet, and is in English otherwise.
  - `use_suggested_name` boolean: Rename the optimized copy to the suggested file name as soon as the alt text arrives, unless it already has a new name by then: yours, or an earlier suggestion.

## Response `202`

Queued. `Location` points at the new record.

- object
  - `data` Image, required
    - `id` string, uuid, required: The image's id.
    - `status` 'queued' | 'optimizing' | 'completed' | 'failed' | 'already-optimized' | 'cancelled', required
    - `name` string, required: The name the optimized copy downloads under: the uploaded name, or the one you gave it, with the delivered format's extension. An `auto` conversion has no format until it finishes, so until then the extension is the uploaded file's own.
    - `original` object, required: The file as it was uploaded.
      - `name` string, required: The file name it downloads under.
      - `format` string, required: The file's format, as its extension: `jpg`, `png`, `webp`, `avif`, `gif`, `heic`, `tiff` and so on.
      - `size` integer, required: Its size in bytes.
      - `width` integer, required: Its width in pixels, the way it displays: a phone photo stored on its side is measured upright.
      - `height` integer, required: Its height in pixels, the way it displays.
      - `download_url` string, uri, required: Where to download it with your key.
    - `optimized` object, nullable, required: The optimized copy, or `null` until the image has finished.
      - `name` string, required: The file name it downloads under.
      - `format` string, required: The file's format, as its extension: `jpg`, `png`, `webp`, `avif`, `gif`, `heic`, `tiff` and so on.
      - `size` integer, required: Its size in bytes.
      - `width` integer, required: Its width in pixels, the way it displays: a phone photo stored on its side is measured upright.
      - `height` integer, required: Its height in pixels, the way it displays.
      - `download_url` string, uri, required: Where to download it with your key.
    - `saved_bytes` integer, nullable, required: Bytes the optimized copy saves against the original. Negative when a conversion or an enlargement made the file bigger. `null` until the image has finished.
    - `saved_percent` number, nullable, required: The same saving as a percentage of the original, to two decimal places. `null` until the image has finished.
    - `settings` object, required: The settings the image was compressed with, as they were sent.
      - `level` 'none' | 'lossless' | 'ultra' | 'smart', required
      - `format` 'auto' | 'webp' | 'avif' | 'png' | 'jpg', required
      - `keep_metadata` boolean, required: Whether the EXIF metadata was kept.
      - `width` integer, nullable, required: The width it was resized to, or `null`.
      - `height` integer, nullable, required: The height it was resized to, or `null`.
      - `scale` integer, nullable, required: The percentage it was scaled to, or `null`.
    - `alt_text` object, nullable, required: The AI alt text and suggested file name, or `null` when none was asked for. See [Alt text and file names](/docs/images#alt-text-and-file-names).
      - `status` 'pending' | 'written' | 'failed' | 'skipped', required: Where a result's AI alt text stands. `pending`: asked for and not written yet (only a finished result shows it as in progress; a failed compression keeps the request for its retry). `written`: the text and the suggested file name are stored. `failed`: the model refused, or the call or its thumbnail failed; it can be asked for again. `skipped`: asked for on a day whose alt texts were spent.
      - `text` string, nullable, required: One sentence for the image's `alt` attribute, or `null` until it is written.
      - `language` string, nullable, required: The language tag it was written in.
      - `suggested_name` string, nullable, required: A short descriptive file name without an extension, ready for the rename call, or `null` until it is written or when the model offered none.
    - `scan_id` string, uuid, nullable, required: The page scan that found the image, or `null` for an upload.
    - `source_url` string, uri, nullable, required: The address the image was fetched from: the image's address on the scanned page, or the `url` you sent instead of a file. `null` for a file you sent.
    - `share_url` string, uri, nullable, required: The public page while the image is shared, or `null`.
    - `created_at` string, date-time, required: When the image was queued.
    - `updated_at` string, date-time, required: When anything about it last changed, its status included.

## Other responses

- `401`: `unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.
- `403`: `email_not_verified`: The key belongs to an account whose email address is not verified yet. Follow the link in the verification email, then call again with the same key. `account_banned`: The account behind the key has been banned. Its keys stop working with the ban.
- `422`: `validation_failed`: A field is missing or wrong, or the file or address did not pass the checks every upload goes through. `errors` names each field with its messages. `animation_not_resizable`: A resize was asked of an animated WebP or an animated PNG, and Iminify cannot resize their frames: only the first one would be kept. Without `width`, `height` or `scale`, and in its own format, it comes back with every frame. An animated GIF can be resized.
- `429`: `rate_limited`: One of your per-minute limits is spent: requests, compressions or page scans. The compressions and scans are counted together with the website's, so work queued there counts too. Nothing was done; wait for the number of seconds in the `Retry-After` header and send it again. `daily_limit_reached`: Your plan's images, page scans or AI alt texts for the day are used up. `Retry-After` holds the seconds until the rolling 24-hour window opens again. An image sent while only the alt texts are used up still compresses, without one.
- `503`: `start_failed`: The file could not be stored or queued, usually a short hiccup at the storage. Nothing was counted. Send the same request again.

---

[API](https://skmtc.dev/iminify/apis/iminify-api.md) · [All operations](https://skmtc.dev/iminify/apis/iminify-api/llms.txt) · [OpenAPI document](https://skmtc.dev/iminify/apis/iminify-api/revisions/12dc614c2c21?raw)
