Перейти к содержимому
Версия 1.0 ещё не выпущена; проект находится на стадии pre-MVP. См. возможности и ограничения версии 1.0.

Формы на сайте

Секция Форма на странице собирает то, что вводят посетители. Это руководство о том, куда уходят эти отправки: как включить приём, добавить адресатов, читать результаты доставки, стирать значения и принимать подписанный вебхук form.submitted. Как добавить саму форму на страницу, см. Добавить секцию.

  • Нужно право site:infra. Оно есть у встроенной роли admin и у суперадминистратора. Без него раздел Интеграции не показывается.
  • Должен быть развёрнут Worker приёма форм с маршрутом <host>/v1/interactions/* на хосте сайта. Без него формы не принимают отправки. См. Развёртывание изменений.
  • Адресатам email нужна настроенная почта установки (RESEND_API_KEY и MAIL_FROM или ваш почтовый транспорт). См. Секреты для дополнительных функций.
  1. Откройте Настройки → Интеграции. Карточка Формы сайта находится под исходящими вебхуками.
  2. Включите Принимать отправки. Надпись сменится на Формы принимают отправки.
  3. Задайте Хранить отправленное посетителями (дней): от 1 до 365. По умолчанию 30.
  4. При необходимости добавьте общих для сайта адресатов оператора. Нажмите Сохранить настройки форм. Для хранения заявок без доставки адресаты не нужны.

Пока переключатель выключен, каждая форма на сайте отвечает, что не принимает отправки, и ничего не сохраняется. Если выключить его позже, уже поставленные в очередь доставки не отменяются.

У каждого сайта свои настройки. Формы одного сайта никогда не отправляют данные адресатам другого сайта.

Каждую заявку сайт направляет не более чем 5 адресатам оператора. Для отдельной формы можно задать своих адресатов и отдельно включить письмо-подтверждение. Посетители не выбирают адресатов оператора, и на странице они не указаны.

  • Добавить почту добавляет поле Адрес почты. Введите один адрес.
  • Добавить вебхук добавляет поля URL вебхука и Секрет подписи. URL должен начинаться с https:// и не должен содержать имя пользователя или пароль. Секрет — не короче 16 символов (не длиннее 256).

У каждого адресата свой переключатель Отправлять сюда: Вкл. или Приостановлено. Приостановленный адресат не получает новых отправок, а уже стоящие для него в очереди доставки завершаются как Не доставлено. Удалить сначала спрашивает подтверждение. Уже сохранённые отправки остаются, а их доставки этому адресату из очереди завершаются как Не доставлено.

Секрет можно записать, но нельзя прочитать обратно. После сохранения поле показывает Секрет сохранён. Введите новый, чтобы заменить. Оставьте поле пустым, чтобы сохранить текущий секрет. URL, получатель и секрет подписи фиксируются при приёме заявки. Изменения действуют только для новых заявок; повторные отправки используют сохранённые настройки. Пока в очереди есть старые доставки, принимающая сторона должна поддерживать прежний секрет.

Если общие адресаты не заданы, карточка показывает Получатель по умолчанию не задан. Заявки всё равно сохраняются и попадают в список. Доставка адресатам отдельной формы и письма-подтверждения продолжают работать.

Если почта не настроена, карточка показывает В этой установке не настроена почта. Тогда доставки по email завершаются ошибкой и повторяются, как для любого недоступного адресата, а затем завершаются как Не доставлено. После настройки почты нажмите Отправить снова у каждой из них.

Если список отправленных форм не загрузился, нажмите «Повторить» в этом разделе. Обновится только история; несохранённые настройки формы останутся. Сообщение об отсутствии отправленных форм появляется только после успешной загрузки пустого списка.

Карточка Последние отправки показывает 50 последних квитанций о получении данных. Сами значения в списке не видны; откройте квитанцию, чтобы прочитать их, пока они хранятся. Для каждой квитанции указаны:

  • id квитанции и время поступления
  • id страницы, язык и время стирания значений (или Значения стёрты)
  • по строке на доставку: канал, сохранённый при приёме адрес почты или вебхука, состояние и короткое пояснение, например HTTP 503

Адрес виден только пока хранятся значения заявки. После истечения срока или стирания остаются канал и состояние, а адрес скрывается. Для вебхука показываются только протокол, хост и путь, без параметров запроса и секрета подписи. В старых квитанциях без сохранённого адреса указан только канал.

Состояние Значение
Ожидает отправки В очереди. Следующий запуск доставки отправит её.
Будет повтор Последняя попытка завершилась временной ошибкой. Запланирована следующая попытка.
Доставлено Email: почтовый провайдер принял письмо. Вебхук: получатель ответил 2xx.
Не доставлено Остановлено. Получатель отказал, все попытки не удались, адресат удалён или приостановлен, или значения были стёрты раньше.

Доставка запускается раз в минуту, не более 10 доставок на сайт за запуск. Запуск закрепляет за собой каждую доставку непосредственно перед её отправкой, и закрепить её может только один запуск. Закрепление действует 5 минут с этого момента. Каждая отправка, и по email, и вебхуком, ждёт ответа не дольше 10 секунд; после этого она считается неудачной попыткой и повторяется.

Запуск, который задержался на одной доставке, никогда не отправит следующую доставку, если её за это время закрепил или завершил другой запуск. Перед разрешением каждой отправки он проверяет, что значения не стёрты и срок хранения не истёк. Если отправка не завершилась до истечения срока закрепления, следующий запуск может закрепить и отправить эту доставку снова; поздний ответ первого запуска игнорируется. Поэтому одно и то же сообщение может быть отправлено несколько раз: см. Дедупликация.

Отправить снова появляется в строках Будет повтор и Не доставлено. Кнопка сбрасывает счётчик попыток и сразу возвращает доставку в очередь. Уведомление сообщает Будет отправлено снова в течение минуты. Используется та же доставка, поэтому получатель видит тот же receipt и то же значение X-Deewan-Delivery.

Пока обработчик отправляет сообщение, Отправить снова отклоняется с 409 delivery_in_progress и сообщением This delivery is being sent right now. Check it again in a few minutes. Ничего не меняется. Повторите после завершения запуска.

Повторная отправка не поможет, если срок хранения истёк, значения стёрты, адресат удалён или приостановлен. Доставка снова завершится как Не доставлено. Повтор использует получателя, URL, шаблон и секрет подписи, сохранённые при приёме заявки, а не более поздние настройки.

Стереть значения после подтверждения сразу удаляет то, что отправил посетитель. Квитанция остаётся, поэтому повторная отправка тех же данных распознаётся, и ничего не сохраняется дважды. Ещё не отправленные доставки завершаются как Не доставлено.

В редакторе страницы выберите для поля вид Загрузка файлов. В поле Типы файлов перечислите через запятую расширения или точные MIME-типы, например .pdf, .png или application/pdf. Пустое поле разрешает все поддерживаемые форматы изображений и документов. Шаблоны вроде image/* не принимаются. Задайте Максимум файлов (1–5, по умолчанию 1) и Размер одного файла (до 5 МиБ, по умолчанию 5 МиБ). Во всей заявке допускается не более 5 файлов общим размером до 10 МиБ. Настройка Обязательное действует и для загрузки файлов.

Поддерживаются PNG, JPEG, WebP, AVIF, GIF, PDF, DOCX, XLSX, PPTX, ODT, ODS, ODP, RTF, TXT и CSV. Приём проверяет содержимое файла, а не только имя или тип, указанный браузером. Для пустых файлов, неподдерживаемых форматов и превышенных ограничений показывается ошибка у поля. Опубликованная форма позволяет выбирать и отправлять файлы и с JavaScript, и без него. Без JavaScript отказ при проверке перезагружает страницу, и браузер очищает выбор файлов. Перед повторной отправкой выберите файлы заново.

Откройте сохранённую заявку в разделе Последние отправки, чтобы увидеть имя, тип и размер файла, затем нажмите Скачать. Для скачивания нужно то же право site:infra, что и для просмотра заявки; используется выбранный сайт. Вложения хранятся в закрытом хранилище заявок, не попадают в публичную медиатеку и не получают публичных ссылок. Для приёма вложений в установке должен быть настроен закрытый бакет хранения. Один и тот же закрытый бакет R2 должен быть привязан как PRIVATE_MEDIA_BUCKET к Worker приёма форм и Worker CMS, который обслуживает скачивание и очистку по расписанию. Генератор конфигурации приёма форм копирует существующую привязку бакета.

Срок хранения вложений совпадает со сроком заявки. Стереть значения сразу скрывает сведения о файлах и закрывает скачивание. По истечении срока скачивание тоже недоступно, даже если фоновая очистка ещё не запускалась. Задача очистки удаляет файлы из хранилища и повторяет попытки при сбоях. Квитанция остаётся. Уже скачанные файлы и копии у получателей отозвать нельзя.

Стандартное письмо оператору содержит имена и размеры файлов, а не сами вложения. Вебхук может содержать attachments: объект с именами полей и массивами { id, name, type, size }. Это сведения о сохранённых файлах, а не ссылки для скачивания. Переменные пользовательских шаблонов писем по-прежнему содержат только строковые и логические значения полей.

Каждая отправка получает дату стирания при поступлении: время поступления плюс число дней хранения, заданное в тот момент. Если изменить срок позже, это коснётся только новых отправок. По истечении срока значения и скачивание вложений сразу становятся недоступны, даже если очистка ещё не запускалась. Задача очистки работает раз в минуту для активных и отключённых сайтов: удаляет сохранённые значения и файлы, повторяет попытки при сбоях хранилища и оставляет квитанцию. Отключение сайта останавливает доставку, но не очистку по сроку хранения.

При приёме каждая отправка проверяется по опубликованной форме страницы, никогда не по черновику. Один клиент может отправить данные на сайт 10 раз за 10 минут. Повтор той же отправки получает ответ «уже получено»; новая квитанция и новые записи доставки не создаются. Чтобы увидеть каждое состояние для посетителя, выберите форму в редакторе страниц и используйте Предпросмотр; см. Добавить секцию.

По умолчанию тема письма — New form submission, а в теле по одной строке на поле, в порядке формы, в виде label: value. Флажок показывает Yes или No, пустой ответ — —. Если посетитель дал согласие, добавляется строка Consent: given. Последняя строка называет квитанцию, страницу, язык и время поступления.

У почтового провайдера есть 10 секунд, чтобы принять письмо. Если ответа нет, произошла сетевая ошибка или провайдер отказал, отправка повторяется по тем же правилам, что и при сбое вебхука: всего не более 5 попыток. Если провайдер принял письмо, но его ответ потерялся, письмо отправляется снова, поэтому одна отправка может прийти в почтовый ящик дважды. В последней строке стандартного письма стоит идентификатор квитанции. По нему можно распознать повтор. Свой шаблон содержит только настроенный текст: данные квитанции автоматически не добавляются.

Эти адресаты не связаны с исходящими вебхуками. Они задаются только в разделе Формы сайта и отправляют только form.submitted. Контракт из раздела Исходящие вебхуки к ним не относится.

Dee Wan отправляет POST на URL адресата:

Заголовок Значение
Content-Type application/json
X-Deewan-Event form.submitted
X-Deewan-Delivery id доставки: одна отправка одному адресату
X-Deewan-Signature sha256= и HMAC-SHA256 от точных байтов тела в виде шестнадцатеричной строки в нижнем регистре; ключ — секрет подписи адресата

Тело (значения приведены для примера):

{
"event": "form.submitted",
"receipt": "<receipt id>",
"page": "<page id>",
"locale": "en",
"section": "<form section id>",
"submitted_at": "2026-10-13T09:30:00.000Z",
"values": { "email": "visitor@example.com", "subscribe": true },
"labels": { "email": "Email", "subscribe": "Send me news" },
"consent": true,
"attachments": {
"brief": [
{
"id": "<attachment id>",
"name": "brief.pdf",
"type": "application/pdf",
"size": 1024
}
]
}
}
  • receipt — id отправки, тот же, что показывает карточка Последние отправки.
  • values сопоставляет имени каждого поля строку или логическое значение. labels сопоставляет имени каждого поля его подпись в опубликованной форме.
  • submitted_at — момент, когда приём сохранил отправку, в формате ISO-8601 UTC.
  • Любой ответ 2xx — это Доставлено.
  • Нет ответа за 10 секунд, сетевая ошибка, 408, 429 или любой 5xx — повторяется.
  • Любой другой статус окончательный и завершается как Не доставлено. Перенаправления не выполняются, поэтому 3xx тоже окончательный.
  • Не более 5 попыток всего. Ожидание начинается с 1 минуты и удваивается, до 1 часа, со случайным разбросом 50–100 %. Корректный Retry-After (секунды или HTTP-дата) может удлинить ожидание, до 1 часа.
  • Каждая попытка использует URL и секрет подписи, сохранённые при приёме заявки. Изменения действуют только для новых заявок. При этом отключение или удаление адресата останавливает ожидающие доставки.

Проверяйте исходные байты тела до разбора. Пересериализованный JSON не совпадёт с подписью. Подпись покрывает только тело; submitted_at находится внутри него. Отдельного заголовка с меткой времени нет.

async function verifyFormWebhook(secret, rawBody, signatureHeader) {
const hex = signatureHeader?.startsWith("sha256=")
? signatureHeader.slice(7)
: "";
if (!/^[0-9a-f]{64}$/.test(hex)) return false;
const key = await crypto.subtle.importKey(
"raw",
new TextEncoder().encode(secret),
{ name: "HMAC", hash: "SHA-256" },
false,
["verify"],
);
const signature = new Uint8Array(
hex.match(/../g).map((pair) => parseInt(pair, 16)),
);
return crypto.subtle.verify(
"HMAC",
key,
signature,
new TextEncoder().encode(rawBody),
);
}

Учитывайте, что одни и те же данные могут прийти несколько раз. Потерянный ответ 2xx приводит к повтору, Отправить снова повторяет доставку, а отправка, которая длится дольше 5-минутного срока закрепления, может уйти ещё раз. Не рассчитывайте, что запрос будет отправлен ровно один раз. Письма тоже могут повторяться; стандартное письмо содержит идентификатор квитанции в последней строке.

  • Дедуплицируйте по receipt. Он находится в подписанном теле и не меняется ни между попытками, ни при нажатии Отправить снова, ни между адресатами этой отправки.
  • X-Deewan-Delivery тоже не меняется между попытками и при нажатии Отправить снова, но различается у разных адресатов и не подписан. Используйте его, чтобы различать адресатов, но не как единственный ключ.
  • Сохраните receipt и выполните связанные с ним действия одной атомарной операцией, до ответа 2xx. Тогда повтор ничего не изменит.

Добавьте форму на страницу в редакторе страниц или прочитайте контракт исходящих вебхуков для событий контента.

В разделе Настройки → Интеграции → Формы сайта откройте квитанцию, чтобы увидеть сохранённые значения заявки. Настройки, значения и история доставки доступны только с правом site:infra. Истёкшие или удалённые значения нельзя прочитать или отправить повторно, даже если плановая очистка ещё не запускалась. Удаление значений также удаляет сохранённые данные ожидающих отправок.

В разделе Настройки доставки выберите опубликованную форму страницы и задайте её получателей. Без отдельных настроек действуют общие настройки сайта. Пустой список в отдельных настройках отключает доставку оператору для этой формы; письмо-подтверждение настраивается отдельно. Для электронной почты доступны поля Тема и Текст шаблона · {{field}}; Вставить поле добавляет поле формы. Поддерживаются только подстановки {{field}}, без исполняемых выражений. Секреты вебхуков и настройки получателей хранятся на сервере и не попадают в публичные страницы и перенос сайта.

Письмо-подтверждение отправляется на выбранное поле электронной почты, только если в опубликованной форме есть согласие и посетитель его отметил. Для него действуют те же правила хранения, очереди, повторной отправки и удаления, что и для писем оператору. Сообщение об успешной отправке формы не меняется.

Получатель или URL вебхука, шаблон и секрет подписи фиксируются при приёме заявки. Изменение настроек не перенаправляет старые повторные отправки. Отключение или удаление получателя останавливает ожидающие отправки; отключение подтверждений останавливает и их очередь. Непосредственно перед началом отправки сервер повторно проверяет срок хранения и удаление значений. Уже начавшийся запрос к почтовому сервису или вебхуку отозвать нельзя.

Точный повтор уже принятой заявки возвращает прежнюю квитанцию, даже если формы отключены, опубликованная форма изменена или удалена, лимит запросов исчерпан либо сохранённые значения удалены. Новая заявка и новые отправки не создаются. Другие данные с тем же ключом отклоняются. Последняя проверка разрешает одну попытку отправки; удаление значений не может атомарно отозвать уже разрешённый или выполняющийся запрос к внешнему сервису.


Стабильная версия ещё не выпущена (pre-MVP)
Коммит исходного кода: fe23db481c422b40e317b92fc98116b4c0c26a87 (с локальными изменениями)
Дата сборки (UTC): 2026-10-18T09:22:34.630Z
Коммит для обновления: не определён: в рабочей копии есть изменения. Примечания к выпуску