Подготавливаем страницу…
Подготавливаем страницу…
Готовый файл-прокси на PHP: один API-ключ обслуживает все чекбоксы согласия в форме, и на обработку ПДн, и на маркетинг. Тот же production-паттерн работает на 1opd.ru и у клиентов платформы. Время подключения около 30 минут.
Напрямую в произвольный API Tilda данные не отправляет, зато умеет звать Webhook по указанному URL. Отсюда схема из четырёх шагов:
Пользователь → Tilda-форма → Tilda Webhook → ВАШ proxy.php → 1ОПД (галочка (forms_scope[] (POST согласия) в форме) /api/v2/ create- agreement)
Один proxy.php на сервере клиента смотрит, какие чекбоксы субъект отметил в форме, и шлёт в 1ОПД столько POST-запросов, сколько чекбоксов активно: обычно один на согласие на обработку ПДн и, если он есть, второй на маркетинг. Все чекбоксы сайта при этом обслуживает один API-ключ 1ОПД, такой ключ называют multi-form (см. Шаг 02).
sk_ (secret, только server-side) forms_scope=[id1, id2, …] , и в каждом запросе передаёте form_id в body.Ключ создаёт менеджер 1ОПД и передаёт вам один раз. Все endpoints → API Reference
Прочитайте один раз: дальше в инструкции эти слова уже не будут пугать.
Здесь лежат формы согласия и их form_id.
Зайдите на lk.v2.1opd.ru под учётной записью, выданной менеджером 1ОПД.
Один ключ на все чекбоксы сайта. Полный ключ показывается один раз при создании.
API-ключ создаёт менеджер 1ОПД. Просите именно multi-form ключ: он пишет сразу в несколько форм согласия, например одновременно в «обработку ПДн» и в «маркетинг». Ключ с forms_scope=[1, 2] работает с формами 1 и 2, отдельный ключ на каждую форму выпускать не нужно.
[1, 2] IP вашего хостинга (опц) sk_) для сайта mydomain.ru, с forms_scope на все формы согласия (обработка ПДн и маркетинг)».sk_ и 64 hex-символов. Сохраните её сразу: повторно 1ОПД её не покажет, в БД лежит только хеш.form_id, которые обслуживает ключ. Например: 1 для «Согласия на обработку ПДн», 2 для «Маркетинговых коммуникаций». Они понадобятся в Шаге 04.forms_scope=[1]. PHP-файл из Шага 04 настраивается так же.sk_abc12…, а не ключ целиком: секрет остаётся в proxy.php на стороне клиента. При утрате менеджер выпустит новый ключ и отзовёт прежний. sk_abc1234567... и список form_id (например: 1 = обработка, 2 = маркетинг).В ЛК → раздел «Интеграция» → Формы → form_id.
В ЛК 1ОПД откройте раздел «Интеграция» в левой панели и найдите список форм: в названии каждой стоит её form_id=N. Это и есть номер, который вы передаёте в поле form_id в body POST-запроса.
form_id какой цели обработки соответствует. Например: 1 для основного согласия на обработку ПДн, 2 для маркетинга.sk_… и таблица «чекбокс → form_id». Можно собирать proxy.php.Один файл, приёмник Tilda Webhook. Правятся только переменные сверху.
Скопируйте код ниже целиком, отредактируйте 4 блока «НАСТРОЙКИ» (API-ключ, чекбоксы→form_id, маппинг полей, поле-идентификатор) и загрузите файл на веб-сервер по адресу вида https://mydomain.ru/opd/proxy.php.
opd/ в корне сайта. Положите туда файл proxy.php с кодом ниже.opd/ права 755. <?php
// proxy.php — приёмник Tilda Webhook для отправки согласий в 1ОПД (152-ФЗ).
// Положите этот файл на ваш веб-сервер (PHP 7.4+) и пропишите URL
// в Tilda → Настройки сайта → Формы → Сервис «Webhook».
//
// ОДИН файл обслуживает ВСЕ чекбоксы согласия в форме Tilda через ОДИН
// API-ключ. Главное — чтобы у ключа в 1ОПД в forms_scope были все нужные
// form_id (это делает менеджер 1ОПД при создании ключа).
// ── НАСТРОЙКИ — отредактируйте эти 4 блока ───────────────────────────────
// 1. API-ключ 1ОПД. Получите у менеджера ОДИН раз — в ЛК виден только префикс.
$api_key = 'sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
// 2. Endpoint 1ОПД (можно оставить как есть).
$endpoint = 'https://app.1opd.ru/api/v2/create-agreement';
// 3. Какой чекбокс Tilda какой form_id 1ОПД соответствует.
// Имена слева ('Checkbox', 'Checkbox_2') — это поле name=... у чекбокса
// в форме Tilda (см. Шаг 06). Числа справа — form_id из ЛК 1ОПД (см.
// Шаг 03). Если у вас один чекбокс — оставьте только первую строку.
$consent_form_ids = [
'Checkbox' => 1, // основной чекбокс «Согласен с обработкой ПДн»
'Checkbox_2' => 2, // дополнительный «Маркетинговая рассылка» (опц)
];
// 4. Маппинг полей Tilda → имена в 1ОПД (как заведены в «Реестре процессов»).
$field_mapping = [
'Name' => 'first_name',
'Email' => 'email',
'Phone' => 'phone_number',
// 'Company' => 'company_name', // раскомментируйте при необходимости
];
// Какое поле Tilda — главный идентификатор субъекта (для дедупа в 1ОПД).
$hash_field = 'Email';
// ── ЛОГИКА (обычно править не нужно) ─────────────────────────────────────
$tilda_data = $_POST;
if (empty($tilda_data)) {
$tilda_data = json_decode(file_get_contents('php://input'), true) ?? [];
}
$log_file = __DIR__ . '/opd-debug.log';
function opd_log(string $line): void {
global $log_file;
file_put_contents($log_file, date('Y-m-d H:i:s') . ' ' . $line . "\n", FILE_APPEND);
}
$formatted_fields = [];
foreach ($tilda_data as $key => $value) {
if (!isset($field_mapping[$key])) continue;
if (is_array($value)) $value = implode(', ', $value);
$formatted_fields[] = ['field' => $field_mapping[$key], 'value' => (string)$value];
}
$hash_value = (string)($tilda_data[$hash_field] ?? '');
if ($hash_value === '') {
opd_log("SKIP: пустой hash_field ({$hash_field}) — субъект не идентифицируется.");
http_response_code(200);
exit;
}
$sent_count = 0;
foreach ($consent_form_ids as $checkbox_name => $form_id) {
if (($tilda_data[$checkbox_name] ?? '') !== 'yes') {
opd_log("SKIP form_id={$form_id} ({$checkbox_name}): чекбокс не активен.");
continue;
}
$payload = [
'form_id' => $form_id,
'hash_field' => $hash_value,
'fields' => $formatted_fields,
];
$ctx = stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\nAPI-KEY: {$api_key}\r\n",
'content' => json_encode($payload, JSON_UNESCAPED_UNICODE),
'ignore_errors' => true,
'timeout' => 10,
],
]);
$response = @file_get_contents($endpoint, false, $ctx);
$code = 'no-response';
if (isset($http_response_header)) {
foreach ($http_response_header as $h) {
if (strpos($h, 'HTTP/') === 0) { $code = $h; break; }
}
}
opd_log("SEND form_id={$form_id} ({$checkbox_name}) -> {$code} | response: {$response}");
$sent_count++;
}
opd_log("DONE: отправлено {$sent_count} согласий для {$hash_field}={$hash_value}.");
http_response_code(200);
echo json_encode(['ok' => true, 'sent' => $sent_count]);
$consent_form_ids первую строку и попросите у менеджера ключ с forms_scope=[1]. Остальное в файле менять не нужно.proxy.php открывается по адресу https://mydomain.ru/opd/proxy.php и в браузере отдаёт JSON {"ok":true,"sent":0}: без данных пересылать нечего.Tilda → Настройки сайта → Формы → «Добавить сервис» → «Webhook».
В Tilda откройте сайт → «Настройки сайта» (вверху справа) → «Формы» → блок «Подключение к сервисам приёма данных» → «Webhook».
proxy.php: полный URL с https://.Обязательный чекбокс «Согласие на обработку ПДн» и опциональный «Маркетинг».
В Tilda откройте блок с формой → «Контент» → раздел «Поля». Добавьте поле типа «Checkbox», имя ему Tilda присвоит сама: Checkbox. В текст поля впишите формулировку согласия. Она обязана точно совпадать с формулировкой в PDF-документе, загруженном в 1ОПД.
① Основной чекбокс: согласие на обработку ПДн (обязательный)
Checkbox (имя по умолчанию) «Даю согласие на обработку персональных данных в соответствии с Политикой обработки персональных данных».
Required = Да. Без отметки форма не отправляется: согласие субъект даёт своей волей и в своём интересе (ст. 9 ч. 1 152-ФЗ).
② Опциональный чекбокс: маркетинговая рассылка (добровольный)
Checkbox_2 (Tilda сама нумерует второй чекбокс) «Даю согласие на получение информационной и рекламной рассылки».
Required = Нет. Согласие на рассылку субъект даёт отдельно от согласия на обработку.
proxy.php обязаны совпадать буква в букву, включая регистр. Поле СогласиеПДн в Tilda означает тот же СогласиеПДн в массиве $consent_form_ids.Checkbox и Checkbox_2 либо свои, тогда поправьте PHP.required, маркетинговый нет.Заполните форму тестовым email. Сверьте debug.log и ЛК 1ОПД.
Откройте опубликованную страницу с формой. Заполните Name / Email / Phone, отметьте оба чекбокса и нажмите «Отправить».
opd/opd-debug.log. В нём должны быть строки:2026-05-21 13:42:01 SEND form_id=1 (Checkbox) -> HTTP/1.1 200 OK | response: {"hash":"..."}
2026-05-21 13:42:01 SEND form_id=2 (Checkbox_2) -> HTTP/1.1 200 OK | response: {"hash":"..."}
2026-05-21 13:42:01 DONE: отправлено 2 согласий для Email=test@example.ru. test@example.ru.debug.log есть строка «SEND form_id=… → 200 OK» либо «→ 202 Accepted»: оба кода означают приём.Самый частый вопрос при подключении: как одним ключом обслуживать и обработку ПДн, и маркетинг, и обратную связь.
Один ключ на одну форму согласия. Форма с двумя чекбоксами требовала двух ключей и двух PHP-файлов либо усложнённого JS.
Один ключ с forms_scope=[1, 2, 5] закрывает несколько форм. В каждом POST-запросе вы указываете form_id явно, и бэкенд направляет запись в нужную форму. PHP-файл при этом один на весь сайт.
Сценарий 1: одно согласие закрывает несколько форм сбора. На сайте стоят «Заказать звонок», «Обратная связь» и ещё пара форм, и цель обработки у всех одна (например, обработка обращений субъектов). Привязка идёт к согласию, а не к кнопке. Достаточно одного multi-form ключа со scope этого согласия, а в каждом запросе вы проставляете один и тот же form_id.
Сценарий 2: в одной форме два чекбокса под разные согласия. Обработка ПДн и маркетинг составляют разные цели обработки. Один multi-form ключ с forms_scope=[1, 2] покрывает обе формы: в каждом запросе вы передаёте свой form_id (1 для обработки, 2 для маркетинга), и бэкенд по scope направляет запись в нужный реестр.
Зачем тогда «выбранные формы» (per-form scope)? Для изоляции отдельных точек сбора, когда один ключ не должен писать сразу в несколько форм. Например, лендинг партнёрской кампании получает свой ключ с forms_scope=[5], и его утечка не затронет данные основной формы. Передавать form_id в body всё равно обязательно: бэкенд проверит вхождение в scope ключа и при несовпадении вернёт 403. Отказ виден в журнале audit_log в ЛК клиента.
form_id.proxy.php добавляете строку в $consent_form_ids, например 'Checkbox_3' => 5.Checkbox_3 и нужным текстом.Когда нужен второй ключ: когда в одном кабинете 1ОПД ведутся разные юридические лица. Один ключ принадлежит одному юрлицу. Для холдинга с формами разных компаний на одном сайте архитектуру подберёт менеджер.
Когда поставить PHP-файл на сервер негде, остаётся упрощённый JS-вариант: он перехватывает submit формы и шлёт fetch в 1ОПД прямо из браузера. Ограничения:
pk_-ключ, и он виден в исходниках страницы. Защита одна: allowed_origins (CORS).debug.log здесь нет.Код вставляют в Tilda → Настройки сайта → «Ещё» → HTML-блок:
<script>
// Запасной вариант — если у вас НЕТ собственного PHP-сервера для прокси.
// Работает только с pk_ ключом + Origin whitelist по вашему домену.
// ВАЖНО: основная production-схема — это PHP-прокси через Tilda Webhook
// (см. Шаги 04–07). JS-снiпет ниже годится для прототипа/демо.
document.addEventListener('submit', function (e) {
if (!e.target.matches('form[name="form12345"]')) return; // имя вашей формы
var fd = new FormData(e.target);
var fields = Array.from(fd.entries())
.filter(function (p) { return ['Name','Email','Phone'].indexOf(p[0]) >= 0; })
.map(function (p) { return { field: p[0].toLowerCase(), value: String(p[1]) }; });
function sendAgreement(formId) {
return fetch('https://app.1opd.ru/api/v2/create-agreement', {
method: 'POST',
headers: {
'API-KEY': 'pk_xxxxxxxxxxxxxxxxxxxx',
'Content-Type': 'application/json'
},
body: JSON.stringify({
form_id: formId,
hash_field: fd.get('Email') || '',
fields: fields
})
});
}
if ((fd.get('Checkbox') || '') === 'yes') sendAgreement(1); // основное согласие
if ((fd.get('Checkbox_2') || '') === 'yes') sendAgreement(2); // маркетинг
});
</script> Перед использованием запросите у менеджера 1ОПД ключ типа pk_ (publishable) и внесите в allowed_origins свой домен и https://*.tilda.ws для предпросмотра.
Самые частые проблемы и что с ними делать. Решает 95% случаев.
Проверьте по порядку:
Проверьте 3 пункта:
proxy.php в $api_key стоит полный ключ: префикс sk_ и 64 hex-символа.API-KEY: и ключом в HTTP-заголовке нет лишних пробелов и переносов (в шаблоне выше всё корректно). Откройте proxy.php → $consent_form_ids и сверьте числа справа с номерами форм в ЛК 1ОПД → раздел «Согласия». Для новой формы попросите менеджера добавить её form_id в forms_scope действующего ключа.
Откройте опубликованный сайт → правый клик на чекбоксе → «Посмотреть код» и найдите атрибут name="…". Это имя обязано точно совпадать с ключом в массиве $consent_form_ids в PHP-файле.
Проверьте и значение чекбокса: по умолчанию Tilda ставит yes. Если вы его меняли, поправьте сравнение в PHP (=== 'yes').
В $field_mapping укажите соответствие имён Tilda именам полей в 1ОПД (как они заведены в «Реестре процессов»). Например: 'Name' => 'first_name', 'Phone' => 'phone_number'.
Опубликуйте сайт через «Опубликовать». Webhook'и работают только на опубликованном (custom) домене, а не в превью *.tilda.cc.
chmod 644 proxy.php и chmod 755 opd/.Откройте ЛК → «Интеграция»: персональные snippet'ы + готовый HTML-чекбокс с авто-ссылками на согласие и политику + кнопка «IP-whitelist» для каждого ключа.
Открыть ЛК →Запросите тестовый доступ: выдаём ключ под ваш домен и помогаем подключиться.
Связаться →Все endpoints, коды ошибок, форматы HMAC/Origin/IP. Таблица «какую защиту выбрать».
Открыть →Успехом считаются и 200, и 202. Проверка «строго 200» отметит ошибкой согласие, которое 1ОПД принял и доставит.
В массиве fields передавайте любые из 28 полей ниже, имя поля стоит в столбце field. Обязательное одно: email, он же идентификатор субъекта (hash_field). Остальные 27 опциональны, незаполненное поле не передавайте. Все значения 1ОПД шифрует на своей стороне (AES-256-GCM). Актуальный список полей конкретной формы отдаёт POST /api/v2/get-fields.
| field | Название | Примечание |
|---|---|---|
email | Электронная почта | обязательное · идентификатор (hash_field) |
first_name | Имя | опциональное |
last_name | Фамилия | опциональное |
sur_name | Отчество | опциональное |
birth_date | Дата рождения | опциональное |
phone_number | Номер телефона | опциональное |
birth_place | Место рождения | опциональное |
registration_address | Адрес регистрации | опциональное |
delivery_address | Адрес доставки | опциональное |
passport_details | Паспортные данные | опциональное |
inn | ИНН | опциональное |
snils | СНИЛС | опциональное |
bank_details | Банковские реквизиты | опциональное |
account_vk | Аккаунт VK | опциональное |
account_telegram | Аккаунт Telegram | опциональное |
account_instagram | Аккаунт Instagram | опциональное |
account_facebook | Аккаунт Facebook | опциональное |
account_viber | Аккаунт Viber | опциональное |
account_ok | Аккаунт OK | опциональное |
account_whatsapp | Аккаунт WhatsApp | опциональное |
job_title | Должность | опциональное |
organization_name | Название организации | опциональное |
field_of_activity | Сфера деятельности | опциональное |
city | Город | опциональное |
mattermost_account | Аккаунт Mattermost | опциональное |
slack_account | Аккаунт Slack | опциональное |
ms_teams_account | Аккаунт MS Teams | опциональное |
sex | Пол | значения male / female · в карточках: «мужчина» / «женщина» |
Набор одинаков для всех способов интеграции (Tilda, WordPress, Bitrix, браузерный JS, server-side API). Каждое значение приходит строкой длиной до 5000 символов.