К содержимому
PostAPI

API для интеграций

Всё, что вы делаете на сайте, можно делать из своей CRM, магазина или скрипта: хранить шаблоны и адреса, строить конверт одним запросом, отправлять в печать пакеты до 5 000 адресов и получать событие, когда файл готов.

Лимиты

120 / мин
запросов на ключ — обычные методы
30 / мин
рендер, создание заданий, печать
5 000
конвертов в одном задании
7 дн.
хранится готовый файл, затем удаляется

Ключей — до 10, подписок на webhook — до 10 на аккаунт. API бесплатный; текущие условия — на странице «Тарифы».

Доступ

Запросы идут на https://dev.postapi.ru/api/v1 с ключом в заголовке:

Authorization: Bearer ваш-ключ

Ключ создаётся в кабинете, раздел «API и webhooks». Он показывается один раз: хранится только отпечаток, восстановить значение нельзя. Потерян или утёк — отзовите его и создайте новый. Удобно завести отдельный ключ на каждую интеграцию, тогда отзыв одного не ломает остальные.

Данные изолированы: по ключу видны только ваши шаблоны, адреса и задания. Чужой объект отвечает так же, как несуществующий, — 404 not_found.

Все размеры в API — в миллиметрах, начало координат — левый верхний угол лицевой стороны конверта. Даты — в формате ISO 8601.

Ошибки

Успешные ответы — JSON {"data": …} (в списках ещё meta с постраничной разбивкой). Ошибка у всех методов одной формы:

{
    "error": {
        "code": "invalid_data",
        "message": "Данные конверта содержат ошибки.",
        "details": { "recipient.postal_code": "Индекс — ровно 6 цифр." }
    }
}

details — поле запроса и что в нём не так; у ошибок без подробностей это пустой объект.

КодСтатусКогда
unauthenticated401Нет заголовка, ключ не найден или отозван
account_blocked403Аккаунт заблокирован
forbidden403Нет доступа к объекту
read_only403Попытка изменить или удалить системный шаблон
not_found404Объект не найден или принадлежит другому аккаунту
file_unavailable409Файл задания ещё не готов или удалён по сроку хранения
validation_failed422Запрос не прошёл проверку: нет обязательного поля, неверный тип
invalid_template422Шаблон содержит ошибки: зона вне конверта, неизвестный формат и т. п.
invalid_data422Данные конверта, адреса, профиль или webhook не прошли проверку
text_overflow422Текст не помещается в зону даже минимальным кеглем
rate_limited429Превышен лимит запросов; заголовок Retry-After — через сколько секунд повторить
server_error500Внутренняя ошибка; подробности наружу не отдаются

Лимит — 120 запросов в минуту на ключ, а не на адрес. В каждом ответе есть X-RateLimit-Limit и X-RateLimit-Remaining.

Идемпотентность

Создание задания принимает заголовок Idempotency-Key — до 80 символов: латиница, цифры и - _ : .. Если сеть оборвалась и вы повторили запрос с тем же ключом, второе задание не появится: придёт первое с кодом 200 и заголовком Idempotent-Replayed: true. Хороший ключ — номер заказа или партии в вашей системе.

Форматы

GET /api/v1/formats

Список форматов конвертов

Нужен ключ. Заголовок Authorization: Bearer pa_…

Стандартные форматы с размерами лицевой стороны и идентификатором системного шаблона. Свой размер задаётся в шаблоне (format.code = CUSTOM, стороны от 70 до 500 мм).

Пример

curl -H "Authorization: Bearer $KEY" https://dev.postapi.ru/api/v1/formats

Ответ

{
    "data": [
        { "code": "DL", "name": "DL (Е65)", "width_mm": 220, "height_mm": 110, "orientation": "landscape", "system_template": "system-dl" },
        { "code": "C5", "name": "C5", "width_mm": 229, "height_mm": 162, "orientation": "landscape", "system_template": "system-c5" }
    ]
}

Шаблоны

Шаблон описывает конверт: формат, безопасное поле и зоны — прямоугольники в миллиметрах с типом содержимого. Системные шаблоны (system-c5 и т. д.) доступны всем и только для чтения: чтобы изменить, сделайте копию через copy_from.

Тип зоныЧто печатает
addressАдресный блок: имя, строки адреса и индекс. Данные берутся из стороны с тем же ключом (sender, recipient). Перенос по словам, автоподбор кегля
postal_codeИндекс кодовыми знаками по образцу ГОСТ Р 51506-99; поле source — чей индекс (по умолчанию получателя)
textПроизвольный текст: из data.fields[ключ зоны] или из поля text самой зоны
imageВаш логотип из профиля, вписанный в зону с сохранением пропорций
placeholderПунктирная рамка с подписью — место для марки или оттиска

GET /api/v1/templates

Список шаблонов

Нужен ключ. Заголовок Authorization: Bearer pa_…

Сначала системные (system: true), затем ваши.

Ответ

{
    "data": [
        {
            "id": "system-c5", "name": "C5 — стандартный", "system": true,
            "format": { "code": "C5", "width_mm": 229, "height_mm": 162, "orientation": "landscape" },
            "definition": { "print": { "safe_margin_mm": 5 }, "styles": { "font": "PT Sans", "size": 11 }, "zones": [ … ] },
            "warnings": [], "created_at": null, "updated_at": null
        }
    ]
}

POST /api/v1/templates

Создать шаблон

Нужен ключ. Заголовок Authorization: Bearer pa_…

Передайте copy_from или definition. Шаблон проверяется целиком, а все ошибки возвращаются сразу, с путём к полю: zones.2.x, format.code. Зона получателя (key: recipient, type: address) обязательна.

Поля запроса

ПолеТипЗачем
name string Название, до 120 символов
copy_from string id шаблона для копирования, например system-c5
definition object Шаблон целиком: format, print, styles, zones. Нужен, если нет copy_from

Пример

curl -X POST https://dev.postapi.ru/api/v1/templates \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"name":"Письма клиентам","copy_from":"system-c5"}'

Ответ

{ "data": { "id": "01m3z…", "name": "Письма клиентам", "system": false, "format": { … }, "definition": { … }, "warnings": [] } }

Поля зоны:

Поле зоныТипЗачем
key *stringКлюч: латиница в нижнем регистре, цифры, _ (до 32 символов), уникален в шаблоне
type *stringaddress, postal_code, text, image или placeholder
x, y, w, h *numberПоложение и размер в мм от левого верхнего угла; зона целиком внутри конверта
captionstringПодпись над блоком мелким серым («Кому», «От кого») или текст в рамке
size, min_sizenumberКегль и нижний предел автоуменьшения, пт (6–72)
align, font, colorstringleft/center/right, шрифт PT Sans, цвет #RRGGBB
bold_namebooleanДля address: имя полужирным
digit_height_mmnumberДля postal_code: высота цифры 6–20 мм

GET /api/v1/templates/{id}

Получить шаблон

Нужен ключ. Заголовок Authorization: Bearer pa_…

Возвращает один шаблон: системный или свой.

PUT /api/v1/templates/{id}

Изменить шаблон

Нужен ключ. Заголовок Authorization: Bearer pa_…

Только свои шаблоны. Системный отвечает 403 read_only.

Поля запроса

ПолеТипЗачем
name string Новое название
definition object Новый шаблон целиком (заменяет прежний)

DELETE /api/v1/templates/{id}

Удалить шаблон

Нужен ключ. Заголовок Authorization: Bearer pa_…

Ответ 204 без тела. Уже созданные задания не затрагиваются.

Рендер

POST /api/v1/render

Один конверт сразу: PDF, PNG или SVG

Нужен ключ. Заголовок Authorization: Bearer pa_…

Синхронно строит один конверт и возвращает файл, а не JSON. Страница PDF равна размеру конверта с допуском 0,1 мм (или листу, если в профиле mode: sheet). Число предупреждений — например, «кегль уменьшен» — в заголовке X-Envelope-Warnings. Если в профиле загружен логотип, он встаёт в зону image с ключом logo.

Данные конверта (data):

  • recipient * — name, address (строки через перевод строки), postal_code — ровно 6 цифр;
  • sender — то же, необязательно;
  • fields — тексты для зон типа text по их ключам.

Поля запроса

ПолеТипЗачем
data* object Данные конверта: sender, recipient, fields (см. ниже)
template string id шаблона. Вместо него можно указать format или definition
format string Код системного формата: DL, C6, C65, C5, C4, B4, E4
definition object Шаблон целиком, без сохранения
output string pdf (по умолчанию), png или svg
dpi integer Разрешение PNG, 50–300
strict boolean true (по умолчанию) — текст не помещается → ошибка; false — всё равно построить
profile object Профиль печати: mode (envelope|sheet), sheet (A4|A3), offset_x_mm, offset_y_mm, scale
printer_profile_id string id профиля принтера из кабинета вместо profile

Пример

curl -X POST https://dev.postapi.ru/api/v1/render \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"format":"C5","data":{"recipient":{"name":"Иванов Иван","address":"Невский пр-т, д. 28, кв. 5\nг. Санкт-Петербург","postal_code":"191186"}}}' \
  -o konvert.pdf

Ответ

200 OK
Content-Type: application/pdf        (или image/png, image/svg+xml)
X-Envelope-Warnings: 1               (если были предупреждения)

<тело файла>

422 text_overflow — адрес не помещается даже минимальным кеглем; в details — ключ зоны. 422 invalid_data — неверный индекс или нет получателя.

Задания

Пакетная печать идёт заданием: вы отдаёте список получателей, сервис формирует файл в очереди. Статусы: draft → queued → rendering → ready → sent_to_print → printed; при сбое — failed. О готовности можно узнать опросом GET /jobs/{id} или webhook job.ready.

POST /api/v1/jobs

Создать задание

Нужен ключ. Заголовок Authorization: Bearer pa_…

Ответ 202 и заголовок Location. Строки с ошибками не останавливают пакет: неверный индекс или слишком длинный адрес попадают в errors задания, остальные конверты формируются. Задание падает (failed), только если не получилось ни одного конверта. Передайте Idempotency-Key, чтобы повтор запроса не создал дубль.

Поля запроса

ПолеТипЗачем
template* string id шаблона
recipients array До 5 000 получателей: name, address, postal_code
file file CSV или XLSX вместо recipients (multipart/form-data); колонки «ФИО», «Адрес», «Индекс»
address_ids / label / all array / string / bool Адреса из вашей адресной книги вместо recipients
sender object Отправитель для всех конвертов; иначе — адрес с отметкой is_sender из книги
output string pdf — один файл, страница на конверт (по умолчанию); zip — файл на каждый конверт
printer_profile_id string Профиль принтера из кабинета; или profile — прямо в запросе
name string Название для списка заданий
notify boolean Прислать письмо о готовности (по умолчанию false)

Пример

curl -X POST https://dev.postapi.ru/api/v1/jobs \
  -H "Authorization: Bearer $KEY" -H "Idempotency-Key: rassylka-001" \
  -F template=system-dl -F output=pdf -F file=@adresa.xlsx

Ответ

{
    "data": {
        "id": "01m3z50beht8q837f74jszh1sf",
        "name": null,
        "status": "queued",
        "template": { "id": "system-dl", "name": "DL (Е65) — стандартный" },
        "output": "pdf",
        "counts": { "total": 120, "ok": 0, "failed": 0, "pages": 0 },
        "error": null,
        "file": { "available": false, "url": null, "size": null, "expires_at": null },
        "created_at": "2026-10-03T12:00:00+03:00"
    }
}

GET /api/v1/jobs/{id}

Статус задания

Нужен ключ. Заголовок Authorization: Bearer pa_…

Когда status станет ready, в file.url появится адрес файла. Конверты, которые не попали в файл, перечислены в errors:

Ответ

{
    "data": {
        "id": "01m3z50beht8q837f74jszh1sf", "status": "ready",
        "counts": { "total": 120, "ok": 119, "failed": 1, "pages": 119 },
        "file": { "available": true, "url": "…/api/v1/jobs/01m3z…/file", "size": 1843201, "expires_at": "2026-10-10T12:00:10+03:00" },
        "errors": [ { "position": 14, "recipient": "Петров П.", "message": "Индекс — ровно 6 цифр." } ]
    }
}

GET /api/v1/jobs

Список заданий

Нужен ключ. Заголовок Authorization: Bearer pa_…

Новые сверху; в ответе meta: page, per_page, total, last_page.

Поля запроса

ПолеТипЗачем
status string Фильтр по статусу
per_page integer До 100, по умолчанию 20
page integer Номер страницы

GET /api/v1/jobs/{id}/file

Скачать результат

Нужен ключ. Заголовок Authorization: Bearer pa_…

PDF или ZIP. Файл хранится 7 дн., затем удаляется — после этого и пока задание не готово ответ 409 file_unavailable.

Пример

curl -H "Authorization: Bearer $KEY" -o konverty.pdf https://dev.postapi.ru/api/v1/jobs/01m3z…/file

POST /api/v1/jobs/{id}/print

Отправить на печать

Нужен ключ. Заголовок Authorization: Bearer pa_…

Для способов, которые отправляют файл (email, cups), статус становится sent_to_print. Файл больше 20 МБ по почте не уходит.

Поля запроса

ПолеТипЗачем
adapter* string download — только отметка «печатаю сам»; email — отправить файл по почте (в типографию); cups — на принтер сервера, если подключён
email string Адрес получателя файла — для adapter = email

Адреса

Адресная книга хранится в зашифрованном виде и видна только вам. Индекс всегда проверяется: ровно 6 цифр.

GET /api/v1/addresses

Список адресов

Нужен ключ. Заголовок Authorization: Bearer pa_…

Ответ с data и meta, как у списка заданий.

Поля запроса

ПолеТипЗачем
q string Поиск по имени, адресу и индексу
label string Группа
per_page integer До 100, по умолчанию 50
page integer Номер страницы

POST /api/v1/addresses

Добавить адрес

Нужен ключ. Заголовок Authorization: Bearer pa_…

Поля запроса

ПолеТипЗачем
name* string ФИО или организация
address* string Адрес, строки через перевод строки
postal_code* string Индекс, 6 цифр
label string Группа для отбора, до 64 символов
is_sender boolean Адрес отправителя — подставляется в задания

Пример

curl -X POST https://dev.postapi.ru/api/v1/addresses -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"name":"Иванов Иван","address":"Невский пр-т, д. 28","postal_code":"191186","label":"клиенты"}'

Ответ

{ "data": { "id": "01m3z…", "name": "Иванов Иван", "address": "Невский пр-т, д. 28", "postal_code": "191186", "label": "клиенты", "is_sender": false, "created_at": "…" } }

POST /api/v1/addresses/validate

Проверить адрес без сохранения

Нужен ключ. Заголовок Authorization: Bearer pa_…

Возвращает нормализованный вид (лишние пробелы убраны) и ошибки по полям. Ничего не сохраняет — удобно проверять форму у себя на сайте.

Поля запроса

ПолеТипЗачем
name, address, postal_code string Те же поля, что при создании

Ответ

{ "data": { "valid": false, "normalized": { "name": "Иванов", "address": "Москва", "postal_code": "12", "label": null, "is_sender": false }, "errors": { "postal_code": "Индекс — ровно 6 цифр." } } }

GET /api/v1/addresses/{id}

Получить адрес

Нужен ключ. Заголовок Authorization: Bearer pa_…

PUT /api/v1/addresses/{id}

Изменить адрес

Нужен ключ. Заголовок Authorization: Bearer pa_…

Передайте только изменяемые поля.

DELETE /api/v1/addresses/{id}

Удалить адрес

Нужен ключ. Заголовок Authorization: Bearer pa_…

Ответ 204.

Webhooks

Вместо опроса можно получать события: когда задание меняет статус, мы отправляем POST с JSON на ваш адрес. Адрес — только https на публичный сервер: адреса во внутренней сети отклоняются. Редиректы не выполняются.

События: job.queued, job.rendering, job.ready, job.sent_to_print, job.printed, job.failed. По умолчанию подписка — на job.ready и job.failed.

{
    "id": "01m3z5…",
    "event": "job.ready",
    "created_at": "2026-10-03T12:00:10+03:00",
    "data": { …то же представление задания, что в GET /jobs/{id}… }
}

Заголовки: X-PostAPI-Event, X-PostAPI-Delivery, X-PostAPI-Timestamp и X-PostAPI-Signature: sha256=<hex>. Подпись — HMAC-SHA256 от строки <timestamp>.<тело запроса> с секретом подписки. Проверяйте её и сверяйте время, чтобы отсечь повторы старых запросов:

$body = file_get_contents('php://input');
$expected = hash_hmac('sha256', $_SERVER['HTTP_X_POSTAPI_TIMESTAMP'] . '.' . $body, $secret);
$given = substr($_SERVER['HTTP_X_POSTAPI_SIGNATURE'], 7);   // без «sha256=»
if (!hash_equals($expected, $given) || abs(time() - (int) $_SERVER['HTTP_X_POSTAPI_TIMESTAMP']) > 300) {
    http_response_code(401); exit;
}

Ответ 2xx — доставлено. Иначе повторы через 1, 5 и 30 минут. Подписка, у которой подряд не удались 30 доставок, отключается — включите её снова в кабинете.

POST /api/v1/webhooks

Подписаться на события

Нужен ключ. Заголовок Authorization: Bearer pa_…

Секрет подписи возвращается только в этом ответе — сохраните его.

Поля запроса

ПолеТипЗачем
url* string https-адрес вашего обработчика
events array Список событий; по умолчанию job.ready и job.failed

Пример

curl -X POST https://dev.postapi.ru/api/v1/webhooks -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"url":"https://example.ru/hooks/postapi","events":["job.ready","job.failed"]}'

Ответ

{ "data": { "id": "01m3z…", "url": "https://example.ru/hooks/postapi", "events": ["job.ready", "job.failed"], "active": true, "secret": "whsec_…" } }

GET /api/v1/webhooks

Список подписок

Нужен ключ. Заголовок Authorization: Bearer pa_…

Секрет в списке не показывается.

GET /api/v1/webhooks/{id}

Подписка и последние доставки

Нужен ключ. Заголовок Authorization: Bearer pa_…

В recent_deliveries — статус, число попыток и код ответа вашего сервера.

POST /api/v1/webhooks/{id}/ping

Пробное событие

Нужен ключ. Заголовок Authorization: Bearer pa_…

Отправляет событие ping — проверить обработчик и подпись. Ответ 202.

DELETE /api/v1/webhooks/{id}

Удалить подписку

Нужен ключ. Заголовок Authorization: Bearer pa_…

Ответ 204.

Что-то не описано или не работает?

Машинное описание всех методов — в OpenAPI; его можно загрузить в Postman или Insomnia. Остальное — напишите нам.