Сценарии целиком
Шесть типовых задач от начала до конца: какие инструменты MCP вызывать, в каком порядке и с какими аргументами, и то же самое запросами REST. Порядок и подводные камни объяснены в AGENTS.md, вёрстка — в руководстве по вёрстке.
Как читать:
- строка MCP —
инструмент {аргументы}; строка REST —МЕТОД /путь {тело}, всегда с заголовкомAuthorization: Bearer vru_…; <documentId>,<sheetId>,<jobId>и подобные берутся из ответов предыдущих шагов;- шаг «показать человеку» — не вызов, а пауза: дождитесь согласия, прежде чем тратить квоту или слать письма.
Школьная олимпиада: грамоты за места
Задача: призёрам олимпиады — грамоты «за первое (второе, третье) место», ФИО в дательном падеже, школа под именем.
Порядок важен: сначала таблица, потом раскладка. Готовая раскладка верстает строку «за %place_word место», только если у документа уже есть колонка place, а %place_word («первое») считается из неё сама.
get_account {}
create_project {"name": "Олимпиада по математике 2026"}
create_document {"title": "Грамота призёра — олимпиада по математике", "projectId": "<projectId>", "format": "a4", "orientation": "portrait"}
import_recipients {"documentId": "<documentId>", "columns": ["name", "email", "place", "team"], "titles": ["ФИО", "Почта", "Место", "Школа"], "rows": [["Иванова Мария Сергеевна", "ivanova@example.com", "1", "Школа № 5"], ["Петров Олег Иванович", "", "2", "Лицей № 2"]], "mode": "replace"}
apply_preset {"documentId": "<documentId>", "sheetId": "<sheetId>", "kind": "award", "style": "classic", "titlePrinted": false}
update_document {"documentId": "<documentId>", "eventName": "Городская олимпиада по математике", "eventDate": "14 ноября 2026", "constants": [{"key": "signer_role", "title": "Должность подписанта", "value": "Директор"}, {"key": "signer_name", "title": "Подписант", "value": "А. В. Смирнова"}]}
check_sheet {"documentId": "<documentId>", "sheetId": "<sheetId>"}
preview_sheet {"documentId": "<documentId>", "sheetId": "<sheetId>"}
validate_recipients {"documentId": "<documentId>"}
edit_recipients {"documentId": "<documentId>", "applySuggestions": true} — однозначные исправления, если они есть
— показать человеку: сколько грамот выйдет и сколько останется —
start_generation {"documentId": "<documentId>", "format": "pdf"}
get_job {"jobId": "<jobId>", "waitSeconds": 60}
get_download_link {"jobId": "<jobId>", "format": "zip", "name": "%place место %name"}GET /api/auth/me
GET /api/org/usage
POST /api/projects {"name": "Олимпиада по математике 2026"}
POST /api/documents {"title": "…", "projectId": "<projectId>", "format": "a4", "orientation": "portrait"}
POST /api/documents/<documentId>/recipients/import {"columns": […], "titles": […], "rows": […], "mode": "replace"}
POST /api/documents/<documentId>/sheets/<sheetId>/preset {"kind": "award", "style": "classic", "titlePrinted": false}
PATCH /api/documents/<documentId> {"eventName": "…", "eventDate": "…", "constants": […]}
POST /api/documents/<documentId>/sheets/<sheetId>/check {}
POST /api/documents/<documentId>/sheets/<sheetId>/preview {}
POST /api/documents/<documentId>/validation {}
POST /api/documents/<documentId>/validation/fix {"fixes": [{"rowId": "…", "column": "name", "value": "…"}]} — suggestion из замечаний
POST /api/documents/<documentId>/generate {"format": "pdf"}
GET /api/jobs/<jobId> — раз в 2–3 секунды до done
POST /api/jobs/<jobId>/archive-link {"format": "zip", "name": "%place место %name"}Если грамоты печатаются на готовых бланках с напечатанным словом «Грамота» — titlePrinted: true, а бланк загрузите фоном: upload_image {"documentId": "<documentId>", "sheetId": "<sheetId>", "target": "background", "url": "https://example.ru/blank.jpg"}. Участникам без места подойдёт отдельный документ с раскладкой participant.
Протокол и бланк лежат файлами на диске, а у агента есть оболочка (Claude Code, Codex, Cursor) — вместо import_recipients и upload_image:
get_upload_link {"documentId": "<documentId>", "target": "recipients", "mode": "replace"}
curl -sS -F "file=@протокол.xlsx" "<ссылка из ответа>" — в оболочке; ответ: imported, columns
get_upload_link {"documentId": "<documentId>", "target": "background", "sheetId": "<sheetId>"}
curl -sS -F "file=@бланк.jpg" "<ссылка из ответа>" — фон сразу на листе
preview_sheet {"documentId": "<documentId>", "sheetId": "<sheetId>"}Курс с часами: сертификат и выдача из учебной платформы
Задача: каждому, кто закончил курс, учебная платформа сама выдаёт сертификат с объёмом часов и отправляет его письмом.
Подготовка (один раз, вместе с человеком):
get_account {}
create_document {"title": "Сертификат — курс «Основы SQL»", "format": "a4", "preset": {"kind": "course", "style": "modern", "titlePrinted": false}}
update_document {"documentId": "<documentId>", "eventName": "«Основы SQL»", "eventHours": "72 академических часа", "constants": [{"key": "signer_role", "title": "Должность подписанта", "value": "Руководитель программы"}, {"key": "signer_name", "title": "Подписант", "value": "И. П. Орлов"}]}
check_sheet {"documentId": "<documentId>", "sheetId": "<sheetId>"}
preview_sheet {"documentId": "<documentId>", "sheetId": "<sheetId>"}
set_mail_template {"documentId": "<documentId>", "subject": "%name, ваш сертификат о прохождении курса", "bodyHtml": "<p>Здравствуйте, %name!</p><p>Поздравляем с окончанием курса. Сертификат — во вложении.</p>", "attachGeneratedFile": true}
get_document {"documentId": "<documentId>"}Последний вызов показывает в fields.issue, какие поля принимает выдача. Раскладка course печатает «прошёл» или «прошла» по ФИО и строку «в объёме %hours» из eventHours.
Выдача — запрос платформы на каждого выпускника:
curl -X POST "https://vruchay.ru/api/documents/$DOCUMENT_ID/issue" \
-H "Authorization: Bearer $VRUCHAY_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: sql-course-enrollment-48213" \
-d '{"data":{"name":"Иванова Анна Сергеевна"},"email":"ivanova@example.com","send":true}'То же через MCP — для проверки на одном человеке: issue_document {"documentId": "<documentId>", "data": {"name": "Иванова Анна Сергеевна"}, "email": "ivanova@example.com", "send": true, "idempotencyKey": "sql-course-enrollment-48213"}.
- Ключ — идентификатор записи о завершении курса: повтор после обрыва связи вернёт тот же сертификат, а не выпустит второй.
201— сохраните в карточке ученикаfile.code,file.verifyUrlиfile.recipientUrl.202— опрашивайтеstatusUrlраз в 1–2 секунды.- Вебхуков нет: готовность узнаётся из ответа или опросом.
- Предел — 120 выдач в минуту на организацию;
429— подождать и повторить.
Конференция: сертификат участника, форма по ссылке и письма
Задача: зарегистрированным заранее — сертификаты письмом после конференции; тем, кто пришёл без регистрации, — ссылка или QR на экране, по которым сертификат забирают сами.
create_project {"name": "Конференция «Цифровая школа» 2026"}
create_document {"title": "Сертификат участника", "projectId": "<projectId>", "format": "a4", "preset": {"kind": "attendee", "style": "strict", "titlePrinted": false}}
update_document {"documentId": "<documentId>", "eventName": "Конференция «Цифровая школа»", "eventDate": "20–21 ноября 2026", "eventPlace": "Казань"}
check_sheet {"documentId": "<documentId>", "sheetId": "<sheetId>"}
preview_sheet {"documentId": "<documentId>", "sheetId": "<sheetId>"}
set_mail_template {"documentId": "<documentId>", "subject": "Сертификат участника конференции", "bodyHtml": "<p>%name, спасибо, что были с нами! Сертификат — во вложении.</p>"}
import_recipients {"documentId": "<documentId>", "columns": ["name", "email"], "rows": [["Соколова Елена Павловна", "sokolova@example.com"]], "mode": "replace"}
validate_recipients {"documentId": "<documentId>"}
edit_recipients {"documentId": "<documentId>", "applySuggestions": true} — однозначные исправления, если они есть
— показать человеку: сколько сертификатов выйдет —
start_generation {"documentId": "<documentId>"}
get_job {"jobId": "<jobId>", "waitSeconds": 60}
get_mail {"documentId": "<documentId>"}
— показать человеку: сколько писем уйдёт (audience.willSend), кому нет и с какого адреса —
send_mail {"documentId": "<documentId>"}
— показать человеку настройки формы —
setup_form {"kind": "link", "name": "Конференция — без регистрации", "documentIds": ["<documentId>"], "formFields": ["name"], "singleFilePerEmail": true}POST /api/projects {"name": "…"}
POST /api/documents {"title": "Сертификат участника", "projectId": "<projectId>", "format": "a4", "preset": {"kind": "attendee", "style": "strict", "titlePrinted": false}}
PATCH /api/documents/<documentId> {"eventName": "…", "eventDate": "…", "eventPlace": "…"}
POST /api/mail/templates/<documentId> {"subject": "…", "bodyHtml": "…"}
POST /api/documents/<documentId>/recipients/import {"columns": ["name", "email"], "rows": […], "mode": "replace"}
POST /api/documents/<documentId>/generate {}
GET /api/jobs/<jobId>
POST /api/mailing/send {"documentIds": ["<documentId>"], "kind": "transactional", "source": "table"}
POST /api/integrations/tilda {"kind": "link", "name": "…", "documentIds": ["<documentId>"], "formFields": ["name"]}Ответ формы несёт connect.formUrl — ссылку https://vruchay.ru/f/…: её показывают на экране или превращают в QR. «Один документ в руки» считается по заявкам самой формы: повторная заявка с того же адреса получает уже выданный формой сертификат — после кода на этот адрес. Тому, кому сертификат ушёл письмом по списку, форма выпустит второй, — поэтому ссылку показывают тем, кто пришёл без регистрации. Каждая новая заявка тратит документ из остатка. Для формы нужны права «Полный доступ».
Новое мероприятие по прошлому шаблону
Задача: оформление прошлогодней грамоты — новому турниру, без старых получателей.
Из шаблона организации (isTemplate: true):
list_documents {"templates": true}
create_document {"title": "Грамота — турнир 2027", "templateId": "<templateId>", "projectId": "<projectId>"}Из обычного документа — копией «под новое мероприятие»: копируются размер листа, листы с макетами и фоном, колонки, проект и настройки проверки; получатели, мероприятие, даты и срок — нет.
list_documents {"search": "турнир 2026"}
create_document {"copyOf": "<sourceId>", "title": "Грамота — турнир 2027"}
update_document {"documentId": "<newId>", "eventName": "Турнир по шахматам 2027", "eventDate": "март 2027"}
get_document {"documentId": "<newId>"}
edit_layout {"documentId": "<newId>", "sheetId": "<sheetId>", "baseVersion": 1, "update": [{"id": "<id текстового блока>", "props": {"text": "за победу в турнире"}}]}
check_sheet {"documentId": "<newId>", "sheetId": "<sheetId>"}
preview_sheet {"documentId": "<newId>", "sheetId": "<sheetId>"}
create_document {"copyOf": "<newId>", "asTemplate": true, "title": "Грамота турнира"}REST: GET /api/documents?templates=true, POST /api/documents {"templateId": …}, POST /api/documents/{id}/duplicate, PATCH /api/documents/{id}, PATCH /api/documents/{id}/sheets/{sheetId}/elements, POST /api/documents/{id}/template.
baseVersion—versionлиста изget_document. Если лист успел поменяться, придёт409— перечитайте и повторите.props.textзаменяет текст блока целиком; поля пишутся как%name.- Последний вызов сохраняет копию макета шаблоном на следующий год — спросите человека, нужно ли.
Исправить ошибку в выданном документе
Задача: в грамоте опечатка в фамилии — выдать исправленную, а старую сделать недействительной.
search_registry {"search": "Иванова"}
get_recipients {"documentId": "<documentId>", "limit": 500}
edit_recipients {"documentId": "<documentId>", "update": [{"rowId": "<rowId>", "data": {"name": "Иванова Марина Сергеевна"}}]}
preview_sheet {"documentId": "<documentId>", "sheetId": "<sheetId>", "rowId": "<rowId>"}
— показать человеку: перевыпуск тратит документ из остатка —
reissue_documents {"fileIds": ["<fileId>"]}
get_job {"jobId": "<jobId>", "waitSeconds": 60}
search_registry {"search": "Иванова Марина"}
send_mail {"fileIds": ["<новый fileId>"]}- В реестре у строки есть
fileIdиdocumentId; строку таблицы находят по имени или почте вget_recipients— перевыпуск печатает по ней. jobIdдляget_job— из ответа перевыпуска,jobs[0].jobId.- Перевыпуск не отзывает старый документ, а заменяет: его страница проверки показывает, где взять новый (
state: "replaced",replacedBy). send_mailсfileIdsотправляет письмо с уже выпущенным файлом на почту из строки таблицы и квоту не тратит.
Если документ выдан по ошибке вовсе — отзыв, без замены:
revoke_documents {"fileIds": ["<fileId>"]}
— показать человеку: число документов и имена —
revoke_documents {"fileIds": ["<fileId>"], "expectedCount": 1, "reasonPublic": "Выдан по ошибке"}REST — те же пути и тела: GET /api/registry?search=…, PATCH /api/documents/{id}/recipients/rows/{rowId}, POST /api/registry/reissue, POST /api/registry/resend, POST /api/registry/revoke/preview, POST /api/registry/revoke. Перевыпуск и отзыв требуют прав «Полный доступ».
Проект на сайт: несколько документов за одной формой
Задача: у школы есть сайт; на странице олимпиады — кнопки «Получить грамоту» и «Получить благодарность» для учителей. Всё выданное — в отдельном проекте, со своим реестром и цифрами.
create_project {"name": "Сайт школы — олимпиада"}
create_document {"title": "Диплом участника", "projectId": "<projectId>", "format": "a4", "preset": {"kind": "participant", "style": "academic", "titlePrinted": false}}
create_document {"title": "Благодарность учителю", "projectId": "<projectId>", "format": "a4", "preset": {"kind": "thanks", "style": "academic", "titlePrinted": false}}
update_document {"documentId": "<id диплома>", "eventName": "Школьная олимпиада по физике"}
update_document {"documentId": "<id благодарности>", "eventName": "Школьная олимпиада по физике"}
check_sheet {…} и preview_sheet {…} — для каждого листа
— показать человеку настройки формы —
setup_form {"kind": "site", "name": "Сайт школы", "documentIds": ["<id диплома>", "<id благодарности>"], "allowedDomains": ["school5.example.ru"]}В ответе connect.embedHtml — HTML для каждого документа отдельно: две кнопки на одной странице или на разных. Куда вставлять на Тильде, WordPress и Битриксе — в Способах выдачи.
Дальше всё смотрят по проекту:
search_registry {"projectId": "<projectId>"}
api_request {"method": "GET", "path": "/api/registry/analytics", "query": {"projectId": "<projectId>"}}
api_request {"method": "GET", "path": "/api/integrations/tilda/requests", "query": {"integrationId": "<integrationId>"}}REST: POST /api/projects, POST /api/documents (с projectId), POST /api/integrations/tilda, GET /api/registry?projectId=…, GET /api/registry/analytics?projectId=…, GET /api/integrations/tilda/requests. Для формы нужны права «Полный доступ» и возможность tilda в плане; каждая заявка тратит документ из остатка.