Ошибки и повторы
Ошибку видно по HTTP-статусу, а причину — по полю error в JSON. На error стоит опираться в коде, message — для журнала и человека, он написан по-русски. У 401 и 429 поля message нет, поэтому строить логику на нём не стоит. Например:
{
"error": "quota_exceeded",
"message": "Лимит страниц исчерпан"
}Коды ошибок#
| HTTP | Код | Когда |
|---|---|---|
| 400 | invalid_request | нет source или содержимого, лишний или неверный параметр в options — имя поля в message |
| 400 | url_not_allowed | адрес без http(s) или ведёт во внутреннюю сеть |
| 401 | missing_api_key | нет заголовка Authorization: Bearer … и X-API-Key |
| 401 | invalid_api_key | ключ неверный или отозван |
| 402 | quota_exceeded | лимит исчерпан или документ больше остатка; страницы не списываются |
| 403 | email_not_verified | почта аккаунта не подтверждена |
| 403 | source_not_allowed | источник недоступен на тарифе: на Free — только HTML |
| 409 | idempotency_in_progress | ещё выполняется, повторите через Retry-After с тем же ключом |
| 409 | idempotency_conflict | тело запроса отличается от исходного |
| 410 | result_expired | новый рендер требует нового ключа |
| 413 | payload_too_large | вынесите картинки по ссылкам или уменьшите файл |
| 429 | rate_limit_exceeded | запросы чаще лимита тарифа; повторите через Retry-After секунд |
| 502 | render_failed | обычно дело в разметке или недоступной странице |
| 503 | unavailable | очередь заполнена или рендер перезапускается; повторите позже |
| 504 | render_timeout | документ слишком тяжёлый или страница грузится долго |
Какие запросы повторять#
Передавайте Idempotency-Key — случайный идентификатор одного документа. При таймауте или обрыве повторите то же тело и тот же ключ: готовый PDF хранится приватно 24 часа и выдаётся без нового списания. Без сохранённого ключа повтор считается новым документом.
| Ответ | Действие |
|---|---|
409 idempotency_in_progress | запрос ещё выполняется; повторите тот же ключ через Retry-After |
409 idempotency_conflict | ключ уже связан с другим содержимым; исправьте ошибку в клиенте |
410 result_expired | PDF удалён; новый рендер требует нового ключа и расходует страницы |
429 | дождитесь Retry-After, сохраните ключ |
таймаут, обрыв или 503 | повторите с тем же ключом; это не создаст второе списание |
сохранённая ошибка с new_key_required: true | этот рендер завершён без списания; исправьте причину и используйте новый ключ |
Страницы списываются один раз, когда PDF сохранён и готов к выдаче. Отключение клиента после этого не отменяет списание: результат доступен для повторной выдачи 24 часа. Факт доставки клиенту сервер подтвердить не может. Подробности — Идемпотентность.
Как это делают библиотеки#
Библиотеки pdfapi повторяют 429, 503 и неустановленное соединение сами — по умолчанию до двух раз — и никогда не повторяют таймауты. Ошибки приходят исключениями отдельных классов:
Ответы не от API#
Между вами и API стоят прокси. Они иногда отвечают сами — кодом 413 или страницей HTML с кодом 502. У таких ответов нет поля error: определяйте ошибку по статусу (библиотеки pdfapi так и делают). 404 чаще всего значит, что в базовом адресе забыли /api: правильно — https://pdfapi.ru/api.