Перейти к основному содержимому
Certyneo
Публичное API v1

Интегрируйте электронную подпись в вашу систему

Отправляйте конверты, отслеживайте подписи, получайте вебхуки. Простое REST API, OpenAPI 3.0, примеры curl/Node/Python — всё необходимое для интеграции Certyneo с вашим HRIS, CRM или бизнес-приложением за несколько часов.

Быстрый старт

Три шага: создайте API ключ в параметрах, закодируйте ваш PDF в base64, отправьте. Ответ содержит `signUrl`, который вы можете поделить прямо с получателем.

cURLbash
# 1. Upload the PDF (multipart) and capture the returned document id.
DOC_ID=$(curl -s -X POST https://certyneo.com/api/v1/documents \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -F "file=@contrat.pdf" | jq -r .id)

# 2. Create a DRAFT envelope referencing the uploaded document.
ENV_ID=$(curl -s -X POST https://certyneo.com/api/v1/envelopes \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d "{
    \"subject\": \"Contrat de prestation\",
    \"documentIds\": [\"$DOC_ID\"],
    \"recipients\": [
      { \"email\": \"client@example.com\", \"name\": \"Marie Dubois\", \"role\": \"SIGNER\" }
    ]
  }" | jq -r .id)

# 3. Dispatch the envelope — this sends the invitation email/SMS.
curl -X POST https://certyneo.com/api/v1/envelopes/$ENV_ID/send \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx"
JavaScript / Nodets
// Plain fetch, no SDK to install.
const auth = { Authorization: `Bearer ${process.env.CERTYNEO_API_KEY}` };

// 1. Upload the PDF (multipart).
const fd = new FormData();
fd.append("file", new Blob([pdfBuffer], { type: "application/pdf" }), "contrat.pdf");
const doc = await fetch("https://certyneo.com/api/v1/documents", {
  method: "POST", headers: auth, body: fd,
}).then((r) => r.json());

// 2. Create the DRAFT envelope.
const envelope = await fetch("https://certyneo.com/api/v1/envelopes", {
  method: "POST",
  headers: { ...auth, "Content-Type": "application/json" },
  body: JSON.stringify({
    subject: "Contrat de prestation",
    documentIds: [doc.id],
    recipients: [
      { email: "client@example.com", name: "Marie Dubois", role: "SIGNER" },
    ],
  }),
}).then((r) => r.json());

// 3. Dispatch — this triggers the invitation channel for every recipient.
await fetch(`https://certyneo.com/api/v1/envelopes/${envelope.id}/send`, {
  method: "POST", headers: auth,
});
console.log(envelope.id);
Pythonpython
import os, requests

auth = {"Authorization": f"Bearer {os.environ['CERTYNEO_API_KEY']}"}

# 1. Upload the PDF (multipart).
with open("contrat.pdf", "rb") as f:
    doc = requests.post(
        "https://certyneo.com/api/v1/documents",
        headers=auth,
        files={"file": ("contrat.pdf", f, "application/pdf")},
    ).json()

# 2. Create the DRAFT envelope.
envelope = requests.post(
    "https://certyneo.com/api/v1/envelopes",
    headers={**auth, "Content-Type": "application/json"},
    json={
        "subject": "Contrat de prestation",
        "documentIds": [doc["id"]],
        "recipients": [
            {"email": "client@example.com", "name": "Marie Dubois", "role": "SIGNER"},
        ],
    },
).json()

# 3. Dispatch — this triggers the invitation channel for every recipient.
requests.post(
    f"https://certyneo.com/api/v1/envelopes/{envelope['id']}/send",
    headers=auth,
)
print(envelope["id"])

Попробовать API с помощью ваших инструментов

Коллекция Postman и карточка RapidAPI создаются из спецификации OpenAPI, которая также документирует эту страницу. Все три остаются согласованными с реальным API, endpoint за endpoint, вместо того чтобы расходиться при первом добавлении.

Коллекция Postman

25 запроса, организованные по доменам — конверты, документы, шаблоны, печати, webhooks — с примером тела и ответа для каждого. Вставьте ваш ключ в переменную apiKey коллекции, затем запустите GET /health: она не требует аутентификации и подтверждает, что ваша конфигурация правильная перед первым аутентифицированным вызовом.

Карточка RapidAPI

Тот же каталог endpoints, тестируемый прямо из браузера. Тестовая площадка ожидает два отдельных заголовка: ключ RapidAPI, который вам назначила платформа, и ваш ключ Certyneo в Authorization — второй фактически авторизирует вызов.

Конверты

Создание, отправка, отслеживание статуса, отмена. Конверт может содержать несколько документов и несколько подписантов (параллельно или последовательно).

Вебхуки

Все события конверта и получателя (`envelope.sent`, `recipient.signed`, `envelope.completed`…) доставляются на выбранный вами URL — полный список на /developers/webhooks. HMAC SHA-256 для каждого payload для проверки источника.

Простая аутентификация

Bearer token. Один ключ на окружение (test / prod). Можно отозвать мгновенно. Лимит 100 запросов/мин/ключ, всплеск до 200, чистый ответ 429 с заголовком Retry-After.

Доступные endpoints

53 открытых маршрутов: учётная запись, документы, конверты, шаблоны, вебхуки, электронные печати, ключи API и выставление счётов. Все принимают токен Bearer и возвращают JSON.

МетодПутьОписание
GET/api/v1/account/meИдентичность аутентифицированного вызывающего абонента (id, e-mail, план) : тест идентификаторов без требуемой области
GET/api/v1/sandboxПодсчитать данные, созданные тестовыми ключами (автоматически удаляются через 30 дней)
DELETE/api/v1/sandboxУдалить все данные, созданные тестовыми ключами, не затрагивая реальные данные
POST/api/v1/documentsЗагрузить PDF (multipart) : возвращает id документа
GET/api/v1/documentsСписок документов
GET/api/v1/documents/{id}Читать метаданные документа
DELETE/api/v1/documents/{id}Удалить документ
GET/api/v1/envelopesСписок конвертов (фильтровать с помощью ?status= и ?limit=)
POST/api/v1/envelopesСоздать конверт (статус DRAFT) : на основе templateId или documentIds с дополнительным массивом fields
GET/api/v1/envelopes/{id}Читать состояние конверта
PATCH/api/v1/envelopes/{id}Изменить конверт DRAFT
DELETE/api/v1/envelopes/{id}Удалить конверт DRAFT (409 после отправки : отменить вместо этого)
POST/api/v1/envelopes/{id}/sendОтправить конверт DRAFT : отправляет приглашения
POST/api/v1/envelopes/{id}/voidОтменить отправленный конверт, который еще не полностью подписан : ожидающие подписанты получат уведомление
POST/api/v1/envelopes/{id}/remindНапомнить по запросу подписантам, которые ожидают отправленный конверт (опционально конкретный получатель)
GET/api/v1/envelopes/{id}/audit-trailЗагрузить PDF журнала доказательств eIDAS
POST/api/v1/envelopes/{id}/embed-urlВозвращает URL подписи получателя с разрешением на кадрирование для запрошенного источника. Вызывается в момент клика: разрешение действительно два часа.
GET/api/v1/audit-anchors/{root}Public : метаданные привязанного пакета аудита или файл доказательства .ots с ?format=ots (без аутентификации)
POST/api/v1/audit-anchors/verifyPublic : проверить запись аудита и её доказательство по привязанному корню Меркла (без аутентификации, ничего не раскрывает)
GET/api/v1/envelopes/{id}/signed-documentЗагрузить подписанный PDF (один раз COMPLETED)
GET/api/v1/envelopes/bulkСписок ваших массовых рассылок
POST/api/v1/envelopes/bulkМассовая рассылка: создание N конвертов из шаблона и CSV (только Standard/Business)
GET/api/v1/envelopes/bulk/{id}Ход массовой рассылки: счётчики, ошибки по строкам, созданные конверты
GET/api/v1/templatesСписок переиспользуемых шаблонов конвертов
POST/api/v1/templatesСоздание шаблона (документы, роли, позиционированные поля)
GET/api/v1/workspacesСписок рабочих пространств, в которых вы можете создать конверт
POST/api/v1/sepa-mandatesГенерация PDF мандата SEPA и его конверта DRAFT с уже размещёнными полями
POST/api/v1/payroll-adapters/normalizeНормализация CSV расчётного листка (Silae, Sage Paie, PayFit, Lucca) в формат массовой рассылки
POST/api/v1/ag-coproprieteСоздание конверта общего собрания собственников помещений (решения и доли участия)
POST/api/v1/ag-copropriete/{envelopeId}/votesРегистрация голосов собственника помещения по решениям собрания
POST/api/v1/ag-copropriete/{envelopeId}/tallyПодсчёт собрания: результат по решению, взвешенный по долям участия
GET/api/v1/videos/{videoId}Загрузка сохранённого видео идентификации: право доступа RGPD (ст. 15)
GET/api/v1/webhooksСписок вебхуков
POST/api/v1/webhooksРегистрация вебхука: возвращает секрет подписи только один раз
GET/api/v1/webhooks/{id}Чтение подписки на вебхук
PATCH/api/v1/webhooks/{id}Изменение URL, событий или статуса активности
DELETE/api/v1/webhooks/{id}Отписать вебхук
POST/api/v1/sealsПрименение квалифицированной электронной печати к документу
GET/api/v1/seals/{id}Чтение статуса печати
GET/api/v1/seals/{id}/certificateЗагрузка сертификата печати
GET/api/v1/payslips/workspacesРасчётные листки: пространства, для которых этот ключ распределяет, удерживаемые или делегированные клиентом (бухгалтерские фирмы, администраторы расчётных листков)
GET/api/v1/payslips/employeesРасчётные листки: реестр сотрудников, включая тех, кто отказался от электронной доставки (требуется бумажный расчётный листок)
PUT/api/v1/payslips/employeesРасчетные листки: добавить или обновить сотрудников реестра (никогда не удалять)
POST/api/v1/payslipsОтправить расчетный листок (PDF) в хранилище сотрудника: запечатано, хранится 50 лет, повторная попытка без дубликатов
GET/api/v1/payslipsСписок отправленных расчетных листков с подтверждением просмотра
GET/api/v1/keysСписок ключей API
POST/api/v1/keysСоздать ключ API: секрет отображается только один раз
PATCH/api/v1/keys/{id}Переименовать или отозвать ключ
DELETE/api/v1/keys/{id}Удалить ключ
GET/api/v1/billing/usageПотребление текущего периода и прогнозируемая стоимость
GET/api/v1/statusСтатус сервиса
GET/api/v1/healthПроверка здоровья: база данных, очередь и хранилище объектов
GET/api/v1/openapiСпецификация OpenAPI, читаемая машиной

Шаблоны оболочек

Шаблон раз и навсегда сохраняет PDF, роли и расположение полей подписи, а затем переиспользуется при каждой отправке: передайте его идентификатор в templateId вместо documentIds, и позиционированные поля скопируются на созданный конверт.

  • • Шаблоны создаются с панели управления (Шаблоны → Новый шаблон), где вы загружаете документ и позиционируете поля мышью — это самый простой способ. API также позволяет создавать их через POST /api/v1/templates, указав документы, роли и поля; помните, что поля в нём позиционируются абсолютными координатами (страница, x, y, ширина, высота), поэтому необходимо знать макет PDF.
  • • На аккаунте, который ещё не сохранил ни одного шаблона, GET /api/v1/templates возвращает пустой список. Это нормальное поведение, а не ошибка аутентификации.
  • • Список содержит только шаблоны, принадлежащие пользователю-владельцу ключа API. Шаблон, созданный коллегой, в нём не отображается, даже в рамках общей рабочей области: сгенерируйте ключ с аккаунта, которому принадлежит шаблон.
  • • templateId и documentIds взаимно исключают друг друга: передайте один из них, но не оба и не ни один.
  • • Предоставьте как минимум столько же получателей SIGNER, сколько ролей подписантов в шаблоне, иначе создание будет отклонено с кодом 400. Поле signerCount, возвращаемое списком, указывает ожидаемое количество.
  • • Уровень подписи шаблона наследуется конвертом, кроме случаев, когда запрос явно передаёт signatureLevel.
cURLbash
# 1. Discover the templates saved on this account.
curl -s https://certyneo.com/api/v1/templates \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx"

# {
#   "data": [
#     { "id": "cmdq7f4k80001s6y2h1xa9pl3", "name": "Contrat de prestation",
#       "signerCount": 2, "documentCount": 1, "signatureLevel": "SIMPLE" }
#   ],
#   "pagination": { "page": 1, "pageSize": 20, "total": 1, "pages": 1 }
# }
#
# An empty "data" array means no template exists on this account yet —
# create one from the dashboard, it is not an authentication problem.

# 2. Create the envelope FROM the template: no documentIds and no field
#    coordinates, both are carried by the template. Pass one SIGNER
#    recipient per signer role, in the template's role order.
curl -X POST https://certyneo.com/api/v1/envelopes \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Contrat de prestation",
    "templateId": "cmdq7f4k80001s6y2h1xa9pl3",
    "recipients": [
      { "email": "client@example.com", "name": "Marie Dubois", "role": "SIGNER" },
      { "email": "legal@example.com", "name": "Paul Martin", "role": "SIGNER" }
    ]
  }'

# 3. The envelope is DRAFT at this point — POST /envelopes/{id}/send
#    dispatches it, exactly as in the quick-start above.

Из Power Automate или Zapier

Действие «Создать конверт» в наших no-code коннекторах охватывает только путь через шаблон: поле Шаблон в нём обязательно. Для документа ad hoc, который меняется при каждом выполнении, используйте действие «Загрузить документ», а затем необработанное HTTP-действие на POST /api/v1/envelopes, передав возвращённый documentIds.

Отправка документа: две принятые формы

POST /api/v1/documents принимает файл двумя способами на выбор. Одинаковые проверки применяются в обоих случаях: разрешённые типы, лимит 50 МБ, проверка бинарной подписи и антивирусный анализ.

  • • В multipart/form-data с частью, названной file. Это классическая форма, используемая curl -F и большинством библиотек.
  • • В необработанном теле: байты файла составляют тело запроса, а заголовок Content-Type указывает его тип (например, application/pdf). Полезно для инструмента, который передает содержимое как есть, без обёртывания запроса — это делает соединитель Power Automate.
  • • В необработанном теле имя файла не имеет места в теле: укажите его через заголовок X-File-Name или параметр ?fileName=. Без него документ называется по его типу.
  • • Неподдерживаемый тип отвечает 415, указывая две принятые формы, а тело, заявленное как multipart, но нечитаемое, отвечает 400. Ни то, ни другое не является ошибкой сервера.
cURLbash
# a. multipart/form-data — the classic shape.
curl -X POST https://certyneo.com/api/v1/documents \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -F "file=@contrat.pdf;type=application/pdf"

# b. raw body — the file bytes ARE the body, typed by Content-Type.
#    The filename has nowhere to live in the body, so pass it as a header
#    (or ?fileName=). Without it the document is named after its type.
curl -X POST https://certyneo.com/api/v1/documents \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/pdf" \
  -H "X-File-Name: contrat.pdf" \
  --data-binary "@contrat.pdf"

# Both return the same 201 with the document id to pass as documentIds.

Размещение полей подписи

Без шаблона конверт, созданный из documentIds, не имеет предпозиционированных полей: подписант получает документ без места для подписи. Массив fields, переданный в том же вызове создания, размещает каждое поле с точностью до пункта — это эквивалент на стороне API того, что шаблон сохраняет раз и навсегда.

  • • Координаты указаны в пунктах PDF, начало отсчёта в верхнем левом углу страницы и ось Y вниз (страница A4 имеет размер 595 × 842 пункта). x и y обозначают верхний левый угол поля, width и height — его размер.
  • • pageNumber начинается с 1, documentIndex начинается с 0. Номер страницы за пределами документа не отклоняется при создании: поле игнорируется во время подписи и не отображается нигде — это первое, что нужно проверить, когда поле отсутствует в вызове.
  • • recipientEmail должен соответствовать одному из получателей в том же вызове без учета регистра. В противном случае создание не удается, перечисляя все ошибочные строки, что позволяет избежать их исправления по одной.
  • • fields и templateId исключают друг друга: шаблон уже имеет собственный макет. Массив fields используется только с documentIds.
  • • Принятые типы: SIGNATURE, INITIALS, DATE_SIGNED, TEXT, CHECKBOX и RADIO_GROUP. required по умолчанию имеет значение true; placeholder и dateFormat необязательны, а options учитывается только для RADIO_GROUP.
  • • Конверт принимает максимум 100 полей, 20 документов и 50 получателей — ограничения вашего плана могут быть ниже.
cURLbash
# Ad-hoc envelope WITH pre-placed fields — no template involved.
# Coordinates are PDF points, origin TOP-LEFT of the page, +Y downwards
# (A4 = 595 x 842 pt). x / y are the field box's top-left corner.
#
# The last field is positioned by ANCHOR instead of by eye: the server
# locates "Signature du client" in the PDF and computes the spot. x / y
# stay required there — they are the fallback if the text is not found.
curl -X POST https://certyneo.com/api/v1/envelopes \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Contrat de prestation",
    "documentIds": ["cmdq7f4k80001s6y2h1xa9pl3"],
    "recipients": [
      { "email": "client@example.com", "name": "Marie Dubois", "role": "SIGNER" }
    ],
    "fields": [
      { "recipientEmail": "client@example.com", "documentIndex": 0,
        "pageNumber": 2, "fieldType": "SIGNATURE",
        "x": 90, "y": 640, "width": 180, "height": 44 },
      { "recipientEmail": "client@example.com", "documentIndex": 0,
        "pageNumber": 2, "fieldType": "DATE_SIGNED",
        "x": 320, "y": 640, "width": 140, "height": 30,
        "dateFormat": "DD/MM/YYYY" },
      { "recipientEmail": "client@example.com", "documentIndex": 0,
        "pageNumber": 2, "fieldType": "TEXT",
        "x": 90, "y": 700, "width": 200, "height": 30,
        "placeholder": "Fonction", "required": false },
      { "recipientEmail": "client@example.com", "documentIndex": 0,
        "pageNumber": 2, "fieldType": "SIGNATURE",
        "anchorText": "Signature du client", "anchorPlacement": "below",
        "anchorIndex": 0,
        "x": 90, "y": 640, "width": 180, "height": 44 }
    ]
  }'

# The envelope is DRAFT at this point — POST /envelopes/{id}/send
# dispatches it, exactly as in the quick-start above.

Текстовые якоря: размещение поля без знания координат

Вместо координат поле может ссылаться на текст, напечатанный в документе: anchorText находит его в PDF, а сервер вычисляет позицию при создании. Это предпочтительный способ, когда документ воссоздается при каждой отправке — слияние почты, генератор контрактов — потому что макет меняется, а фраза «Подпись клиента» остается. anchorPlacement указывает, с какой стороны текста размещается поле (по умолчанию right, иначе below, above или left), а anchorIndex выбирает вхождение, когда текст появляется несколько раз.

x и y остаются обязательными даже с якорем: они служат резервным вариантом. Неправильный якорь не приводит к сбою создания — поле сохраняет буквальную позицию, которую вы указали, без ошибок или предупреждений в ответе. Укажите правдоподобный резервный вариант вместо 0,0 и проверьте результат при первой отправке.

Встроенная подпись: подпишите, не покидая приложение

Ваш клиент просматривает и подписывает свой документ через ваш собственный интерфейс. Церемония открывается в окне поверх вашей страницы и автоматически возвращает его к вам по завершении. На стороне сервера ничего нового: вы создаете конверт как обычно, указав redirectUrl, а затем передаете SDK URL-адрес подписи получателя.

  • • Вызовите Certyneo.sign() прямо в обработчике щелчка и передайте серверный вызов через getUrl. Ожидание перед sign() выходит за рамки жеста пользователя: Safari и Firefox блокируют окно. SDK открывает его немедленно и загружает его, когда ваше обещание разрешится.
  • • redirectUrl — это канал возврата. Мы перенаправляем подписанта туда, добавляя certyneo_status (completed или declined) и certyneo_envelope. Загрузите тот же скрипт на эту страницу возврата: он уведомляет окно портала, оставшееся открытым позади.
  • • В встроенном режиме наши собственные призывы к действию удаляются. Ваш клиент никогда не видит приглашение создать аккаунт Certyneo.
  • • Если браузер отказывает в открытии окна, SDK автоматически переходит на полнопроходную переадресацию. Процесс идентичен для подписанта, и ваша страница возврата получает ровно те же параметры.
  • • Намеренно не существует обратного вызова «пользователь отказался»: состояние окна не читается с вашей страницы, и такой обратный вызов срабатывал бы неправильно. Подпись, которая не приходит, остаётся в ожидании до webhook.
JavaScriptjavascript
// 1. Your server creates and sends the envelope, then hands the browser the
//    recipient's signing URL. Nothing new on the API side:
//      POST /api/v1/envelopes        { …, "redirectUrl": "https://your-app.com/quote/42/signed" }
//      POST /api/v1/envelopes/{id}/send   → recipients[].accessToken
//      signingUrl = "https://certyneo.com/sign/" + accessToken

// 2. On your quote page — load the SDK once:
//      <script src="https://certyneo.com/embed.js"></script>

document.querySelector("#sign").addEventListener("click", () => {
  Certyneo.sign({
    // Called AFTER the window is already open, so no popup blocker ever
    // sees a delay between the click and window.open.
    getUrl: () =>
      fetch("/api/quote/42/signature", { method: "POST" })
        .then((r) => r.json())
        .then((d) => d.signingUrl),

    onCompleted: (e) => showConfirmation(e.envelopeId),
    onDeclined: () => showDeclined(),
    onError: (e) => showError(e),
  });
});

// 3. On https://your-app.com/quote/42/signed — your return page — load the
//    same script and render a short confirmation. It relays the outcome to
//    the portal window behind it, then closes itself.

Событие браузера не является доказательством подписания

onCompleted — это сигнал отображения, испускаемый браузером, поэтому его может подделать кто угодно из своей консоли. Никогда не переводите папку в статус «подписано» на этом основании: используйте его для обновления экрана и полагайтесь на webhook подписанного envelope.completed, полученный вашим сервером, для реального статуса. Это классическая ловушка интеграций платежей, и здесь она повторяется в точности.

Разработка на вашем компьютере

С тестовым ключом redirectUrl принимает http://localhost (и 127.0.0.1): вы разворачиваете весь процесс на вашей машине перед развёртыванием. Реальный ключ его отказывает, чтобы ни один конверт производства не перенаправлял настоящего подписанта на машину, которая не принадлежит ему.

Отобразить церемонию на вашей странице

Режим встраивания отображает подпись внутри вашего интерфейса без всплывающего окна. Он требует дополнительного шага по сравнению с режимом окна: подтверждение того, что сайт, на котором она будет отображаться, вам принадлежит. Это предотвращает встраивание наших церемоний третьей стороной для обмана ваших клиентов.

  • • Объявите ваш сайт в разделе Параметры → Встроенная подпись, затем опубликуйте указанную запись DNS. Точный адрес: поддомен или другой порт считаются отдельным сайтом.
  • • При каждой подписи запросите свежий URL через POST /api/v1/envelopes/{id}/embed-url. Он содержит разрешение на отображение и действует два часа, что соответствует моменту клика, а не созданию конверта.
  • • Два сценария не могут выполняться во встроенном режиме: квалифицированная подпись, проверка идентичности которой отказывается быть встроенной, и платёж при подписании. В обоих случаях подписант перенаправляется в полное окно.
  • • Надпись «Powered by Certyneo» исчезает из встроенного режима начиная с плана Business. Сам режим встраивания включён уже в плане Standard.
JavaScriptjavascript
// Mode cadre : la cérémonie s'affiche DANS votre page.
//
// 1. Déclarez votre site une fois pour toutes dans Réglages → Signature
//    intégrée, et publiez l'enregistrement DNS qu'on vous y donne.
//
// 2. À chaque signature, votre serveur demande une URL fraîche. Elle porte
//    l'autorisation qui permet au navigateur d'afficher la cérémonie chez
//    vous, et vaut deux heures :
//
//      POST /api/v1/envelopes/{id}/embed-url
//      { "origin": "https://portail.exemple.fr" }
//      -> { "signingUrl": "…", "expiresAt": "…" }

Certyneo.sign({
  mode: "iframe",
  el: "#zone-signature",        // sélecteur ou nœud de votre page

  getUrl: () =>
    fetch("/api/devis/42/signature", { method: "POST" })
      .then((r) => r.json())
      .then((d) => d.signingUrl),

  onCompleted: (e) => afficherConfirmation(e.envelopeId),
  onDeclined: () => afficherRefus(),
});

// Le cadre parle à votre page par postMessage — pas besoin de page de retour,
// contrairement au mode fenêtre.

Получить подпись без отправки каких-либо писем

Портал, отображающий церемонию у себя, часто не нуждается в нашем приглашении: оно приходит вместе с его собственным процессом и предлагает аккаунт клиенту, который его не хочет. Установите значение NONE для канала уведомления получателя, и ему больше ничего не будет отправлено — вы сами отведете его на подпись.

  • • Этот параметр устанавливается для каждого получателя, а не для конверта: вы можете отключить уведомление клиента, который вы размещаете, и сохранить электронное письмо для внешнего контрподписанта, у которого нет портала.
  • • Это зарезервировано для подписывающих и одобряющих, единственные, кому вам нужно передать ссылку. Вы читаете ее в ответе при создании и отправке, или запрашиваете свежий URL в момент нажатия в POST /api/v1/envelopes/{id}/embed-url.
  • • Автоматические напоминания останавливаются сами по себе для этого получателя: мы ему никогда не писали, мы не начинаем с напоминания. Другие получатели продолжают получать напоминания нормально.
  • • Сертификат подписи упоминает об этом для каждого получателя. Папка доказательств, которая молчала бы об этом, позволила бы предположить, что этот подписывающий получил от нас приглашение, которое никогда не существовало.
JSONjson
POST /api/v1/envelopes

{
  "subject": "Mandat de gestion",
  "documentIds": ["doc_8f2c1a4b9e7d"],
  "recipients": [
    {
      "email": "client@exemple.fr",
      "name": "Camille Client",
      "role": "SIGNER",
      "notificationChannel": "NONE"
    },
    {
      "email": "notaire@exemple.fr",
      "name": "Maître Notaire",
      "role": "SIGNER"
    }
  ]
}

// La réponse rend le lien de chaque signataire :
//
//   "recipients": [
//     { "email": "client@exemple.fr",  "accessToken": "…",
//       "notificationChannel": "NONE"  },
//     { "email": "notaire@exemple.fr", "accessToken": "…",
//       "notificationChannel": "EMAIL" }
//   ]
//
// Le client ne reçoit rien : vous l'emmenez sur sa signature depuis votre
// portail. Le notaire, lui, reçoit son invitation comme d'habitude.

Отображение имени вашего клиента как отправителя

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

  • • Зарезервировано для плана Business и выше. На более низком плане создание отклоняется, чтобы подписант не увидел другое имя, чем ожидаемое.
  • • Имя — это отображение: сертификат и журнал аудита сохраняют реального отправителя, и письма всегда отправляются от Certyneo.
  • • Адрес не обязателен. Без него подписант видит только имя, никогда адрес владельца ключа.
JSONjson
POST /api/v1/envelopes

{
  "subject": "Devis 2026-118",
  "documentIds": ["doc_8f2c1a4b9e7d"],
  "recipients": [
    { "email": "client@exemple.fr", "name": "Camille Client", "role": "SIGNER" }
  ],
  "sender": {
    "name": "1.2.3. Panneaux Solaires",
    "email": "devis@123-panneaux-solaires.fr"
  }
}

Аутентификация

Каждый вызов содержит ключ API в заголовке Authorization. Ключи генерируются из Параметры → Ключи API и отображаются только один раз.

HTTPhttp
GET /api/v1/account/me HTTP/1.1Host: certyneo.com
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx

# 200 OK
{ "data": { "id": "usr_…", "email": "you@example.com", "plan": "BUSINESS", "environment": "live" } }
  • • Формат: sk_live_… в production, sk_test_… для sandbox. Заголовок: Authorization: Bearer <ключ>.
  • • Области: envelopes, documents, webhooks, seals — для чтения (:read) или записи (:write). Запись подразумевает чтение; область * предоставляет все права.
  • • Ключи sk_test_ создают ресурсы в песочнице, исключённые из квоты и выставления счетов. Получателю не отправляется настоящее письмо, если только его адрес не совпадает с email отправляющего аккаунта — удобно для тестирования всего процесса на себе.
  • • Ошибки: 401 неверный ключ, 403 недостаточная область, 429 превышен лимит частоты запросов, 402 достигнута месячная квота.

Формат ответов

Важный момент перед написанием вашего клиента: коллекции заключены в объект data, а единичные ресурсы возвращаются плоско. Чтение response.data.data для единичного ресурса возвращает undefined.

Коллекция — упакованнаяjson
// GET /api/v1/envelopes
// Collections are WRAPPED in a "data" array.
{
  "data": [
    { "id": "env_abc123", "subject": "Contrat", "status": "SENT" }
  ]
}
Индивидуальная ресурсная единица — плоскаяjson
// GET /api/v1/envelopes/{id}
// Single resources are returned FLAT — no "data" envelope.
{
  "id": "env_abc123",
  "subject": "Contrat",
  "status": "COMPLETED",
  "recipients": [ /* … */ ]
}

Ограничения пропускной способности

Ограничения гарантируют стабильное качество обслуживания для всех клиентов. Если вам нужно больше, свяжитесь с нами.

  • • 100 запросов в минуту на API ключ
  • • Всплеск допустимо до 200 запросов менее чем за 10с
  • • Ответ 429 с заголовком Retry-After, указывающим задержку в секундах

Узнать больше