Webhooks
Отправляйте каждый ответ на ваш собственный адрес в формате JSON сразу, как только он приходит.
Один POST на каждый ответ
Отправляется, как только ответ сохранён, и респонденту не приходится ждать.
Стабильная структура JSON
Публичные названия типов и постоянные ID полей: переименование вопроса никогда не сломает ваш код.
10 секунд, одна попытка
Fillio ждёт ваш эндпоинт десять секунд и больше не повторяет попытку.
Как включить webhook
Откройте форму, перейдите на вкладку «Настройки» и включите Webhook. Вставьте адрес, который должен получать ответы; Fillio сохранит его через мгновение после того, как вы перестанете печатать, и подтвердит это на экране. У каждой формы один адрес, а выключение переключателя стирает его.
Адрес должен быть HTTPS
Fillio обращается только к адресам, начинающимся с https://. Адрес http:// поле настроек примет, но вызван он не будет, то есть webhook будет выглядеть сохранённым и молча ничего не доставлять.
Адреса внутри частной сети тоже отклоняются: любой хост в 10.x, 127.x, 169.254.x, 172.16-31.x или 192.168.x, любой адрес IPv6, а также любое имя localhost или оканчивающееся на .local либо .internal. Ваш эндпоинт должен быть доступен из публичного интернета.
Запрос
POST с телом в JSON. Вместе с ним приходят четыре заголовка.
| Заголовок | Описание |
|---|---|
| Content-Type: application/json | Тело всегда в JSON. |
| User-Agent: Fillio Webhooks/1.0 | Обозначает отправителя как Fillio. Это удобно, когда один эндпоинт слушает сразу несколько сервисов. |
| X-Fillio-Event: FORM_RESPONSE | Название события. FORM_RESPONSE остаётся единственным значением, которое Fillio сегодня отправляет. |
| X-Fillio-Event-Id | Новый UUID для этой доставки, продублированный в теле как eventId. |
Полезная нагрузка
Оболочка с описанием события и объект data с описанием ответа.
{
"eventId": "8f2c1d7a-4b09-4e5c-9a13-6d0f8b2e77c4",
"eventType": "FORM_RESPONSE",
"createdAt": "2026-08-26T09:14:22.481Z",
"data": {
"responseId": "Qh3Rk9wZm1sVtY7cN2xP",
"formId": "7bTn4Kq2Wx",
"formName": "Workshop signup",
"createdAt": "2026-08-26T09:14:22.481Z",
"fields": [
{
"key": "V1StGXR8_Z5jdHi6B-myT",
"label": "Full name",
"type": "INPUT_TEXT",
"value": "Mira Kaya"
},
{
"key": "kM4pQz7LxAe2Rn0BsTvUw",
"label": "Which session?",
"type": "MULTIPLE_CHOICE",
"value": "c9XbNf3JdQ",
"options": [
{ "id": "c9XbNf3JdQ", "text": "Morning" },
{ "id": "eR2mYt8KpL", "text": "Afternoon" }
]
},
{
"key": "zA6cWn1FyH4tXd9QrLbEs",
"label": "How likely are you to recommend us?",
"type": "LINEAR_SCALE",
"value": 9
}
]
}
}| Свойство | Описание |
|---|---|
| eventId | Уникальный ID этой доставки. |
| eventType | Всегда FORM_RESPONSE. |
| createdAt | Когда ответ был отправлен: метка времени ISO 8601 в UTC. |
| data.responseId | ID сохранённого ответа. |
| data.formId | ID формы, тот же, что стоит в её публичной ссылке. |
| data.formName | Заголовок формы обычным текстом, без какого-либо форматирования. |
| data.fields | По одной записи на каждый отвеченный вопрос. |
Внутри fields
В каждой записи четыре свойства, а у вопроса с вариантами есть пятое.
| Свойство | Описание |
|---|---|
| key | Постоянный ID вопроса. Он переживает любые правки формулировки, поэтому сопоставляйте именно по нему, а не по подписи. |
| label | Вопрос в том виде, в каком он написан в редакторе. |
| type | Тип вопроса из списка ниже. |
| value | Ответ в том виде, в каком его хранит этот вопрос. |
| options | Только у вопросов с вариантами: ID и текст каждого варианта, чтобы вы могли превратить ответ обратно в подпись. |
Приходят только отвеченные вопросы
Вопрос, которого респондент не коснулся, в массиве отсутствует, а не приходит с пустым значением; вопрос, скрытый условной логикой, не появляется вовсе. Ищите каждый ответ по его key, а не по позиции и не по фиксированному числу записей.
В ответах на вопросы с выбором приходят ID, а не подписи
В ответе на выпадающий список или переключатели приходит ID выбранного варианта, а в ответе на флажки, множественный выбор или ранжирование приходит массив ID вариантов. Сопоставляйте их со списком options в той же записи. В ответе на ранжирование сохраняется порядок, в котором респондент расставил элементы.
Вариант «Другое»
Когда респондент пишет в поле «Другое», значением становится не ID варианта, а текст __OTHER__: и следом то, что он ввёл. Уберите этот префикс, чтобы прочитать ответ.
"value": "__OTHER__:Heard about it from a friend"Файлы и подписи
В ответе на загрузку файла приходит ссылка для скачивания файла из хранилища Fillio. В ответе-подписи приходит data URL с PNG в base64, который можно сохранить или показать напрямую.
Типы полей
Тип остаётся стабильным публичным именем, поэтому изменения внутри Fillio никогда не доходят до вашей интеграции. Всё, что Fillio не может сопоставить, приходит как INPUT_TEXT.
| Тип | Вопрос | Значение |
|---|---|---|
| INPUT_TEXT | Краткий ответ | Текст |
| TEXTAREA | Развёрнутый ответ | Текст |
| INPUT_EMAIL | Текст | |
| INPUT_PHONE_NUMBER | Номер телефона | Текст |
| INPUT_NUMBER | Число | Число текстом, ровно как оно было введено |
| INPUT_LINK | Ссылка | Текст |
| INPUT_DATE | Дата | Дата в формате YYYY-MM-DD |
| INPUT_TIME | Время | Время в формате HH:MM по 24-часовым часам |
| DROPDOWN | Выпадающий список | Один ID варианта |
| MULTIPLE_CHOICE | Переключатель | Один ID варианта |
| CHECKBOXES | Флажок | Массив ID вариантов |
| MULTI_SELECT | Множественный выбор | Массив ID вариантов |
| RATING | Звёздный рейтинг | Число |
| LINEAR_SCALE | Линейная шкала | Число |
| RANKING | Ранжирование | Массив ID вариантов в порядке, заданном респондентом |
| FILE_UPLOAD | Загрузка файла | Ссылка для скачивания |
| SIGNATURE | Подпись | Data URL с PNG в base64 |
Если ваш эндпоинт не отвечает
Fillio ждёт десять секунд. Таймаут, ошибка соединения или любой статус за пределами диапазона 2xx считаются неудачной доставкой. И на этом всё: повторов нет, и очереди, из которой можно переиграть, тоже.
На сам ответ это никак не влияет. Он сохраняется до того, как отправляется запрос, и остаётся в вашей панели, что бы ни делал ваш эндпоинт, так что панель остаётся полной записью даже при потерянной доставке.
Подписи нет
Fillio не подписывает запрос и не отправляет общий секрет, поэтому само по себе тело не доказывает, откуда оно пришло. Если вашему эндпоинту нужна уверенность, дайте ему адрес, который знаете только вы: длинный, неугадываемый путь или строку запроса. А всё, что приходит по другому адресу, считайте недоверенным.
У каждой доставки есть свой ID события: он стоит и в заголовке X-Fillio-Event-Id, и в теле. Проще всего сделать эндпоинт безопасным при повторном вызове, записывая те ID, что вы уже обработали.
Направьте webhook на любой сервис для просмотра запросов и один раз отправьте собственную форму. Вы увидите тело запроса ровно таким, каким его шлёт ваша форма, с вашими же ID полей. Быстрее написать сопоставление на своей стороне уже не получится.