Перейти к содержимому

Одобрение и подписание документов

Помимо согласия на cookie, SDK может записать, что человек одобрил конкретную версию документа — условия использования, договор дистанционной продажи, уведомление о конфиденциальности или документ, сформированный вашей собственной системой.

Код одобрения не входит в cmp.js. Он загружается автоматически при первом вызове одного из двух методов, описанных ниже (или заранее — с помощью data-modules="documents"); см. Файлы сборки и модули по требованию.


Загружает активную версию документа, показывает её в диалоге с кнопками «Принять» и «Отклонить» и записывает одобрение, когда человек принимает документ.

const result = await CMP.showDocumentApproval('distance-sales-agreement', {
language: 'en', // необязательно, по умолчанию — язык SDK
metadata: { order_id: 'ORD-54321' }, // необязательно
approvalToken: tokenFromYourBackend // необязательно / обязательно, см. ниже
});
if (result.success && result.decision === 'accepted') {
continueCheckout(result.consent_token);
} else if (result.decision === 'rejected') {
// человек отклонил документ
} else {
showError(result.error); // { code, status, message }
}
ПараметрОписание
languageЯзык версии документа, которую нужно показать.
metadataПары «ключ — значение», сохраняемые вместе с записью (объединяются с CMP.setMetadata).
approvalTokenОдноразовый токен одобрения, выпущенный вашим бэкендом.

Для обратной совместимости простой объект без какого-либо из этих ключей рассматривается как metadata.

Отклонение закрывает диалог и вызывает событие document:rejected; запись на сервер не отправляется. Если сохранение завершается временной ошибкой, диалог остаётся открытым и человек может снова нажать «Принять» — повторная попытка использует тот же ключ идемпотентности (и тот же токен).

2. CMP.approveDocument(slug, options) — ваш собственный интерфейс

Заголовок раздела «2. CMP.approveDocument(slug, options) — ваш собственный интерфейс»

Записывает одобрение, ничего не показывая, — для флажка в вашей форме, вашего собственного средства просмотра договоров или панели для подписи, которую вы отображаете сами.

const result = await CMP.approveDocument('terms-of-service', {
approvalToken: tokenFromYourBackend,
metadata: { order_id: 'ORD-54321' }
});
ПараметрОтправляется какОписание
version_iddocument_version_idВерсия, которую нужно одобрить. Если параметр не указан, SDK определяет активную версию для language.
version—Обозначение версии, возвращаемое в результате, когда вы передаёте version_id.
languagelanguageЯзык версии.
decisiondecision'accepted' (по умолчанию) или 'rejected'.
visitor_idvisitor_idВаш идентификатор человека (не более 100 символов). Игнорируется, когда используется токен одобрения, — вместо него сохраняется subject токена.
approvalTokenapproval_tokenОдноразовый токен одобрения.
document_content_base64custom_document_contentСодержимое документа, сформированного вашей системой (HTML, обычный текст или PDF; примерно до 500 КБ в декодированном виде).
document_mime_typecustom_document_mime_typetext/html, text/plain или application/pdf.
signatureполя верхнего уровняСм. Поля подписи.
metadatametadataПары «ключ — значение», сохраняемые вместе с записью.

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


Браузерный SDK подписывает свои запросы API-ключом сайта, который виден в исходном коде вашей страницы. Поэтому одобрение документа, отправленное из браузера, доказывает лишь то, что его отправил кто-то, имеющий доступ к вашей странице; имя или адрес электронной почты в нём — это то, что было введено.

Токен одобрения позволяет вашему бэкенду поручиться за то, кто именно одобряет документ:

  1. Ваш бэкенд, которому известен вошедший в систему пользователь, вызывает POST /tool/v1/s2s/approval-tokens (см. REST API) и получает токен (hat_…).
  2. Вы передаёте токен на страницу и отдаёте его SDK как approvalToken.
  3. SDK отправляет его как поле верхнего уровня approval_token. Сервер атомарно погашает токен, берёт сведения о личности человека из токена, а не из браузера, и сохраняет запись с identity_assurance: tenant_attested.

Правила:

  • Токен действителен для одного сайта и одного документа (при необходимости — для одной версии), в течение ограниченного времени (по умолчанию 10 минут, не более 1 часа) и один раз.
  • Документ можно настроить в панели управления так, чтобы он требовал токен. Для такого документа SDK сразу, не отправляя запроса, возвращает ошибку, если токен не передан: error.code = "APPROVAL_TOKEN_REQUIRED". Сервер применяет то же правило.
  • Коды сервера передаются без изменений: APPROVAL_TOKEN_REQUIRED, APPROVAL_TOKEN_INVALID (неизвестен, истёк, уже использован или выпущен для другого сайта/документа), APPROVAL_TOKEN_CONFLICT (поле подписанта или содержимое документа, отправленные браузером, противоречат тому, за что ручается токен).
  • При сбое сети или ответе 5xx SDK повторяет попытку с тем же токеном и тем же ключом идемпотентности; сервер рассматривает повтор как тот же самый запрос. После окончательного ответа 4xx повторных попыток нет, а одобрения никогда не сохраняются в офлайн-очереди. Чтобы попробовать снова, выпустите новый токен.

approveDocument принимает объект signature для одобрений, полученных с нарисованной подписью или явным заявлением. SDK не содержит панели для подписи: вы сами отображаете панель (или флажок с заявлением) и передаёте результат.

await CMP.approveDocument('service-contract', {
approvalToken: tokenFromYourBackend,
signature: {
image_base64: canvas.toDataURL('image/png'),
mime_type: 'image/png',
signer_name: 'Jane Doe',
signer_email: '[email protected]',
declaration_text: 'I have read and accept the service contract.',
input_type: 'touch',
stroke_count: 14,
drawing_duration_ms: 3200,
screen_resolution: '390x844'
}
});
ПолеОтправляется какПримечания
image_base64signature_imagePNG, JPEG или WebP; примерно до 150 КБ в декодированном виде.
mime_typesignature_mime_type
signer_name, signer_email, signer_phone, signer_id_numberте же именаТо, что подписант сообщает о себе, если только за эти сведения не ручается токен одобрения.
declaration_textdeclaration_textФраза, с которой человек согласился (не более 1000 символов).
input_typeinput_typetouch, mouse или pen.
stroke_count, drawing_duration_ms, strokes_dataте же именаТелеметрия рисования.
screen_resolutionscreen_resolution

Все эти значения отправляются как поля верхнего уровня запроса, а не внутри metadata. Поля otp_verified / otp_reference из браузера не принимаются; они учитываются только на маршруте server-to-server или через токен одобрения.

Что здесь означает «простая электронная подпись»

Заголовок раздела «Что здесь означает «простая электронная подпись»»

Запись, созданная таким образом, является простой электронной подписью: это данные в электронной форме (нарисованное изображение, заявление, технический контекст), которые присоединены к конкретной версии документа и которые подписант использовал для подписания. Это не усиленная и не квалифицированная электронная подпись — подписанту не выдаётся сертификат, и HashEntry не проверяет личность подписанта.

Что показывает доказательство:

  • какая версия документа (по хешу содержимого) была одобрена, когда, с какого IP-адреса и user agent и с какими заявленными сведениями о подписанте;
  • что запись не изменялась с момента её создания (см. Офлайн-проверка доказательств);
  • насколько надёжно подкреплена личность — в поле identity_assurance:
ЗначениеСмысл
self_declaredСведения о подписанте поступили из браузера. Их никто не проверял.
tenant_attestedЗа человека поручился ваш бэкенд — либо с помощью одноразового токена одобрения, либо заявив о выполненной проверке OTP на маршруте server-to-server. Это заверение — ваше: HashEntry фиксирует, что вы это засвидетельствовали, а не то, что это проверил HashEntry.

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


Если сервер отвечает 409 CONFIG_OUTDATED, SDK заново читает активную версию документа:

  • не изменилась (кеш сервера был холодным) → тот же запрос отправляется ещё один раз;
  • изменилась → одобрение не отправляется повторно. Результат — success: false с error.code = "DOCUMENT_VERSION_CHANGED", и срабатывает событие document:error.

Во втором случае покажите документ снова (человек не видел новую версию) и получите новое одобрение — с новым токеном, если вы используете токены.


CMP.on('document:approved', ({ slug, version, consentId }) => {});
CMP.on('document:rejected', ({ slug, version }) => {});
CMP.on('document:error', ({ slug, version, code, status, message }) => {});
error.codeЧто делать
MODULE_LOAD_FAILEDФайл модуля не удалось загрузить (сеть, блокировщик рекламы, CSP). Вызовите метод ещё раз, чтобы повторить попытку.
DOCUMENT_NOT_FOUND, VERSION_NOT_FOUNDПроверьте slug, а также то, что документ прикреплён к сайту и что у него есть активная версия на запрошенном языке.
APPROVAL_TOKEN_REQUIREDВыпустите токен на своём бэкенде и передайте его.
APPROVAL_TOKEN_INVALID, APPROVAL_TOKEN_CONFLICTВыпустите новый токен; убедитесь, что поля подписанта соответствуют токену.
DOCUMENT_VERSION_CHANGEDПокажите документ снова.
CONFIG_OUTDATEDПереданная вами версия не является активной, и перепроверить её не удалось.
NETWORK_ERROR, TIMEOUT, RATE_LIMIT_EXCEEDED, QUEUE_OVERLOADEDВременная ошибка. Дайте человеку возможность попробовать ещё раз.
VALIDATION_ERROR и ошибки размера (SIGNATURE_IMAGE_TOO_LARGE, CUSTOM_DOCUMENT_TOO_LARGE, …)Исправьте запрос.

Считайте одобрение данным только тогда, когда result.success === true. Сохраняйте result.consent_token: он идентифицирует запись для последующей проверки и экспорта доказательств.