[{"data":1,"prerenderedAt":9},["ShallowReactive",2],{"$flJ1WYHsn6szh-5RLUeWPTBbCPZSlHzRNtWaHXB339DI":3},{"title":4,"description":5,"lead":6,"html":7,"slug":8},"Генерация PDF из HTML-шаблона: от самописных решений к API","Сравниваем Puppeteer, WeasyPrint, PDFKit и другие инструменты для генерации PDF из HTML. Показываем, как подключить Bulldoc API и генерировать PDF по шаблону на Python, JavaScript и Node.js — без лишней инфраструктуры.","Рано или поздно любое приложение обрастает задачей «выгрузить это в PDF». Счёт, договор, отчёт — неважно. Задача кажется простой ровно до первого боевого деплоя. В этой статье разбираем, почему самостоятельная реализация генерации PDF из HTML превращается в отдельный инфраструктурный проект, и как Bulldoc решает её одним API-вызовом.","\u003Ch2>Зачем вообще генерировать PDF программно\u003C\u002Fh2>\n\u003Cp>PDF остаётся де-факто стандартом для любых «официальных» документов: счета, акты, договоры, билеты, сертификаты, аналитические отчёты. Пользователь ожидает получить файл, который одинаково выглядит на любом устройстве, не редактируется без специального ПО и корректно печатается.\u003C\u002Fp>\n\u003Cp>Для разработчика это значит, что генерация PDF должна быть \u003Cstrong>программной и повторяемой\u003C\u002Fstrong> — данные из базы подставляются в шаблон, документ рендерится и отдаётся пользователю или сохраняется в хранилище.\u003C\u002Fp>\n\u003Ch2>Популярные инструменты для генерации PDF из HTML\u003C\u002Fh2>\n\u003Ch3>Puppeteer \u002F Playwright\u003C\u002Fh3>\n\u003Cp>Самый распространённый подход в Node.js-мире — запустить chromium-headless и вызвать \u003Ccode>page.pdf()\u003C\u002Fcode>. Puppeteer и Playwright дают доступ к полному браузерному рендерингу: поддержка CSS Grid, Flexbox, веб-шрифтов, SVG, даже Canvas.\u003C\u002Fp>\n\u003Cdiv class=\"shiki-code\">\u003Cpre class=\"shiki material-theme-palenight\" style=\"background-color:transparent;color:#babed8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">\u002F\u002F Генерация PDF через Puppeteer\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C792EA\">const\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> browser \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF;font-style:italic\"> await\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> puppeteer\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">launch\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">()\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C792EA\">const\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> page \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF;font-style:italic\"> await\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> browser\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">newPage\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">()\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">await\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> page\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">setContent\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">(html)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C792EA\">const\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> pdf \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF;font-style:italic\"> await\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> page\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">pdf\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">{\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\"> format\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">A4\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> }\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">await\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> browser\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">close\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">()\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Звучит просто, но в production сразу возникают проблемы. Chromium весит ~300 МБ и потребляет 200–400 МБ оперативной памяти \u003Cstrong>на каждый параллельный рендер\u003C\u002Fstrong>. Нужен пул процессов, тайм-ауты, логи падений. Если шаблоны поступают от пользователей — открываете XSS-вектор прямо в headless-браузере, то есть нужна строгая изоляция (Docker, seccomp, отдельная VM). При сколь-либо серьезной нагрузке это уже отдельный сервис с автоскейлингом, а если нагрузка невелика, то поддежка такой инфраструктуры просто не стоит того.\u003C\u002Fp>\n\u003Ch3>WeasyPrint\u003C\u002Fh3>\n\u003Cp>Python-библиотека для рендеринга HTML\u002FCSS в PDF через собственный движок (без браузера). Легче Puppeteer, но поддержка CSS значительно хуже: нет Flexbox Grid в полном объёме, проблемы с кастомными шрифтами, специфические баги с page-break. Шаблоны приходится писать «под WeasyPrint», что сильно ограничивает дизайн.\u003C\u002Fp>\n\u003Cdiv class=\"shiki-code\">\u003Cpre class=\"shiki material-theme-palenight\" style=\"background-color:transparent;color:#babed8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\"># Генерация PDF через WeasyPrint\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">from\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> weasyprint \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF;font-style:italic\">import\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> HTML\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#82AAFF\">HTML\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">(\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8;font-style:italic\">string\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">html_content\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">).\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">write_pdf\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">(\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">'\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">output.pdf\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">'\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">)\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Хорошо работает для простых документов, плохо масштабируется и требует установки системных зависимостей (\u003Ccode>libpango\u003C\u002Fcode>, \u003Ccode>libcairo\u003C\u002Fcode> и др.), что усложняет деплой в контейнерах.\u003C\u002Fp>\n\u003Ch3>PDFKit (Node.js \u002F Ruby)\u003C\u002Fh3>\n\u003Cp>PDFKit — это генерация PDF \u003Cstrong>снизу вверх\u003C\u002Fstrong>: вы программно рисуете прямоугольники, добавляете текст, задаёте координаты. Никакого HTML — только low-level PDF API. Результат предсказуем и компактен, но подготовка шаблона требует в разы больше кода, а любое изменение макета — болезненный рефакторинг.\u003C\u002Fp>\n\u003Cdiv class=\"shiki-code\">\u003Cpre class=\"shiki material-theme-palenight\" style=\"background-color:transparent;color:#babed8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">\u002F\u002F Генерация PDF через PDFKit — низкоуровневый подход\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C792EA\">const\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> doc \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> new\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> PDFDocument\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">()\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">doc\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">fontSize\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">18\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">text\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">Счёт №123\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\"> 50\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\"> 50\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">doc\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">fontSize\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">12\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">text\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">`\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">Итого: \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">${\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">amount\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\"> ₽\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">`\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\"> 50\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\"> 100\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Ch3>wkhtmltopdf\u003C\u002Fh3>\n\u003Cp>Классика, основанная на WebKit. Больше не поддерживается активно (последний релиз — 2020 год), движок устарел, современный CSS поддерживается частично. На новых дистрибутивах Linux возникают конфликты зависимостей. Упоминаем для полноты картины — в новых проектах лучше избегать.\u003C\u002Fp>\n\u003Ch3>Краткое сравнение\u003C\u002Fh3>\n\u003Cdiv class=\"overflow-auto\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Инструмент\u003C\u002Fth>\n\u003Cth>HTML\u002FCSS поддержка\u003C\u002Fth>\n\u003Cth>Нагрузка на сервер\u003C\u002Fth>\n\u003Cth>Сложность деплоя\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\u003Ctr>\n\u003Ctd>Puppeteer\u002FPlaywright\u003C\u002Ftd>\n\u003Ctd>Полная (Chromium)\u003C\u002Ftd>\n\u003Ctd>Высокая\u003C\u002Ftd>\n\u003Ctd>Высокая\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>WeasyPrint\u003C\u002Ftd>\n\u003Ctd>Частичная\u003C\u002Ftd>\n\u003Ctd>Низкая\u003C\u002Ftd>\n\u003Ctd>Средняя\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>PDFKit\u003C\u002Ftd>\n\u003Ctd>Нет (low-level)\u003C\u002Ftd>\n\u003Ctd>Низкая\u003C\u002Ftd>\n\u003Ctd>Низкая\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>wkhtmltopdf\u003C\u002Ftd>\n\u003Ctd>Устаревшая\u003C\u002Ftd>\n\u003Ctd>Средняя\u003C\u002Ftd>\n\u003Ctd>Высокая\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003C\u002Fdiv>\u003Cp>Проблема в том, что \u003Cstrong>генерация PDF из HTML — это инфраструктурная задача\u003C\u002Fstrong>.\u003C\u002Fp>\n\u003Cp>Вот неполный список того, с чем придётся разобраться самостоятельно: изоляция шаблонов от XSS и SSRF-атак, управление пулом headless-браузеров и их падениями, мониторинг памяти и CPU при пиковой нагрузке, обновление Chromium после security-патчей, корректная работа кириллических и нестандартных шрифтов, очередь задач при асинхронной генерации.\u003C\u002Fp>\n\u003Ch2>Bulldoc - специализированный сервис для генерации документов\u003C\u002Fh2>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fbulldoc.dev\">Bulldoc\u003C\u002Fa> — это специализированный сервис для генерации и обработки печатных документов, доступный через REST API. Вместо того чтобы поддерживать инфраструктуру рендеринга самостоятельно, вы отправляете HTTP-запрос с HTML-шаблоном и данными — и получаете готовый PDF.\u003C\u002Fp>\n\u003Ch3>Гибкие динамические шаблоны\u003C\u002Fh3>\n\u003Cp>Шаблоны поддерживают синтаксис Handlebars: \u003Ccode>{{ переменная }}\u003C\u002Fcode>, \u003Ccode>{{#each список}}\u003C\u002Fcode>, условия \u003Ccode>{{#if}}\u003C\u002Fcode>. Это привычно, предсказуемо и работает как с простыми счетами, так и со сложными многостраничными отчётами. В шаблоне можно использовать JavaScript (включая сторонние библиотеки), произвольный CSS и любой CSS-фреймворк — рендеринг происходит в полноценном браузерном движке.\u003C\u002Fp>\n\u003Cp>Отдельно можно задавать колонтитулы (header\u002Ffooter), формат страницы (A4, A3 и др.), ориентацию и поля — прямо в параметрах шаблона или в теле запроса.\u003C\u002Fp>\n\u003Ch3>Простое и удобное API\u003C\u002Fh3>\n\u003Cp>API построен по стандарту OpenAPI, что позволяет сгенерировать клиентскую библиотеку для любого языка программирования.\u003C\u002Fp>\n\u003Cp>Поддерживаются два режима работы: \u003Cstrong>асинхронный\u003C\u002Fstrong> (по умолчанию) и \u003Cstrong>синхронный\u003C\u002Fstrong> (параметр \u003Ccode>sync: true\u003C\u002Fcode>). В асинхронном режиме API сразу возвращает объект задачи с \u003Ccode>id\u003C\u002Fcode>, а статус можно опрашивать через \u003Ccode>GET \u002Fv1\u002Ftasks\u002F{id}\u003C\u002Fcode> или получить уведомление через вебхук. В синхронном режиме соединение держится открытым до завершения генерации — удобно для простых документов, когда нужно дождаться результата сразу.\u003C\u002Fp>\n\u003Ch3>Гибкое ценообразование\u003C\u002Fh3>\n\u003Cp>Модель оплаты — предоплаченные пакеты документов. Вы платите за то, что реально генерируете, без подписок и абонентской платы. Это особенно выгодно для приложений с нерегулярной или непредсказуемой нагрузкой.\u003C\u002Fp>\n\u003Ch2>Пошаговое руководство: генерация PDF из HTML-шаблона через Bulldoc\u003C\u002Fh2>\n\u003Ch3>Шаг 1. Регистрация в сервисе\u003C\u002Fh3>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fapp.bulldoc.dev\u002Fuser\u002Fregister\">Зарегистрируйтесь\u003C\u002Fa> в сервисе и создайте аккаунт. Для начала работы достаточно email и пароля.\u003C\u002Fp>\n\u003Ch3>Шаг 2. Создание API-ключа\u003C\u002Fh3>\n\u003Cp>После входа в личный кабинет перейдите в раздел настроек и создайте новый API-ключ. Ключ используется как Bearer-токен во всех запросах:\u003C\u002Fp>\n\u003Cdiv class=\"shiki-code\">\u003Cpre class=\"shiki material-theme-palenight\" style=\"background-color:transparent;color:#babed8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan>Authorization: Bearer ВАШ_API_КЛЮЧ\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Сохраните ключ в надёжном месте — он отображается только один раз при создании.\u003C\u002Fp>\n\u003Ch3>Шаг 3. Добавление шаблона\u003C\u002Fh3>\n\u003Cp>Шаблон — это HTML-документ с Handlebars-разметкой для подстановки данных. Добавить шаблон можно двумя способами.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Через веб-интерфейс\u003C\u002Fstrong> — в разделе «Шаблоны» вы можете создать новый HTML-шаблон, задать данные по умолчанию, настроить формат страницы и сразу увидеть превью. Это удобно для разработки и отладки шаблона.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Через API\u003C\u002Fstrong> — отправьте \u003Ccode>POST \u002Fv1\u002Ftemplates\u003C\u002Fcode> с кодом и параметрами шаблона:\u003C\u002Fp>\n\u003Cdiv class=\"shiki-code\">\u003Cpre class=\"shiki material-theme-palenight\" style=\"background-color:transparent;color:#babed8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">name\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">invoice\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">content\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">&#x3C;html>&#x3C;body>&#x3C;h1>Счёт № {{ invoiceNumber }}&#x3C;\u002Fh1>&#x3C;p>Клиент: {{ clientName }}&#x3C;\u002Fp>&#x3C;p>&#x3C;strong>Итого: {{ total }} ₽&#x3C;\u002Fstrong>&#x3C;\u002Fp>&#x3C;\u002Fbody>&#x3C;\u002Fhtml>\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">data\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">    \"\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\">invoiceNumber\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">001\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">    \"\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\">clientName\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">ООО Ромашка\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">    \"\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\">total\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">15 000\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  },\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">format\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">A4\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">orientation\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">portrait\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">margin\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> {\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\">top\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\"> 20\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\">bottom\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\"> 20\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\">left\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\"> 20\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\">right\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\"> 20\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Поле \u003Ccode>data\u003C\u002Fcode> задаёт данные по умолчанию — они используются для предпросмотра и будут \u003Cstrong>объединены\u003C\u002Fstrong> с данными, которые вы передаёте при генерации конкретного документа.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Синтаксис шаблонов (Handlebars)\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>Простая подстановка переменной — \u003Ccode>{{ имя_переменной }}\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Перебор массива — с помощью \u003Ccode>{{#each}}\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cdiv class=\"shiki-code\">\u003Cpre class=\"shiki material-theme-palenight\" style=\"background-color:transparent;color:#babed8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">ul\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">  {{\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF;font-style:italic\">#each\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8;font-style:italic\"> items\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">}}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">    &#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">li\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">>\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">{{\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8;font-style:italic\">this.name\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">}} — {{\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8;font-style:italic\">this.price\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">}} ₽\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">li\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">  {{\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF;font-style:italic\">\u002Feach\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">}}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">ul\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Условный блок — с помощью \u003Ccode>{{#if}}\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cdiv class=\"shiki-code\">\u003Cpre class=\"shiki material-theme-palenight\" style=\"background-color:transparent;color:#babed8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">{{\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF;font-style:italic\">#if\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8;font-style:italic\"> isPaid\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">}}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  &#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">span\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\"> class\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">badge\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">>\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">Оплачен\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">span\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">{{\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF;font-style:italic\">else\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">}}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  &#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">span\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\"> class\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">badge\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">>\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">Ожидает оплаты\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">span\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">{{\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF;font-style:italic\">\u002Fif\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">}}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>В шаблоне работает полноценный JavaScript: можно подключать библиотеки для рендеринга схем и графиков, использовать любые CSS-фреймворки, добавлять кастомные шрифты.\u003C\u002Fp>\n\u003Ch3>Шаг 4. Синхронные и асинхронные запросы\u003C\u002Fh3>\n\u003Cp>По умолчанию все запросы на генерацию — \u003Cstrong>асинхронные\u003C\u002Fstrong>. Это правильная модель для production: вы ставите задачу в очередь, получаете \u003Ccode>taskId\u003C\u002Fcode>, и когда документ готов — забираете его по ссылке или получаете уведомление на вебхук. Такой подход не блокирует HTTP-соединение и хорошо работает при пиковых нагрузках.\u003C\u002Fp>\n\u003Cdiv class=\"shiki-code\">\u003Cpre class=\"shiki material-theme-palenight\" style=\"background-color:transparent;color:#babed8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">\u002F\u002F Ответ на асинхронный запрос\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">id\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">6ITGo\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">status\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">pending\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">type\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">pdf\u002Ffrom-template\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">documents\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> []\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>Для простых сценариев (например, синхронная выгрузка документа пользователю прямо в браузер) удобен \u003Cstrong>синхронный режим\u003C\u002Fstrong> — добавьте \u003Ccode>&quot;sync&quot;: true\u003C\u002Fcode> в тело запроса. API будет держать соединение открытым и вернёт финальный объект задачи с уже готовой ссылкой на документ:\u003C\u002Fp>\n\u003Cdiv class=\"shiki-code\">\u003Cpre class=\"shiki material-theme-palenight\" style=\"background-color:transparent;color:#babed8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">\u002F\u002F Ответ на синхронный запрос\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">id\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">6ITGo\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">status\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">finished\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  \"\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\">documents\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> [\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">    {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">      \"\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\">id\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">abc123\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">      \"\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\">url\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">https:\u002F\u002F...\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">      \"\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\">bytesize\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\"> 34521\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">      \"\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\">expiresAt\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">2026-04-18T12:00:00Z\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">    }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  ]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Ch3>Шаг 5. Примеры запросов для генерации PDF\u003C\u002Fh3>\n\u003Ch4>cURL\u003C\u002Fh4>\n\u003Cdiv class=\"shiki-code\">\u003Cpre class=\"shiki material-theme-palenight\" style=\"background-color:transparent;color:#babed8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFCB6B\">curl\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\"> -X\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\"> POST\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\"> https:\u002F\u002Fapi.bulldoc.dev\u002Fv1\u002Fpdf\u002Ffrom\u002Ftemplate\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C3E88D\">  -H\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">Authorization: Bearer ВАШ_API_КЛЮЧ\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C3E88D\">  -H\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">Content-Type: application\u002Fjson\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> \\\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C3E88D\">  -d\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> '\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C3E88D\">    \"templateId\": \"ВАШ_TEMPLATE_ID\",\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C3E88D\">    \"sync\": true,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C3E88D\">    \"data\": {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C3E88D\">      \"invoiceNumber\": \"042\",\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C3E88D\">      \"clientName\": \"ИП Иванов\",\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C3E88D\">      \"total\": \"37 500\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C3E88D\">    }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C3E88D\">  }\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">'\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Ch4>JavaScript \u002F Node.js\u003C\u002Fh4>\n\u003Cp>Ниже пример генерации PDF из шаблона в Node.js с использованием встроенного \u003Ccode>fetch\u003C\u002Fcode> (Node 18+). Обратите внимание, что мы используем синхронный режим и сразу получаем ссылку на скачивание.\u003C\u002Fp>\n\u003Cdiv class=\"shiki-code\">\u003Cpre class=\"shiki material-theme-palenight\" style=\"background-color:transparent;color:#babed8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">\u002F\u002F Node.js — генерация PDF из HTML-шаблона через Bulldoc API\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C792EA\">async\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\"> function\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> generateInvoice\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">(\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8;font-style:italic\">data\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C792EA\">  const\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> response\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF;font-style:italic\"> await\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> fetch\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">(\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">https:\u002F\u002Fapi.bulldoc.dev\u002Fv1\u002Fpdf\u002Ffrom\u002Ftemplate\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F07178\">    method\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">POST\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F07178\">    headers\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> {\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F07178\">      Authorization\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> `\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">Bearer \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">${\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">process\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">env\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">BULLDOC_API_KEY\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">}`\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">      \"\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">Content-Type\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">application\u002Fjson\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">    },\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F07178\">    body\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> JSON\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">stringify\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">(\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F07178\">      templateId\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">ВАШ_TEMPLATE_ID\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F07178\">      sync\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#FF9CAC\"> true\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#676E95;font-style:italic\"> \u002F\u002F ждём готового результата\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F07178\">      data\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> data\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">    }\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  }\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">  if\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\"> (\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">!\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">response\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">ok\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">) \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">    throw\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> new\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> Error\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">(\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">`\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">Bulldoc API error: \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">${\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">response\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">status\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">}`\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">  }\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C792EA\">  const\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> task\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF;font-style:italic\"> await\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> response\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">json\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">()\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">  \u002F\u002F task.documents[0].url — прямая ссылка на скачивание PDF\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">  return\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> task\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">documents\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">[\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">0\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">]\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">url\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">}\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">\u002F\u002F Использование\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C792EA\">const\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> url \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF;font-style:italic\"> await\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> generateInvoice\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">{\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F07178\">  invoiceNumber\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">042\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F07178\">  clientName\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">ИП Иванов\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F07178\">  total\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">37 500\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">}\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">console\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">log\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\">(\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">PDF готов:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> url)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">;\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Ch4>Python\u003C\u002Fh4>\n\u003Cp>В Python удобнее всего использовать библиотеку \u003Ccode>httpx\u003C\u002Fcode> или \u003Ccode>requests\u003C\u002Fcode>. Пример ниже демонстрирует \u003Cstrong>генерацию PDF по шаблону\u003C\u002Fstrong> в синхронном режиме, а также вариант с inline-шаблоном — когда шаблон передаётся прямо в запросе, без предварительного сохранения.\u003C\u002Fp>\n\u003Cdiv class=\"shiki-code\">\u003Cpre class=\"shiki material-theme-palenight\" style=\"background-color:transparent;color:#babed8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">import\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> os\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">import\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> httpx  \u003C\u002Fspan>\u003Cspan style=\"color:#676E95;font-style:italic\"># pip install httpx\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">BULLDOC_API_KEY \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> os\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#F07178\">environ\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">[\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">BULLDOC_API_KEY\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">BASE_URL \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">https:\u002F\u002Fapi.bulldoc.dev\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C792EA\">def\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> generate_pdf_from_template\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">(\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8;font-style:italic\">template_id\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\"> str\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8;font-style:italic\"> data\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\"> dict\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> ->\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\"> str\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">    \"\"\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">    Python генерация PDF по шаблону через Bulldoc API.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">    Возвращает URL готового PDF-файла.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">    \"\"\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">    response \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> httpx\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">post\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">(\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C792EA\">        f\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">{\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">BASE_URL\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">}\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">\u002Fv1\u002Fpdf\u002Ffrom\u002Ftemplate\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8;font-style:italic\">        headers\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">={\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">            \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">Authorization\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\"> f\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">\"Bearer \u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">{\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">BULLDOC_API_KEY\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">}\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">            \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">Content-Type\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">application\u002Fjson\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">        },\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8;font-style:italic\">        json\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">={\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">            \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">templateId\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> template_id\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">            \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">sync\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> True,\u003C\u002Fspan>\u003Cspan style=\"color:#676E95;font-style:italic\">  # синхронный режим\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">            \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">data\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> data\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">        },\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8;font-style:italic\">        timeout\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">60.0\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#676E95;font-style:italic\">  # запас для сложных документов\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">    )\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">    response\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">raise_for_status\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">    task \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> response\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">json\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">    return\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> task\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">[\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">documents\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">][\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">0\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">][\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">url\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C792EA\">def\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> generate_pdf_inline\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">(\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8;font-style:italic\">html\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\"> str\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8;font-style:italic\"> data\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\"> dict\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">)\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> ->\u003C\u002Fspan>\u003Cspan style=\"color:#FFCB6B\"> str\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">    \"\"\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">    Конвертировать HTML в PDF без сохранённого шаблона.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">    Удобно для одноразовых или динамически формируемых документов.\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">    \"\"\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">    response \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> httpx\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">post\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">(\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#C792EA\">        f\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">{\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">BASE_URL\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">}\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">\u002Fv1\u002Fpdf\u002Ffrom\u002Ftemplate\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8;font-style:italic\">        headers\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">={\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">            \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">Authorization\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#C792EA\"> f\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">\"Bearer \u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">{\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">BULLDOC_API_KEY\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">}\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">            \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">Content-Type\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">application\u002Fjson\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">        },\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8;font-style:italic\">        json\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">={\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">            \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">template\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> html\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#676E95;font-style:italic\">  # шаблон прямо в теле запроса\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">            \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">sync\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> True,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">            \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">data\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> data\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">        },\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8;font-style:italic\">        timeout\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">60.0\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">    )\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">    response\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">raise_for_status\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">    task \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> response\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">.\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">json\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">()\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">    return\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> task\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">[\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">documents\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">][\u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">0\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">][\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">url\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">]\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\"># Пример использования\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF;font-style:italic\">if\u003C\u002Fspan>\u003Cspan style=\"color:#BABED8\"> __name__ \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">==\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">__main__\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">    # Вариант 1: использовать сохранённый шаблон\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">    pdf_url \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> generate_pdf_from_template\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">(\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8;font-style:italic\">        template_id\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">ВАШ_TEMPLATE_ID\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8;font-style:italic\">        data\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">={\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">invoiceNumber\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">042\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">clientName\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">ИП Иванов\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">total\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">37 500\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">},\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#89DDFF\">    )\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#82AAFF\">    print\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">(\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">PDF готов:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> pdf_url\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#676E95;font-style:italic\">    # Вариант 2: inline-шаблон (конвертировать HTML в PDF на лету)\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">    html_template \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">&#x3C;html>&#x3C;body>&#x3C;h1>Привет, \u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">{{\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\"> name \u003C\u002Fspan>\u003Cspan style=\"color:#F78C6C\">}}\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">!&#x3C;\u002Fh1>&#x3C;\u002Fbody>&#x3C;\u002Fhtml>\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#BABED8\">    pdf_url \u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">=\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> generate_pdf_inline\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">(\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\">html_template\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> {\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">name\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\"> \"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">Мир\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">})\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#82AAFF\">    print\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">(\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C3E88D\">Inline PDF:\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">,\u003C\u002Fspan>\u003Cspan style=\"color:#82AAFF\"> pdf_url\u003C\u002Fspan>\u003Cspan style=\"color:#89DDFF\">)\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Ch2>Итог\u003C\u002Fh2>\n\u003Cp>Генерация PDF из HTML — задача, которая обманчиво выглядит простой. Puppeteer, WeasyPrint, wkhtmltopdf и PDFKit отлично справляются с базовыми сценариями, но в production каждый из них превращается в отдельный инфраструктурный проект: безопасность шаблонов, управление памятью, масштабирование, обновления.\u003C\u002Fp>\n\u003Cp>Bulldoc позволяет вынести эту инфраструктуру за пределы вашего приложения и свести интеграцию к одному HTTP-запросу. Шаблоны на Handlebars, полная поддержка HTML\u002FCSS\u002FJS, синхронный и асинхронный режимы, прозрачное ценообразование — всё это делает его удобным вариантом как для стартапов, так и для зрелых продуктов, которым надоело поддерживать «PDF-сервис» внутри монолита.\u003C\u002Fp>\n\u003Cp>Начните совершенно бесплатно: \u003Ca href=\"https:\u002F\u002Fbulldoc.dev\">bulldoc.dev\u003C\u002Fa>.\u003C\u002Fp>\n","pdf-from-html",1775924089270]