Быстрый старт
- Войдите по email и скопируйте API-ключ в личном кабинете.
- Выполните команду ниже со своим ключом и любым файлом PNG, JPEG или WebP.
- photo-min.png и есть сжатая копия. Это вся интеграция.
curl https://api.compresso.space/v1/compress \
--user api:YOUR_API_KEY \
--data-binary @photo.png \
--output photo-min.png \
--fail-with-bodyЕсли что-то пошло не так, curl завершится с ошибкой, а в photo-min.png окажется короткое JSON-сообщение: что случилось и как это исправить.
В Windows PowerShell пишите curl.exe вместо curl: там curl является псевдонимом другой команды.
Авторизация
Каждый запрос требует API-ключ. Передайте его через HTTP Basic auth, с любым именем пользователя и ключом в качестве пароля (curl --user api:ВАШ_КЛЮЧ), или в заголовке Authorization: Bearer. Оба способа работают везде.
Запросы принимаются только по HTTPS. Обычный HTTP отклоняется с ошибкой https_required, без перенаправления. Если ключ хоть раз ушёл по HTTP, отзовите его в кабинете и создайте новый.
Храните ключи на сервере. API отклоняет запросы со страниц в браузере (browser_not_supported), поэтому ключ не может попасть к вашим посетителям. У аккаунта может быть до 10 активных ключей, любой можно отозвать в любой момент.
curl https://api.compresso.space/v1/usage --user api:YOUR_API_KEYСжатие изображений
Отправьте изображение методом POST на /v1/compress. Тело запроса: сами байты файла, либо форма multipart/form-data с изображением в поле file. Формат определяется по содержимому файла, поэтому Content-Type при отправке байтов не важен.
Успешный ответ и есть сжатое изображение: статус 200 и тот же формат, что вы отправили. Сохраните тело ответа как двоичный файл. Отдельного шага скачивания нет.
# raw bytes
curl https://api.compresso.space/v1/compress \
--user api:YOUR_API_KEY \
--data-binary @photo.png \
--output photo-min.png \
--fail-with-body
# or as a form upload (field "file")
curl https://api.compresso.space/v1/compress \
--user api:YOUR_API_KEY \
--form file=@photo.png \
--output photo-min.png \
--fail-with-bodyЗаголовки ответа
| Content-Type | image/png, image/jpeg или image/webp, как у исходного файла. |
|---|---|
| Original-Size | Размер загруженного файла в байтах. |
| Compressed-Size | Размер возвращённого изображения в байтах. |
| Compression-Count | Сколько сжатий аккаунт использовал за сегодня (UTC), включая это. |
| Compression-Limit | Ваш суточный лимит. |
| Compression-Reset | Когда счётчик обнулится: ближайшие 00:00 UTC, например 2026-09-19T00:00:00Z. |
| Request-Id | Укажите его, если пишете нам о конкретном запросе. |
Проверка расхода
GET /v1/usage возвращает расход аккаунта, ничего не сжимая. Так удобно проверить, что ключ работает. Этот запрос не расходует лимит.
curl https://api.compresso.space/v1/usage --user api:YOUR_API_KEY{
"ok": true,
"plan": "free",
"compression_count": 3,
"compression_limit": 100,
"compression_reset": "2026-09-19T00:00:00Z",
"key": "csk_…a1b2"
}Сжатие папки
Отправляйте изображения по одному: у каждого аккаунта одновременно сжимается одно изображение и ещё одно ждёт, поэтому параллельные загрузки получат rate_limited. Если API отвечает 429 или 503 с заголовком Retry-After, подождите указанное число секунд и повторите. Без Retry-After повторять не нужно.
// Compress every PNG/JPEG/WebP in ./images into ./images-min, one at a time.
import { mkdir, readdir, readFile, writeFile } from "node:fs/promises"
import path from "node:path"
const KEY = process.env.COMPRESSO_API_KEY
const IN = "images"
const OUT = "images-min"
await mkdir(OUT, { recursive: true })
for (const name of await readdir(IN)) {
if (!/\.(png|jpe?g|webp)$/i.test(name)) continue
const body = await readFile(path.join(IN, name))
for (;;) {
const res = await fetch("https://api.compresso.space/v1/compress", {
method: "POST",
headers: { Authorization: `Bearer ${KEY}` },
body,
})
if (res.ok) {
await writeFile(path.join(OUT, name), Buffer.from(await res.arrayBuffer()))
console.log(name, res.headers.get("Original-Size"), "->", res.headers.get("Compressed-Size"))
break
}
const err = await res.json()
// Retry only when the API says so, and only for short waits.
const wait = Number(res.headers.get("Retry-After"))
if (wait > 0 && wait <= 60) {
await new Promise((r) => setTimeout(r, wait * 1000))
continue
}
console.error(name, err.error, err.message)
if (res.status === 429 || res.status === 503) process.exit(1) // limit or long outage
break
}
}Что происходит с изображением
- PNG, JPEG и WebP сжимаются тем же движком и с той же попиксельной проверкой качества, что на compresso.space. Результат визуально неотличим от оригинала.
- Формат и размеры в пикселях не меняются. Ничего не уменьшается и не конвертируется.
- В сжатых изображениях нет метаданных (EXIF, GPS, данных камеры). Фото сначала поворачиваются по EXIF-ориентации, поэтому остаются в правильном положении.
- Если изображение нельзя уменьшить без видимой разницы, вы получите исходный файл без изменений, вместе с метаданными, со статусом 200. Такой запрос тоже считается сжатием.
- Изображения обрабатываются в памяти, не записываются на диск и не хранятся. Само изображение никогда не попадает в логи: для статистики мы сохраняем только размеры и формат.
Частые ошибки
- curl -d портит двоичные файлы. Всегда используйте --data-binary @файл или --form file=@файл.
- Не отправляйте base64, data:-ссылку или JSON со ссылкой на картинку. Отправляйте байты файла.
- В axios нужен responseType: "arraybuffer", иначе изображение прочитается как текст и испортится.
- В Python requests сохраняйте res.content (байты), а не res.text.
- Вызывайте API с сервера или из скриптов сборки, а не из JavaScript на странице: браузеры отклоняются намеренно.
Лимиты
| Бесплатные сжатия | 100 на аккаунт в сутки, сброс в 00:00 UTC |
|---|---|
| Размер файла | до 16 МБ на изображение |
| Разрешение | до 16 мегапикселей |
| Параллельные запросы | 1 в работе и 1 в ожидании на аккаунт |
| Частота запросов | 60 запросов в минуту на аккаунт |
| На сеть | 500 сжатий в сутки с одного IP-адреса по всем ключам |
| API-ключи | до 10 активных ключей на аккаунт |
| Таймаут | ставьте таймаут клиента не меньше 120 секунд |
Ошибки
Любая ошибка приходит в JSON: {"ok": false, "error": "код", "message": "...", "docs": "...", "request_id": "..."}. В message объяснено, что случилось и что делать, поэтому выводите его.
Правило повторов: если 429 или 503 пришли с заголовком Retry-After, подождите указанное число секунд и повторите. Без Retry-After автоматически не повторяйте.
| Код | HTTP | Что это значит | Повторять? |
|---|---|---|---|
| https_required | 400 | Запрос пришёл по обычному HTTP. Используйте https://api.compresso.space/v1. | Нет |
| input_missing | 400 | Тело запроса пустое. Отправьте байты изображения. | Нет |
| invalid_multipart | 400 | Форма собрана неправильно. Пусть её соберёт ваш HTTP-клиент, или отправьте байты напрямую. | Нет |
| invalid_image | 400 | Файл обрезан или повреждён. В curl используйте --data-binary, а не -d. | Нет |
| unauthorized | 401 | Нет ключа, ключ неполный или с ошибкой, неизвестен или отозван. В message сказано, что именно. | Нет |
| browser_not_supported | 403 | Запрос пришёл со страницы в браузере. Вызывайте API с сервера. | Нет |
| not_found | 404 | Такого адреса нет. В API есть POST /v1/compress, GET /v1/usage и GET /v1/openapi.json. | Нет |
| method_not_allowed | 405 | Неверный HTTP-метод для этого адреса. Правильный указан в заголовке Allow. | Нет |
| file_too_large | 413 | Файл больше 16 МБ. | Нет |
| image_too_large | 413 | Изображение больше 16 мегапикселей. Молча оно не уменьшается. | Нет |
| unsupported_format | 415 | Это не PNG, JPEG или WebP. В message указан определённый формат. | Нет |
| animated_unsupported | 415 | Анимированные изображения не поддерживаются. | Нет |
| daily_limit_exceeded | 429 | Суточный лимит исчерпан. Он обнулится в 00:00 UTC, см. Compression-Reset. | Нет |
| rate_limited | 429 | Слишком много запросов одновременно или за минуту. Подождите Retry-After секунд. | Да, после Retry-After |
| server_busy | 503 | Сервер занят другой работой. Подождите Retry-After секунд. | Да, после Retry-After |
| daily_capacity_reached | 503 | Общий суточный объём API исчерпан. Он обнулится в 00:00 UTC. | Да, после Retry-After |
| api_disabled | 503 | API временно выключен на обслуживание. Попробуйте позже. | Позже |
| compress_failed | 500 | Неожиданная ошибка на нашей стороне. Повторите один раз, затем напишите нам с request_id. | Один раз |
OpenAPI
Полное машиночитаемое описание API лежит по адресу https://api.compresso.space/v1/openapi.json (OpenAPI 3.1, ключ не нужен). Импортируйте его в Postman или Insomnia или сгенерируйте по нему клиент.
Изменения
- Вышел API v1: /v1/compress, /v1/usage, 100 бесплатных сжатий в сутки.