{"openapi":"3.1.0","info":{"title":"Iminify API","version":"1.0.0","summary":"Compress, convert and resize images, and scan web pages for every image they load.","description":"Everything the Iminify website does with images, over HTTP. Every request carries a personal access token from Settings > API Tokens as a Bearer token, for an account whose email is verified. Compressions and page scans run in the background: create one, then poll it until it has finished. The guides are at https://www.iminify.com/docs.","termsOfService":"https://www.iminify.com/terms-of-service","contact":{"name":"Iminify","url":"https://www.iminify.com/docs"}},"servers":[{"url":"https://www.iminify.com/api/v1"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Images","description":"Compress, convert and resize images, then download, rename, share or run them again."},{"name":"Page scans","description":"Scan a web page for every image it loads and compress them all at once."},{"name":"Account","description":"The account a key belongs to: its plan, its limits and what today has used."}],"paths":{"/images":{"get":{"operationId":"listImages","description":"Every image on your account, newest first: your uploads, the images your page scans found, and every re-run. The website's results table lists the same images. Follow `links.next` for the next page.","summary":"List images","tags":["Images"],"parameters":[{"name":"status","in":"query","description":"Only images with this status.","schema":{"$ref":"#/components/schemas/CompressStatus"}},{"name":"source","in":"query","description":"`upload` for images you sent (and their re-runs), `scan` for the ones page scans found.","schema":{"type":"string","enum":["upload","scan"]}},{"name":"scan","in":"query","description":"Only the images of this page scan.","schema":{"type":"string","format":"uuid"}},{"name":"per_page","in":"query","description":"Images a page, 1 to 100.","schema":{"type":"integer","default":15,"minimum":1,"maximum":100}},{"name":"page","in":"query","description":"The page to read.","schema":{"type":"integer","default":1,"minimum":1}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer","minimum":1},"from":{"type":["integer","null"],"minimum":1},"last_page":{"type":"integer","minimum":1},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page.","minimum":0},"to":{"type":["integer","null"],"description":"Number of the last item in the slice.","minimum":1},"total":{"type":"integer","description":"Total number of items being paginated.","minimum":0}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]},"example":{"data":[{"id":"9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35","status":"completed","name":"team-offsite.webp","original":{"name":"team-offsite.jpg","format":"jpg","size":2841205,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download?type=original"},"optimized":{"name":"team-offsite.webp","format":"webp","size":212877,"width":1600,"height":1200,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download"},"saved_bytes":2628328,"saved_percent":92.51,"settings":{"level":"smart","keep_metadata":false,"width":1600,"height":null,"scale":null},"scan_id":null,"share_url":null,"created_at":"2026-10-01T09:30:00+00:00","updated_at":"2026-10-01T09:30:06+00:00"},{"id":"9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d","status":"queued","name":"IMG_4471.heic","original":{"name":"IMG_4471.heic","format":"heic","size":3402118,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d/download?type=original"},"optimized":null,"saved_bytes":null,"saved_percent":null,"settings":{"level":"ultra","keep_metadata":true,"width":null,"height":null,"scale":null},"scan_id":null,"share_url":null,"created_at":"2026-10-01T09:31:12+00:00","updated_at":"2026-10-01T09:31:12+00:00"}],"links":{"first":"https://www.iminify.com/api/v1/images?page=1","last":"https://www.iminify.com/api/v1/images?page=1","prev":null,"next":null},"meta":{"current_page":1,"from":1,"last_page":1,"links":[{"url":null,"label":"&laquo; Previous","page":null,"active":false},{"url":"https://www.iminify.com/api/v1/images?page=1","label":"1","page":1,"active":true},{"url":null,"label":"Next &raquo;","page":null,"active":false}],"path":"https://www.iminify.com/api/v1/images","per_page":15,"to":2,"total":2}}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"422":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"},"examples":{"validation_failed":{"summary":"validation_failed","value":{"message":"The selected level is invalid. (and 1 more error)","code":"validation_failed","errors":{"level":["The selected level is invalid."],"width":["The width field prohibits scale from being present."]}}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl \"https://www.iminify.com/api/v1/images?status=completed&per_page=20\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.get(\n    f\"{API}/images\",\n    headers=HEADERS,\n    params={\n        \"status\": \"completed\",\n        \"per_page\": 20,\n    },\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->get('images', [\n    'query' => [\n        'status' => 'completed',\n        'per_page' => 20,\n    ],\n]);\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/images?status=completed&per_page=20', {\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]},"post":{"operationId":"createImage","description":"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.\n\nThe 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 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, gives up after 30 seconds and stops as soon as the file passes your plan's 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`.","summary":"Compress an image","tags":["Images"],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/StoreImageRequest"}},"application/json":{"schema":{"type":"object","description":"The image, as a file or as the address to fetch it from, and the settings to compress it with.","properties":{"url":{"type":"string","format":"uri","description":"The public address of the image to fetch. Send either this or `file`.","maxLength":2048},"level":{"description":"How hard to compress. `smart` finds the lowest quality that still looks like your upload, `ultra` goes further and softens fine texture a little, `lossless` changes no pixel, `none` only applies the format, the resize and the metadata choice. See [Compression settings](/docs/compression-settings).","default":"smart","$ref":"#/components/schemas/CompressLevel"},"format":{"anyOf":[{"description":"Convert to this format. `auto` encodes the image in every format that can hold it and keeps the smallest. Leave it out to keep the upload's own format; a HEIC or TIFF always comes back in another one, because Iminify doesn't write either. `jpeg` is read as `jpg`.","$ref":"#/components/schemas/CompressOutputExtension"},{"type":"null"}]},"keep_metadata":{"type":"boolean","description":"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.","default":false},"width":{"type":["integer","null"],"description":"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.","minimum":1,"maximum":65535},"height":{"type":["integer","null"],"description":"Resize to this height in pixels, the same way as `width`. Up to 65535.","minimum":1,"maximum":65535},"scale":{"type":["integer","null"],"description":"Resize to this percentage of the original, 1 to 100. Cannot be combined with `width` or `height`.","minimum":1,"maximum":100}}}}}},"responses":{"202":{"description":"Queued. `Location` points at the new record.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"}},"required":["data"]},"example":{"data":{"id":"9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d","status":"queued","name":"IMG_4471.heic","original":{"name":"IMG_4471.heic","format":"heic","size":3402118,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d/download?type=original"},"optimized":null,"saved_bytes":null,"saved_percent":null,"settings":{"level":"ultra","keep_metadata":true,"width":null,"height":null,"scale":null},"scan_id":null,"share_url":null,"created_at":"2026-10-01T09:31:12+00:00","updated_at":"2026-10-01T09:31:12+00:00"}}}},"headers":{"Location":{"description":"The address to poll.","schema":{"type":"string","format":"uri"}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"422":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"},"examples":{"validation_failed":{"summary":"validation_failed","value":{"message":"The selected level is invalid. (and 1 more error)","code":"validation_failed","errors":{"level":["The selected level is invalid."],"width":["The width field prohibits scale from being present."]}}}}}}},"429":{"description":"`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 or page scans for the day are used up. `Retry-After` holds the seconds until the rolling 24-hour window opens again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}},"daily_limit_reached":{"summary":"daily_limit_reached","value":{"message":"You've used your 40 images for today. Come back in about 3 hours.","code":"daily_limit_reached"}}}}}},"503":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"start_failed":{"summary":"start_failed","value":{"message":"The file could not be stored or queued, usually a short hiccup at the storage. Nothing was counted. Send the same request again.","code":"start_failed"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST \"https://www.iminify.com/api/v1/images\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\" \\\n  -F \"file=@photo.jpg\" \\\n  -F \"level=smart\" \\\n  -F \"format=webp\" \\\n  -F \"width=1600\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nwith open(\"photo.jpg\", \"rb\") as file:\n    response = requests.post(\n        f\"{API}/images\",\n        headers=HEADERS,\n        data={\n            \"level\": \"smart\",\n            \"format\": \"webp\",\n            \"width\": \"1600\",\n        },\n        files={\"file\": file},\n    )\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->post('images', [\n    'multipart' => [\n        ['name' => 'file', 'contents' => fopen('photo.jpg', 'r'), 'filename' => 'photo.jpg'],\n        ['name' => 'level', 'contents' => 'smart'],\n        ['name' => 'format', 'contents' => 'webp'],\n        ['name' => 'width', 'contents' => '1600'],\n    ],\n]);\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"import { openAsBlob } from 'node:fs';\n\nconst form = new FormData();\nform.append('file', await openAsBlob('photo.jpg'), 'photo.jpg');\nform.append('level', 'smart');\nform.append('format', 'webp');\nform.append('width', '1600');\n\nconst response = await fetch('https://www.iminify.com/api/v1/images', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n  body: form,\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]}},"/images/{id}":{"get":{"operationId":"getImage","description":"One image, with its status. This is the call to poll while an image is compressing; once a second or two apart is plenty.","summary":"Get an image","tags":["Images"],"parameters":[{"name":"id","in":"path","required":true,"description":"The image's id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"}},"required":["data"]},"example":{"data":{"id":"9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35","status":"completed","name":"team-offsite.webp","original":{"name":"team-offsite.jpg","format":"jpg","size":2841205,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download?type=original"},"optimized":{"name":"team-offsite.webp","format":"webp","size":212877,"width":1600,"height":1200,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download"},"saved_bytes":2628328,"saved_percent":92.51,"settings":{"level":"smart","keep_metadata":false,"width":1600,"height":null,"scale":null},"scan_id":null,"share_url":null,"created_at":"2026-10-01T09:30:00+00:00","updated_at":"2026-10-01T09:30:06+00:00"}}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl \"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.get(\n    f\"{API}/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->get('images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35');\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35', {\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]},"patch":{"operationId":"renameImage","description":"Changes the name the optimized copy downloads under. The original keeps the name it was uploaded with. The extension is always the delivered format's, so a typed one (`hero.webp`) is dropped, and characters that don't belong in a file name become a hyphen. Only a finished image can be renamed.","summary":"Rename an image","tags":["Images"],"parameters":[{"name":"id","in":"path","required":true,"description":"The image's id.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameImageRequest"}}}},"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"}},"required":["data"]},"example":{"data":{"id":"9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35","status":"completed","name":"team-offsite.webp","original":{"name":"team-offsite.jpg","format":"jpg","size":2841205,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download?type=original"},"optimized":{"name":"team-offsite.webp","format":"webp","size":212877,"width":1600,"height":1200,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download"},"saved_bytes":2628328,"saved_percent":92.51,"settings":{"level":"smart","keep_metadata":false,"width":1600,"height":null,"scale":null},"scan_id":null,"share_url":null,"created_at":"2026-10-01T09:30:00+00:00","updated_at":"2026-10-01T09:30:06+00:00"}}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"409":{"description":"`image_not_finished`: The call needs an optimized copy (to download, rename or zip it) and the image has not finished. In a batch call, none of the images named had finished.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"image_not_finished":{"summary":"image_not_finished","value":{"message":"Only an image that has finished optimizing can be downloaded.","code":"image_not_finished"}}}}}},"422":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"},"examples":{"validation_failed":{"summary":"validation_failed","value":{"message":"The selected level is invalid. (and 1 more error)","code":"validation_failed","errors":{"level":["The selected level is invalid."],"width":["The width field prohibits scale from being present."]}}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X PATCH \"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\":\"team-offsite\"}'"},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.patch(\n    f\"{API}/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35\",\n    headers=HEADERS,\n    json={\n        \"name\": \"team-offsite\",\n    },\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->patch('images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35', [\n    'json' => [\n        'name' => 'team-offsite',\n    ],\n]);\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35', {\n  method: 'PATCH',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    name: 'team-offsite',\n  }),\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]},"delete":{"operationId":"deleteImage","description":"Deletes the image and both of its files from storage for good. There is no trash and no undo. An image that is still queued or compressing is refused; cancel it while it is queued, or wait for it to finish.","summary":"Delete an image","tags":["Images"],"parameters":[{"name":"id","in":"path","required":true,"description":"The image's id.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The body is empty."},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"409":{"description":"`image_in_progress`: The image is still queued or being compressed. Wait for it to finish, or cancel it while it is still queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"image_in_progress":{"summary":"image_in_progress","value":{"message":"The compression is still running and cannot be deleted yet.","code":"image_in_progress"}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}},"503":{"description":"`delete_failed`: The files could not be removed from storage just now, so nothing was deleted. Send the same request again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"delete_failed":{"summary":"delete_failed","value":{"message":"The files could not be removed from storage just now, so nothing was deleted. Send the same request again.","code":"delete_failed"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X DELETE \"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.delete(\n    f\"{API}/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nprint(response.status_code)  # 204, nothing in the body"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->delete('images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35');\n\necho $response->getStatusCode(), PHP_EOL; // 204, nothing in the body"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35', {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(response.status); // 204, nothing in the body"}]}},"/images/{id}/download":{"get":{"operationId":"downloadImage","description":"The optimized copy, or with `type=original` the file exactly as it was uploaded. The answer is the file itself, with its type in `Content-Type` and its name in `Content-Disposition`. The original is there from the moment the image is queued; the optimized copy once it has finished.","summary":"Download an image","tags":["Images"],"parameters":[{"name":"id","in":"path","required":true,"description":"The image's id.","schema":{"type":"string","format":"uuid"}},{"name":"type","in":"query","description":"Which file: the optimized copy, or the original as it was uploaded.","schema":{"type":"string","enum":["optimized","original"],"default":"optimized"}}],"responses":{"200":{"description":"The file.","content":{"image/*":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"409":{"description":"`image_not_finished`: The call needs an optimized copy (to download, rename or zip it) and the image has not finished. In a batch call, none of the images named had finished.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"image_not_finished":{"summary":"image_not_finished","value":{"message":"Only an image that has finished optimizing can be downloaded.","code":"image_not_finished"}}}}}},"422":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"},"examples":{"validation_failed":{"summary":"validation_failed","value":{"message":"The selected level is invalid. (and 1 more error)","code":"validation_failed","errors":{"level":["The selected level is invalid."],"width":["The width field prohibits scale from being present."]}}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl --fail-with-body -o team-offsite.webp \"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.get(\n    f\"{API}/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nwith open(\"team-offsite.webp\", \"wb\") as out:\n    out.write(response.content)"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->get('images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download', [\n    'sink' => 'team-offsite.webp',\n]);\n\necho 'Saved team-offsite.webp', PHP_EOL;"},{"lang":"javascript","label":"JavaScript","source":"import { writeFile } from 'node:fs/promises';\n\nconst response = await fetch('https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download', {\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nawait writeFile('team-offsite.webp', Buffer.from(await response.arrayBuffer()));"}]}},"/images/{id}/recompress":{"post":{"operationId":"recompressImage","description":"Runs the stored original through again with new settings and answers with a new image; the one you started from stays as it is. Nothing is uploaded again, but it counts as a compression like an upload does. It is how you try `ultra` after `smart`, or AVIF after WebP. Any image that isn't still running can go again, a failed or cancelled one included. A resize that would take the image past 64 megapixels is refused with the message under `errors.image`.","summary":"Compress an image again","tags":["Images"],"parameters":[{"name":"id","in":"path","required":true,"description":"The image's id.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecompressImageRequest"}}}},"responses":{"202":{"description":"Queued. `Location` points at the new record.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"}},"required":["data"]},"example":{"data":{"id":"9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d","status":"queued","name":"IMG_4471.heic","original":{"name":"IMG_4471.heic","format":"heic","size":3402118,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d/download?type=original"},"optimized":null,"saved_bytes":null,"saved_percent":null,"settings":{"level":"ultra","keep_metadata":true,"width":null,"height":null,"scale":null},"scan_id":null,"share_url":null,"created_at":"2026-10-01T09:31:12+00:00","updated_at":"2026-10-01T09:31:12+00:00"}}}},"headers":{"Location":{"description":"The address to poll.","schema":{"type":"string","format":"uri"}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"409":{"description":"`image_in_progress`: The image is still queued or being compressed. Wait for it to finish, or cancel it while it is still queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"image_in_progress":{"summary":"image_in_progress","value":{"message":"The compression is still running and cannot be deleted yet.","code":"image_in_progress"}}}}}},"422":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"},"examples":{"validation_failed":{"summary":"validation_failed","value":{"message":"The selected level is invalid. (and 1 more error)","code":"validation_failed","errors":{"level":["The selected level is invalid."],"width":["The width field prohibits scale from being present."]}}}}}}},"429":{"description":"`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 or page scans for the day are used up. `Retry-After` holds the seconds until the rolling 24-hour window opens again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}},"daily_limit_reached":{"summary":"daily_limit_reached","value":{"message":"You've used your 40 images for today. Come back in about 3 hours.","code":"daily_limit_reached"}}}}}},"503":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"start_failed":{"summary":"start_failed","value":{"message":"The file could not be stored or queued, usually a short hiccup at the storage. Nothing was counted. Send the same request again.","code":"start_failed"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST \"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/recompress\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"level\":\"ultra\",\"format\":\"avif\"}'"},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.post(\n    f\"{API}/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/recompress\",\n    headers=HEADERS,\n    json={\n        \"level\": \"ultra\",\n        \"format\": \"avif\",\n    },\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->post('images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/recompress', [\n    'json' => [\n        'level' => 'ultra',\n        'format' => 'avif',\n    ],\n]);\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/recompress', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    level: 'ultra',\n    format: 'avif',\n  }),\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]}},"/images/{id}/retry":{"post":{"operationId":"retryImage","description":"Queues a failed or cancelled image again with the settings it had. It counts as a compression.","summary":"Retry an image","tags":["Images"],"parameters":[{"name":"id","in":"path","required":true,"description":"The image's id.","schema":{"type":"string","format":"uuid"}}],"responses":{"202":{"description":"Queued. `Location` points at the new record.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"}},"required":["data"]},"example":{"data":{"id":"9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d","status":"queued","name":"IMG_4471.heic","original":{"name":"IMG_4471.heic","format":"heic","size":3402118,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d/download?type=original"},"optimized":null,"saved_bytes":null,"saved_percent":null,"settings":{"level":"ultra","keep_metadata":true,"width":null,"height":null,"scale":null},"scan_id":null,"share_url":null,"created_at":"2026-10-01T09:31:12+00:00","updated_at":"2026-10-01T09:31:12+00:00"}}}},"headers":{"Location":{"description":"The address to poll.","schema":{"type":"string","format":"uri"}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"409":{"description":"`image_not_retryable`: Only a failed or cancelled image can be retried. To run a finished one again with other settings, recompress it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"image_not_retryable":{"summary":"image_not_retryable","value":{"message":"Only a failed or cancelled image can be retried. To run a finished one again with other settings, recompress it.","code":"image_not_retryable"}}}}}},"429":{"description":"`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 or page scans for the day are used up. `Retry-After` holds the seconds until the rolling 24-hour window opens again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}},"daily_limit_reached":{"summary":"daily_limit_reached","value":{"message":"You've used your 40 images for today. Come back in about 3 hours.","code":"daily_limit_reached"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST \"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/retry\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.post(\n    f\"{API}/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/retry\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->post('images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/retry');\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/retry', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]}},"/images/{id}/cancel":{"post":{"operationId":"cancelImage","description":"Calls off an image still waiting in the queue. Once a worker has picked it up it runs to the end.","summary":"Cancel an image","tags":["Images"],"parameters":[{"name":"id","in":"path","required":true,"description":"The image's id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"}},"required":["data"]},"example":{"data":{"id":"9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d","status":"cancelled","name":"IMG_4471.heic","original":{"name":"IMG_4471.heic","format":"heic","size":3402118,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d/download?type=original"},"optimized":null,"saved_bytes":null,"saved_percent":null,"settings":{"level":"ultra","keep_metadata":true,"width":null,"height":null,"scale":null},"scan_id":null,"share_url":null,"created_at":"2026-10-01T09:31:12+00:00","updated_at":"2026-10-01T09:31:40+00:00"}}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"409":{"description":"`image_not_cancellable`: Only an image still waiting in the queue can be cancelled. This one has started, or already ended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"image_not_cancellable":{"summary":"image_not_cancellable","value":{"message":"Only an image still waiting in the queue can be cancelled. This one has started, or already ended.","code":"image_not_cancellable"}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST \"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/cancel\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.post(\n    f\"{API}/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/cancel\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->post('images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/cancel');\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/cancel', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]}},"/images/{id}/share":{"post":{"operationId":"shareImage","description":"Gives a finished image a public page at an address nobody can guess, returned as `share_url`. Anyone with the link can see the optimized copy, compare it with the original, download either one, and run the original through Iminify with their own settings. The page is kept out of search engines. Sharing an image that is already shared keeps its link.","summary":"Share an image","tags":["Images"],"parameters":[{"name":"id","in":"path","required":true,"description":"The image's id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Image"}},"required":["data"]},"example":{"data":{"id":"9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35","status":"completed","name":"team-offsite.webp","original":{"name":"team-offsite.jpg","format":"jpg","size":2841205,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download?type=original"},"optimized":{"name":"team-offsite.webp","format":"webp","size":212877,"width":1600,"height":1200,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download"},"saved_bytes":2628328,"saved_percent":92.51,"settings":{"level":"smart","keep_metadata":false,"width":1600,"height":null,"scale":null},"scan_id":null,"share_url":"https://www.iminify.com/s/k3Xw9QmT2vLp8RzN4bYc6HdJ","created_at":"2026-10-01T09:30:00+00:00","updated_at":"2026-10-01T09:30:06+00:00"}}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"409":{"description":"`image_not_shareable`: Only a finished image whose files a browser can show can be shared. A HEIC or TIFF handed back unconverted cannot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"image_not_shareable":{"summary":"image_not_shareable","value":{"message":"Only a finished image whose files a browser can show can be shared. A HEIC or TIFF handed back unconverted cannot.","code":"image_not_shareable"}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST \"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/share\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.post(\n    f\"{API}/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/share\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->post('images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/share');\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/share', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]},"delete":{"operationId":"unshareImage","description":"Switches the public link off. The page and both of its files answer 404 from the next request on. Sharing the image again later gives it a new link.","summary":"Stop sharing an image","tags":["Images"],"parameters":[{"name":"id","in":"path","required":true,"description":"The image's id.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The body is empty."},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X DELETE \"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/share\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.delete(\n    f\"{API}/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/share\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nprint(response.status_code)  # 204, nothing in the body"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->delete('images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/share');\n\necho $response->getStatusCode(), PHP_EOL; // 204, nothing in the body"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/share', {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(response.status); // 204, nothing in the body"}]}},"/images/rename":{"post":{"operationId":"renameImages","description":"Gives every finished image in `ids` the same name followed by its place in upload order, oldest first: `trip-01`, `trip-02`. The number has at least two digits, more when the count needs them. A single image gets the name alone. Images that haven't finished are passed over, and if none has, the call is refused. It is all or nothing: when one of the names would be too long, none changes. Every id has to be one of your images; the ones that aren't are named in `errors`.","summary":"Rename several images","tags":["Images"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameImagesRequest"}}}},"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Image"}}},"required":["data"]},"example":{"data":[{"id":"9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35","status":"completed","name":"team-offsite-01.webp","original":{"name":"team-offsite.jpg","format":"jpg","size":2841205,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download?type=original"},"optimized":{"name":"team-offsite-01.webp","format":"webp","size":212877,"width":1600,"height":1200,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download"},"saved_bytes":2628328,"saved_percent":92.51,"settings":{"level":"smart","keep_metadata":false,"width":1600,"height":null,"scale":null},"scan_id":null,"share_url":null,"created_at":"2026-10-01T09:30:00+00:00","updated_at":"2026-10-01T09:30:06+00:00"},{"id":"9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d","status":"completed","name":"team-offsite-02.webp","original":{"name":"IMG_4471.jpg","format":"jpg","size":2841205,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d/download?type=original"},"optimized":{"name":"team-offsite-02.webp","format":"webp","size":212877,"width":1600,"height":1200,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d/download"},"saved_bytes":2628328,"saved_percent":92.51,"settings":{"level":"smart","keep_metadata":false,"width":1600,"height":null,"scale":null},"scan_id":null,"share_url":null,"created_at":"2026-10-01T09:30:00+00:00","updated_at":"2026-10-01T09:30:06+00:00"}]}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"409":{"description":"`image_not_finished`: The call needs an optimized copy (to download, rename or zip it) and the image has not finished. In a batch call, none of the images named had finished.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"image_not_finished":{"summary":"image_not_finished","value":{"message":"Only an image that has finished optimizing can be downloaded.","code":"image_not_finished"}}}}}},"422":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"},"examples":{"validation_failed":{"summary":"validation_failed","value":{"message":"The selected level is invalid. (and 1 more error)","code":"validation_failed","errors":{"level":["The selected level is invalid."],"width":["The width field prohibits scale from being present."]}}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST \"https://www.iminify.com/api/v1/images/rename\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"ids\":[\"9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35\",\"9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d\"],\"name\":\"team-offsite\"}'"},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.post(\n    f\"{API}/images/rename\",\n    headers=HEADERS,\n    json={\n        \"ids\": [\"9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35\", \"9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d\"],\n        \"name\": \"team-offsite\",\n    },\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->post('images/rename', [\n    'json' => [\n        'ids' => ['9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35', '9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d'],\n        'name' => 'team-offsite',\n    ],\n]);\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/images/rename', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    ids: ['9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35', '9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d'],\n    name: 'team-offsite',\n  }),\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]}},"/images/download":{"post":{"operationId":"downloadImages","description":"One zip holding the optimized copy of every finished image in `ids`, oldest first. Two images with the same name are kept apart as `name.webp` and `name (2).webp`. Images that haven't finished are left out, and if none has, the call is refused.","summary":"Download several images as a zip","tags":["Images"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchImagesRequest"}}}},"responses":{"200":{"description":"The zip.","content":{"application/zip":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"409":{"description":"`image_not_finished`: The call needs an optimized copy (to download, rename or zip it) and the image has not finished. In a batch call, none of the images named had finished.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"image_not_finished":{"summary":"image_not_finished","value":{"message":"Only an image that has finished optimizing can be downloaded.","code":"image_not_finished"}}}}}},"422":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"},"examples":{"validation_failed":{"summary":"validation_failed","value":{"message":"The selected level is invalid. (and 1 more error)","code":"validation_failed","errors":{"level":["The selected level is invalid."],"width":["The width field prohibits scale from being present."]}}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST --fail-with-body -o images.zip \"https://www.iminify.com/api/v1/images/download\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"ids\":[\"9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35\",\"9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d\"]}'"},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.post(\n    f\"{API}/images/download\",\n    headers=HEADERS,\n    json={\n        \"ids\": [\"9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35\", \"9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d\"],\n    },\n)\nresponse.raise_for_status()\n\nwith open(\"images.zip\", \"wb\") as out:\n    out.write(response.content)"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->post('images/download', [\n    'json' => [\n        'ids' => ['9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35', '9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d'],\n    ],\n    'sink' => 'images.zip',\n]);\n\necho 'Saved images.zip', PHP_EOL;"},{"lang":"javascript","label":"JavaScript","source":"import { writeFile } from 'node:fs/promises';\n\nconst response = await fetch('https://www.iminify.com/api/v1/images/download', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    ids: ['9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35', '9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d'],\n  }),\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nawait writeFile('images.zip', Buffer.from(await response.arrayBuffer()));"}]}},"/scans":{"get":{"operationId":"listScans","description":"Every page scan on your account, newest first, each with its counts and totals. The images themselves come with a single scan, or from the image list filtered by `scan`.","summary":"List page scans","tags":["Page scans"],"parameters":[{"name":"status","in":"query","description":"Only scans with this status.","schema":{"$ref":"#/components/schemas/ScanStatus"}},{"name":"per_page","in":"query","description":"Scans a page, 1 to 100.","schema":{"type":"integer","default":15,"minimum":1,"maximum":100}},{"name":"page","in":"query","description":"The page to read.","schema":{"type":"integer","default":1,"minimum":1}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Scan"}},"links":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"]}},"required":["first","last","prev","next"]},"meta":{"type":"object","properties":{"current_page":{"type":"integer","minimum":1},"from":{"type":["integer","null"],"minimum":1},"last_page":{"type":"integer","minimum":1},"links":{"type":"array","description":"Generated paginator links.","items":{"type":"object","properties":{"url":{"type":["string","null"]},"label":{"type":"string"},"active":{"type":"boolean"}},"required":["url","label","active"]}},"path":{"type":["string","null"],"description":"Base path for paginator generated URLs."},"per_page":{"type":"integer","description":"Number of items shown per page.","minimum":0},"to":{"type":["integer","null"],"description":"Number of the last item in the slice.","minimum":1},"total":{"type":"integer","description":"Total number of items being paginated.","minimum":0}},"required":["current_page","from","last_page","links","path","per_page","to","total"]}},"required":["data","links","meta"]},"example":{"data":[{"id":"9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7","url":"https://example.com/pricing","status":"completed","note":"Rendered in a headless browser. 14 image URLs found: 12 queued for compression, 1 duplicates of an image already queued, 1 in a format the compressor does not accept.","settings":{"level":"smart","format":"webp","keep_metadata":false,"width":1600,"height":null,"scale":null},"images_count":12,"images_in_progress":0,"images_finished":12,"original_size":18406331,"optimized_size":2114902,"saved_bytes":16291429,"saved_percent":88.51,"download_url":"https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/download","created_at":"2026-10-01T11:05:00+00:00","updated_at":"2026-10-01T11:05:41+00:00"}],"links":{"first":"https://www.iminify.com/api/v1/scans?page=1","last":"https://www.iminify.com/api/v1/scans?page=1","prev":null,"next":null},"meta":{"current_page":1,"from":1,"last_page":1,"links":[{"url":null,"label":"&laquo; Previous","page":null,"active":false},{"url":"https://www.iminify.com/api/v1/scans?page=1","label":"1","page":1,"active":true},{"url":null,"label":"Next &raquo;","page":null,"active":false}],"path":"https://www.iminify.com/api/v1/scans","per_page":15,"to":1,"total":1}}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"422":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"},"examples":{"validation_failed":{"summary":"validation_failed","value":{"message":"The selected level is invalid. (and 1 more error)","code":"validation_failed","errors":{"level":["The selected level is invalid."],"width":["The width field prohibits scale from being present."]}}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl \"https://www.iminify.com/api/v1/scans?status=completed\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.get(\n    f\"{API}/scans\",\n    headers=HEADERS,\n    params={\n        \"status\": \"completed\",\n    },\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->get('scans', [\n    'query' => [\n        'status' => 'completed',\n    ],\n]);\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/scans?status=completed', {\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]},"post":{"operationId":"createScan","description":"Opens the page in a browser on Iminify's servers, waits for it to load, scrolls to the bottom and collects every image it loaded, then compresses each one with the settings you send. It answers straight away with the status `queued`; a scan takes from a few seconds to a few minutes. Each scan counts one against your daily scans and your page scans a minute, and the images it finds don't count against your daily images. A scan stops at your plan's images per scan, skips SVG and AVIF files and anything over your plan's file size, and compresses an image that appears twice once.\n\nThe address can leave out `https://`. A page on a private network is refused. A page behind a login, or one that blocks automated browsers, usually comes back with no images, because the scanner sees what a signed-out visitor would.","summary":"Scan a page","tags":["Page scans"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreScanRequest"}}}},"responses":{"202":{"description":"Queued. `Location` points at the new record.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Scan"}},"required":["data"]},"example":{"data":{"id":"9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7","url":"https://example.com/pricing","status":"queued","note":null,"settings":{"level":"smart","format":"webp","keep_metadata":false,"width":1600,"height":null,"scale":null},"images_count":0,"images_in_progress":0,"images_finished":0,"original_size":0,"optimized_size":0,"saved_bytes":0,"saved_percent":null,"download_url":"https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/download","created_at":"2026-10-01T11:05:00+00:00","updated_at":"2026-10-01T11:05:00+00:00"}}}},"headers":{"Location":{"description":"The address to poll.","schema":{"type":"string","format":"uri"}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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. `scans_not_available`: Your plan does not include page scans.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}},"scans_not_available":{"summary":"scans_not_available","value":{"message":"Your plan does not include page scans.","code":"scans_not_available"}}}}}},"422":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"},"examples":{"validation_failed":{"summary":"validation_failed","value":{"message":"The selected level is invalid. (and 1 more error)","code":"validation_failed","errors":{"level":["The selected level is invalid."],"width":["The width field prohibits scale from being present."]}}}}}}},"429":{"description":"`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 or page scans for the day are used up. `Retry-After` holds the seconds until the rolling 24-hour window opens again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}},"daily_limit_reached":{"summary":"daily_limit_reached","value":{"message":"You've used your 40 images for today. Come back in about 3 hours.","code":"daily_limit_reached"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST \"https://www.iminify.com/api/v1/scans\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\":\"https://example.com/pricing\",\"level\":\"smart\",\"format\":\"webp\"}'"},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.post(\n    f\"{API}/scans\",\n    headers=HEADERS,\n    json={\n        \"url\": \"https://example.com/pricing\",\n        \"level\": \"smart\",\n        \"format\": \"webp\",\n    },\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->post('scans', [\n    'json' => [\n        'url' => 'https://example.com/pricing',\n        'level' => 'smart',\n        'format' => 'webp',\n    ],\n]);\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/scans', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    url: 'https://example.com/pricing',\n    level: 'smart',\n    format: 'webp',\n  }),\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]}},"/scans/{id}":{"get":{"operationId":"getScan","description":"One scan with every image it found, newest first. Poll this while a scan runs: it is done once its status is no longer `queued` or `scanning` and `images_in_progress` is 0.","summary":"Get a page scan","tags":["Page scans"],"parameters":[{"name":"id","in":"path","required":true,"description":"The scan's id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"allOf":[{"$ref":"#/components/schemas/Scan"},{"type":"object","required":["images"]}]}},"required":["data"]},"example":{"data":{"id":"9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7","url":"https://example.com/pricing","status":"completed","note":"Rendered in a headless browser. 14 image URLs found: 12 queued for compression, 1 duplicates of an image already queued, 1 in a format the compressor does not accept.","settings":{"level":"smart","format":"webp","keep_metadata":false,"width":1600,"height":null,"scale":null},"images_count":12,"images_in_progress":0,"images_finished":12,"original_size":18406331,"optimized_size":2114902,"saved_bytes":16291429,"saved_percent":88.51,"download_url":"https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/download","images":[{"id":"9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35","status":"completed","name":"team-offsite.webp","original":{"name":"team-offsite.jpg","format":"jpg","size":2841205,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download?type=original"},"optimized":{"name":"team-offsite.webp","format":"webp","size":212877,"width":1600,"height":1200,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b8e-6f0a-4c1e-9b7d-2a4e8f1c6b35/download"},"saved_bytes":2628328,"saved_percent":92.51,"settings":{"level":"smart","keep_metadata":false,"width":1600,"height":null,"scale":null},"scan_id":"9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7","share_url":null,"created_at":"2026-10-01T09:30:00+00:00","updated_at":"2026-10-01T09:30:06+00:00"},{"id":"9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d","status":"completed","name":"hero-banner.webp","original":{"name":"hero-banner.jpg","format":"jpg","size":2841205,"width":4032,"height":3024,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d/download?type=original"},"optimized":{"name":"hero-banner.webp","format":"webp","size":212877,"width":1600,"height":1200,"download_url":"https://www.iminify.com/api/v1/images/9d3c5b91-0b2e-4a7f-8c1d-5e6f7a8b9c0d/download"},"saved_bytes":2628328,"saved_percent":92.51,"settings":{"level":"smart","keep_metadata":false,"width":1600,"height":null,"scale":null},"scan_id":"9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7","share_url":null,"created_at":"2026-10-01T09:30:00+00:00","updated_at":"2026-10-01T09:30:06+00:00"}],"created_at":"2026-10-01T11:05:00+00:00","updated_at":"2026-10-01T11:05:41+00:00"}}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl \"https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.get(\n    f\"{API}/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->get('scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7');\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7', {\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]},"delete":{"operationId":"deleteScan","description":"Deletes the scan and every image it produced, with their files, for good. A scan that is still running, or has an image still compressing, is refused.","summary":"Delete a page scan","tags":["Page scans"],"parameters":[{"name":"id","in":"path","required":true,"description":"The scan's id.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Done. The body is empty."},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"409":{"description":"`scan_in_progress`: The scan is still running, or one of its images is still being compressed. Wait for everything to finish.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"scan_in_progress":{"summary":"scan_in_progress","value":{"message":"The scan is still running, or one of its images is still being compressed. Wait for everything to finish.","code":"scan_in_progress"}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}},"503":{"description":"`delete_failed`: The files could not be removed from storage just now, so nothing was deleted. Send the same request again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"delete_failed":{"summary":"delete_failed","value":{"message":"The files could not be removed from storage just now, so nothing was deleted. Send the same request again.","code":"delete_failed"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X DELETE \"https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.delete(\n    f\"{API}/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nprint(response.status_code)  # 204, nothing in the body"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->delete('scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7');\n\necho $response->getStatusCode(), PHP_EOL; // 204, nothing in the body"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7', {\n  method: 'DELETE',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(response.status); // 204, nothing in the body"}]}},"/scans/{id}/retry":{"post":{"operationId":"retryScan","description":"Queues a failed or cancelled scan again with the settings it had. It counts as a scan.","summary":"Retry a page scan","tags":["Page scans"],"parameters":[{"name":"id","in":"path","required":true,"description":"The scan's id.","schema":{"type":"string","format":"uuid"}}],"responses":{"202":{"description":"Queued. `Location` points at the new record.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Scan"}},"required":["data"]},"example":{"data":{"id":"9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7","url":"https://example.com/pricing","status":"queued","note":null,"settings":{"level":"smart","format":"webp","keep_metadata":false,"width":1600,"height":null,"scale":null},"images_count":0,"images_in_progress":0,"images_finished":0,"original_size":0,"optimized_size":0,"saved_bytes":0,"saved_percent":null,"download_url":"https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/download","created_at":"2026-10-01T11:05:00+00:00","updated_at":"2026-10-01T11:05:00+00:00"}}}},"headers":{"Location":{"description":"The address to poll.","schema":{"type":"string","format":"uri"}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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. `scans_not_available`: Your plan does not include page scans.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}},"scans_not_available":{"summary":"scans_not_available","value":{"message":"Your plan does not include page scans.","code":"scans_not_available"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"409":{"description":"`scan_not_retryable`: Only a failed or cancelled scan can be retried.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"scan_not_retryable":{"summary":"scan_not_retryable","value":{"message":"Only a failed or cancelled scan can be retried.","code":"scan_not_retryable"}}}}}},"429":{"description":"`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 or page scans for the day are used up. `Retry-After` holds the seconds until the rolling 24-hour window opens again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}},"daily_limit_reached":{"summary":"daily_limit_reached","value":{"message":"You've used your 40 images for today. Come back in about 3 hours.","code":"daily_limit_reached"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST \"https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/retry\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.post(\n    f\"{API}/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/retry\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->post('scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/retry');\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/retry', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]}},"/scans/{id}/cancel":{"post":{"operationId":"cancelScan","description":"Calls off a scan still waiting in the queue. Once the scanner has started, the scan runs to the end; its images can still be cancelled one by one.","summary":"Cancel a page scan","tags":["Page scans"],"parameters":[{"name":"id","in":"path","required":true,"description":"The scan's id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Scan"}},"required":["data"]},"example":{"data":{"id":"9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7","url":"https://example.com/pricing","status":"cancelled","note":null,"settings":{"level":"smart","format":"webp","keep_metadata":false,"width":1600,"height":null,"scale":null},"images_count":0,"images_in_progress":0,"images_finished":0,"original_size":0,"optimized_size":0,"saved_bytes":0,"saved_percent":null,"download_url":"https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/download","created_at":"2026-10-01T11:05:00+00:00","updated_at":"2026-10-01T11:05:20+00:00"}}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"409":{"description":"`scan_not_cancellable`: Only a scan still waiting in the queue can be cancelled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"scan_not_cancellable":{"summary":"scan_not_cancellable","value":{"message":"Only a scan still waiting in the queue can be cancelled.","code":"scan_not_cancellable"}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl -X POST \"https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/cancel\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.post(\n    f\"{API}/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/cancel\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->post('scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/cancel');\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/cancel', {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]}},"/scans/{id}/download":{"get":{"operationId":"downloadScan","description":"One zip with the optimized copy of every image of the scan that has finished, in the order the scanner found them. Images still compressing are left out, so wait for `images_in_progress` to reach 0 first.","summary":"Download a page scan as a zip","tags":["Page scans"],"parameters":[{"name":"id","in":"path","required":true,"description":"The scan's id.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The zip.","content":{"application/zip":{"schema":{"type":"string","format":"binary"}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"404":{"description":"`not_found`: No image or scan with that id on your account, or no such address. An id from another account answers the same way as one that never existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"not_found":{"summary":"not_found","value":{"message":"No image with this id.","code":"not_found"}}}}}},"409":{"description":"`image_not_finished`: The call needs an optimized copy (to download, rename or zip it) and the image has not finished. In a batch call, none of the images named had finished.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"image_not_finished":{"summary":"image_not_finished","value":{"message":"Only an image that has finished optimizing can be downloaded.","code":"image_not_finished"}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl --fail-with-body -o scan.zip \"https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/download\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.get(\n    f\"{API}/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/download\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nwith open(\"scan.zip\", \"wb\") as out:\n    out.write(response.content)"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->get('scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/download', [\n    'sink' => 'scan.zip',\n]);\n\necho 'Saved scan.zip', PHP_EOL;"},{"lang":"javascript","label":"JavaScript","source":"import { writeFile } from 'node:fs/promises';\n\nconst response = await fetch('https://www.iminify.com/api/v1/scans/9d3c4f12-7a8b-4c9d-a0e1-f2a3b4c5d6e7/download', {\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nawait writeFile('scan.zip', Buffer.from(await response.arrayBuffer()));"}]}},"/account":{"get":{"operationId":"getAccount","description":"Your plan, what it allows and how much of today's allowance is gone. The website and the API spend the same daily counts, so an image compressed on the site shows up in `usage` here too. A limit of `null` means no daily cap. The window is a rolling 24 hours that starts with your first image or scan, not midnight, so `resets_at` is `null` until something has been used. This is also the cheapest way to check that a key works.","summary":"Get your account","tags":["Account"],"responses":{"200":{"description":"OK.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Account"}},"required":["data"]},"example":{"data":{"name":"Ada Lovelace","email":"ada@example.com","plan":"free","plan_ends_at":null,"limits":{"images_per_day":40,"scans_per_day":3,"images_per_scan":20,"max_file_size":33554432,"max_megapixels":64,"compressions_per_minute":20,"scans_per_minute":1,"requests_per_minute":60,"max_batch":150},"usage":{"images":{"used":12,"remaining":28,"resets_at":"2026-10-02T09:30:00+00:00"},"scans":{"used":1,"remaining":2,"resets_at":"2026-10-02T11:05:00+00:00"}}}}}}},"401":{"description":"`unauthenticated`: No key was sent, or the key does not exist (it was mistyped or deleted). Send it as `Authorization: Bearer <key>`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"unauthenticated":{"summary":"unauthenticated","value":{"message":"Unauthenticated. Send your API key as a Bearer token in the Authorization header.","code":"unauthenticated"}}}}}},"403":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"email_not_verified":{"summary":"email_not_verified","value":{"message":"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.","code":"email_not_verified"}},"account_banned":{"summary":"account_banned","value":{"message":"The account behind the key has been banned. Its keys stop working with the ban.","code":"account_banned"}}}}}},"429":{"description":"`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.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate_limited":{"summary":"rate_limited","value":{"message":"You can start 20 compressions a minute. Try again in 42 seconds.","code":"rate_limited"}}}}}}},"x-codeSamples":[{"lang":"curl","label":"cURL","source":"curl \"https://www.iminify.com/api/v1/account\" \\\n  -H \"Authorization: Bearer $IMINIFY_API_KEY\" \\\n  -H \"Accept: application/json\""},{"lang":"python","label":"Python","source":"import os\n\nimport requests\n\nAPI = \"https://www.iminify.com/api/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {os.environ['IMINIFY_API_KEY']}\",\n    \"Accept\": \"application/json\",\n}\n\nresponse = requests.get(\n    f\"{API}/account\",\n    headers=HEADERS,\n)\nresponse.raise_for_status()\n\nprint(response.json())"},{"lang":"php","label":"PHP","source":"<?php\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\n\n$client = new Client([\n    'base_uri' => 'https://www.iminify.com/api/v1/',\n    'headers' => [\n        'Authorization' => 'Bearer ' . getenv('IMINIFY_API_KEY'),\n        'Accept' => 'application/json',\n    ],\n]);\n\n$response = $client->get('account');\n\nprint_r(json_decode((string) $response->getBody(), true));"},{"lang":"javascript","label":"JavaScript","source":"const response = await fetch('https://www.iminify.com/api/v1/account', {\n  headers: {\n    Authorization: `Bearer ${process.env.IMINIFY_API_KEY}`,\n    Accept: 'application/json',\n  },\n});\n\nif (!response.ok) {\n  throw new Error(`${response.status}: ${(await response.json()).message}`);\n}\n\nconsole.log(await response.json());"}]}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A personal access token from Settings > API Tokens on iminify.com."}},"schemas":{"Account":{"type":"object","properties":{"name":{"type":"string","description":"The account's name."},"email":{"type":"string","format":"email","description":"Its email address."},"plan":{"type":"string","description":"The plan the account is on.","enum":["free","pro"]},"plan_ends_at":{"type":["string","null"],"format":"date-time","description":"When a Pro plan ends, or `null` while it renews or on the free plan."},"limits":{"type":"object","description":"What the plan allows.","properties":{"images_per_day":{"type":["integer","null"],"description":"Images a rolling 24 hours, or `null` for no daily cap."},"scans_per_day":{"type":["integer","null"],"description":"Page scans a rolling 24 hours, or `null` for no daily cap."},"images_per_scan":{"type":"integer","description":"The most images one page scan compresses."},"max_file_size":{"type":"string","description":"The largest file you can upload or have fetched, in bytes."},"max_megapixels":{"type":"integer","description":"The most pixels an image, or the image a resize would produce, may have, in millions."},"compressions_per_minute":{"type":"integer","description":"Compressions you can queue in a minute: uploads, recompresses and retries together, from the API and the website combined."},"scans_per_minute":{"type":"integer","description":"Page scans you can start in a minute, new and retried together, from the API and the website combined."},"requests_per_minute":{"type":"integer","description":"Calls to the API in a minute, of every kind."},"max_batch":{"type":"integer","description":"The most ids one batch call takes."}},"required":["images_per_day","scans_per_day","images_per_scan","max_file_size","max_megapixels","compressions_per_minute","scans_per_minute","requests_per_minute","max_batch"]},"usage":{"type":"object","description":"How much of the day's allowance is used. The website and the API spend the same counts.","properties":{"images":{"type":"object","description":"Images compressed.","properties":{"used":{"type":"integer","description":"How many the current window has used."},"remaining":{"type":["integer","null"],"description":"How many are left, or `null` on a plan without a daily cap."},"resets_at":{"type":["string","null"],"format":"date-time","description":"When the window opens again, or `null` while nothing has been used. The window is a rolling 24 hours from the first use, not midnight."}},"required":["used","remaining","resets_at"]},"scans":{"type":"object","description":"Page scans run.","properties":{"used":{"type":"integer","description":"How many the current window has used."},"remaining":{"type":["integer","null"],"description":"How many are left, or `null` on a plan without a daily cap."},"resets_at":{"type":["string","null"],"format":"date-time","description":"When the window opens again, or `null` while nothing has been used. The window is a rolling 24 hours from the first use, not midnight."}},"required":["used","remaining","resets_at"]}},"required":["images","scans"]}},"required":["name","email","plan","plan_ends_at","limits","usage"],"title":"Account"},"BatchImagesRequest":{"type":"object","description":"The images, by id.","properties":{"ids":{"type":"array","description":"The images, by id. 1 to 150.","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":150,"uniqueItems":true}},"required":["ids"],"title":"BatchImagesRequest"},"CompressLevel":{"type":"string","enum":["none","lossless","ultra","smart"],"title":"CompressLevel"},"CompressOutputExtension":{"type":"string","enum":["auto","webp","avif","png","jpg"],"title":"CompressOutputExtension"},"CompressStatus":{"type":"string","enum":["queued","optimizing","completed","failed","already-optimized","cancelled"],"title":"CompressStatus"},"Image":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The image's id."},"status":{"description":"Where the image is. `queued`: waiting for a worker. `optimizing`: being compressed. `completed`: finished, the optimized copy is ready. `already-optimized`: finished, but nothing came out smaller than the upload, so the upload itself is handed back as the optimized copy. `failed`: it could not be compressed. `cancelled`: called off before it started.","$ref":"#/components/schemas/CompressStatus"},"name":{"type":"string","description":"The name the optimized copy downloads under: the uploaded name, or the one you gave it, with the delivered format's extension. While an `auto` conversion is still queued its format isn't chosen, so this is the uploaded name until it finishes."},"original":{"type":"object","description":"The file as it was uploaded.","properties":{"name":{"type":"string","description":"The file name it downloads under."},"format":{"type":"string","description":"The file's format, as its extension: `jpg`, `png`, `webp`, `avif`, `gif`, `heic`, `tiff` and so on."},"size":{"type":"integer","description":"Its size in bytes."},"width":{"type":"integer","description":"Its width in pixels, the way it displays: a phone photo stored on its side is measured upright."},"height":{"type":"integer","description":"Its height in pixels, the way it displays."},"download_url":{"type":"string","format":"uri","description":"Where to download it with your key."}},"required":["name","format","size","width","height","download_url"]},"optimized":{"type":["object","null"],"description":"The optimized copy, or `null` until the image has finished.","properties":{"name":{"type":"string","description":"The file name it downloads under."},"format":{"type":"string","description":"The file's format, as its extension: `jpg`, `png`, `webp`, `avif`, `gif`, `heic`, `tiff` and so on."},"size":{"type":"integer","description":"Its size in bytes."},"width":{"type":"integer","description":"Its width in pixels, the way it displays: a phone photo stored on its side is measured upright."},"height":{"type":"integer","description":"Its height in pixels, the way it displays."},"download_url":{"type":"string","format":"uri","description":"Where to download it with your key."}},"required":["name","format","size","width","height","download_url"]},"saved_bytes":{"type":["integer","null"],"description":"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":{"type":["number","null"],"description":"The same saving as a percentage of the original, to two decimal places. `null` until the image has finished."},"settings":{"type":"object","description":"The settings the image was compressed with. The format it was converted to is `optimized.format`.","properties":{"level":{"description":"The compression level.","$ref":"#/components/schemas/CompressLevel"},"keep_metadata":{"type":"boolean","description":"Whether the EXIF metadata was kept."},"width":{"type":["integer","null"],"description":"The width it was resized to, or `null`."},"height":{"type":["integer","null"],"description":"The height it was resized to, or `null`."},"scale":{"type":["integer","null"],"description":"The percentage it was scaled to, or `null`."}},"required":["level","keep_metadata","width","height","scale"]},"scan_id":{"type":["string","null"],"format":"uuid","description":"The page scan that found the image, or `null` for an upload."},"share_url":{"type":["string","null"],"format":"uri","description":"The public page while the image is shared, or `null`."},"created_at":{"type":"string","format":"date-time","description":"When the image was queued."},"updated_at":{"type":"string","format":"date-time","description":"When anything about it last changed, its status included."}},"required":["id","status","name","original","optimized","saved_bytes","saved_percent","settings","scan_id","share_url","created_at","updated_at"],"title":"Image"},"RecompressImageRequest":{"type":"object","description":"The settings to run the stored original through again with.","properties":{"level":{"description":"How hard to compress. `smart` finds the lowest quality that still looks like your upload, `ultra` goes further and softens fine texture a little, `lossless` changes no pixel, `none` only applies the format, the resize and the metadata choice. See [Compression settings](/docs/compression-settings).","default":"smart","$ref":"#/components/schemas/CompressLevel"},"format":{"anyOf":[{"description":"Convert to this format. `auto` encodes the image in every format that can hold it and keeps the smallest. Leave it out to keep the upload's own format; a HEIC or TIFF always comes back in another one, because Iminify doesn't write either. `jpeg` is read as `jpg`.","$ref":"#/components/schemas/CompressOutputExtension"},{"type":"null"}]},"keep_metadata":{"type":"boolean","description":"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.","default":false},"width":{"type":["integer","null"],"description":"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.","minimum":1,"maximum":65535},"height":{"type":["integer","null"],"description":"Resize to this height in pixels, the same way as `width`. Up to 65535.","minimum":1,"maximum":65535},"scale":{"type":["integer","null"],"description":"Resize to this percentage of the original, 1 to 100. Cannot be combined with `width` or `height`.","minimum":1,"maximum":100}},"title":"RecompressImageRequest"},"RenameImageRequest":{"type":"object","description":"The new name.","properties":{"name":{"type":"string","description":"The new name, without an extension. With the extension it has to fit in 128 bytes.","examples":["team-offsite"],"maxLength":255}},"required":["name"],"title":"RenameImageRequest"},"RenameImagesRequest":{"type":"object","description":"The images, by id, and the one name they are numbered under.","properties":{"ids":{"type":"array","description":"The images, by id. 1 to 150.","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":150,"uniqueItems":true},"name":{"type":"string","description":"The name they share, without an extension.","examples":["team-offsite"],"maxLength":255}},"required":["ids","name"],"title":"RenameImagesRequest"},"Scan":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"The scan's id."},"url":{"type":"string","format":"uri","description":"The page that was scanned."},"status":{"description":"Where the scanner is. `queued`: waiting for the scanner. `scanning`: the page is open and its images are being collected. `completed`: images were found and queued. `no-image-found`: the page loaded but nothing on it could be compressed. `failed`: the page could not be scanned. `cancelled`: called off before it started. The images themselves keep compressing after `completed`; watch `images_in_progress`.","$ref":"#/components/schemas/ScanStatus"},"note":{"type":["string","null"],"description":"What the scanner wrote when it finished: how many images it found and what became of each, or why it failed. `null` until then."},"settings":{"type":"object","description":"The settings every image the scan found is compressed with.","properties":{"level":{"description":"The compression level.","$ref":"#/components/schemas/CompressLevel"},"format":{"anyOf":[{"description":"The format every image is converted to, or `null` to keep each one's own.","$ref":"#/components/schemas/CompressOutputExtension"},{"type":"null"}]},"keep_metadata":{"type":"boolean","description":"Whether EXIF metadata is kept."},"width":{"type":["integer","null"],"description":"The width every image is resized to, or `null`."},"height":{"type":["integer","null"],"description":"The height every image is resized to, or `null`."},"scale":{"type":["integer","null"],"description":"The percentage every image is scaled to, or `null`."}},"required":["level","format","keep_metadata","width","height","scale"]},"images_count":{"type":"integer","description":"How many images the scan queued."},"images_in_progress":{"type":"integer","description":"How many of them are still queued or being compressed. The scan is done once its status has ended and this is 0."},"images_finished":{"type":"integer","description":"How many of them have finished."},"original_size":{"type":"integer","description":"Bytes of the finished images before compression."},"optimized_size":{"type":"integer","description":"Bytes of the same images after compression."},"saved_bytes":{"type":"string","description":"The difference between the two."},"saved_percent":{"type":["number","null"],"description":"The same saving as a percentage, or `null` while no image has finished."},"download_url":{"type":"string","format":"uri","description":"Where to download every finished image as one zip."},"images":{"type":"array","description":"The scan's images, newest first. Only on a single scan, not in a list.","items":{"$ref":"#/components/schemas/Image"}},"created_at":{"type":"string","format":"date-time","description":"When the scan was queued."},"updated_at":{"type":"string","format":"date-time","description":"When it last changed."}},"required":["id","url","status","note","settings","images_count","images_in_progress","images_finished","original_size","optimized_size","saved_bytes","saved_percent","download_url","created_at","updated_at"],"title":"Scan"},"ScanStatus":{"type":"string","enum":["queued","scanning","completed","failed","no-image-found","cancelled"],"title":"ScanStatus"},"StoreImageRequest":{"type":"object","description":"The image, as a file or as the address to fetch it from, and the settings to compress it with.","properties":{"file":{"type":"string","format":"binary","contentMediaType":"application/octet-stream","description":"The image. Send either this or `url`."},"url":{"type":"string","format":"uri","description":"The public address of the image to fetch. Send either this or `file`.","maxLength":2048},"level":{"description":"How hard to compress. `smart` finds the lowest quality that still looks like your upload, `ultra` goes further and softens fine texture a little, `lossless` changes no pixel, `none` only applies the format, the resize and the metadata choice. See [Compression settings](/docs/compression-settings).","default":"smart","$ref":"#/components/schemas/CompressLevel"},"format":{"anyOf":[{"description":"Convert to this format. `auto` encodes the image in every format that can hold it and keeps the smallest. Leave it out to keep the upload's own format; a HEIC or TIFF always comes back in another one, because Iminify doesn't write either. `jpeg` is read as `jpg`.","$ref":"#/components/schemas/CompressOutputExtension"},{"type":"null"}]},"keep_metadata":{"type":"boolean","description":"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.","default":false},"width":{"type":["integer","null"],"description":"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.","minimum":1,"maximum":65535},"height":{"type":["integer","null"],"description":"Resize to this height in pixels, the same way as `width`. Up to 65535.","minimum":1,"maximum":65535},"scale":{"type":["integer","null"],"description":"Resize to this percentage of the original, 1 to 100. Cannot be combined with `width` or `height`.","minimum":1,"maximum":100}},"title":"StoreImageRequest"},"StoreScanRequest":{"type":"object","description":"The page to scan and the settings every image found on it is compressed with.","properties":{"url":{"type":"string","format":"uri","description":"The page to scan. `https://` can be left out.","maxLength":2048},"level":{"description":"How hard to compress. `smart` finds the lowest quality that still looks like your upload, `ultra` goes further and softens fine texture a little, `lossless` changes no pixel, `none` only applies the format, the resize and the metadata choice. See [Compression settings](/docs/compression-settings).","default":"smart","$ref":"#/components/schemas/CompressLevel"},"format":{"anyOf":[{"description":"Convert to this format. `auto` encodes the image in every format that can hold it and keeps the smallest. Leave it out to keep the upload's own format; a HEIC or TIFF always comes back in another one, because Iminify doesn't write either. `jpeg` is read as `jpg`.","$ref":"#/components/schemas/CompressOutputExtension"},{"type":"null"}]},"keep_metadata":{"type":"boolean","description":"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.","default":false},"width":{"type":["integer","null"],"description":"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.","minimum":1,"maximum":65535},"height":{"type":["integer","null"],"description":"Resize to this height in pixels, the same way as `width`. Up to 65535.","minimum":1,"maximum":65535},"scale":{"type":["integer","null"],"description":"Resize to this percentage of the original, 1 to 100. Cannot be combined with `width` or `height`.","minimum":1,"maximum":100}},"required":["url"],"title":"StoreScanRequest"},"Error":{"type":"object","description":"An error.","properties":{"message":{"type":"string","description":"What went wrong, in a sentence you can show a person."},"code":{"type":"string","description":"What went wrong, as a code a program can branch on. Every code is on the errors page.","enum":["unauthenticated","email_not_verified","account_banned","scans_not_available","not_found","method_not_allowed","image_in_progress","image_not_cancellable","image_not_retryable","image_not_finished","image_not_shareable","scan_in_progress","scan_not_cancellable","scan_not_retryable","payload_too_large","validation_failed","rate_limited","daily_limit_reached","server_error","start_failed","delete_failed","http_error"]}},"required":["message","code"]},"ValidationError":{"type":"object","description":"A request that failed validation.","properties":{"message":{"type":"string","description":"What went wrong, in a sentence you can show a person."},"code":{"type":"string","description":"What went wrong, as a code a program can branch on. Every code is on the errors page.","enum":["unauthenticated","email_not_verified","account_banned","scans_not_available","not_found","method_not_allowed","image_in_progress","image_not_cancellable","image_not_retryable","image_not_finished","image_not_shareable","scan_in_progress","scan_not_cancellable","scan_not_retryable","payload_too_large","validation_failed","rate_limited","daily_limit_reached","server_error","start_failed","delete_failed","http_error"]},"errors":{"type":"object","description":"Each field that failed, with its messages.","additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["message","code","errors"]}}}}