CleanSign API

Справочник · v1

CleanSign API

REST-API сервиса CleanSign для проверки электронных подписей (ЭП/ЭЦП). Принимает документы и файлы подписи через multipart/form-data, возвращает JSON со сведениями о подписантах, цепочкой сертификатов и классификацией подписи. Использует тот же движок проверки, что и веб-форма на главной странице. Подходит для пакетной обработки документов и мониторинга срока действия сертификатов; готовых коннекторов к учётным системам и операторам ЭДО сервис не поставляет — встраивание выполняется на стороне клиента.

Базовый URL: https://api.cleanvoice.ru/cleansign/api/v1.

Какие проверки выполняются

  • Соответствие хеша документа подписанному атрибуту messageDigest — отсекает подмену подписанного содержимого.
  • Криптографическая проверка подписи (ГОСТ Р 34.10-2012, RSA, ECDSA).
  • Построение цепочки сертификатов до закреплённого trust-anchor (ГУЦ Минцифры) в режиме fail-closed.
  • Проверка привязки signingCertificateV2 (RFC 5126), исключающая подмену сертификата подписанта.
  • Проверка аккредитации УЦ-эмитента в реестре Минцифры на текущий момент и на момент подписания.
  • Опционально: проверки OCSP и CRL, верификация контр-подписей и меток времени CAdES (профили BES — A).
  • Классификация подписи по 63-ФЗ — КЭП (она же УКЭП — усиленная квалифицированная), НЭП (усиленная неквалифицированная) или иная — с указанием класса средства ЭП (КС1, КС2, КС3) и СКЗИ.

Поддерживаемые форматы

  • CMS / PKCS#7 — отделённая подпись в виде самостоятельного файла рядом с документом. Расширения: .sig, .sgn, .sign, .p7s, .bin (плюс числовые суффиксы вида .sig2, .sig.001). Документом может быть любой файл — .pdf, .docx, .xlsx, .doc, .xml, .txt, .html, .rtf и любой бинарный.
  • CAdES — те же расширения, что и CMS; распознаются профили BES, EPES, T, C, X-L, X Long Type 1, A.
  • PAdES — встроенная подпись в PDF (.pdf): чтение /ByteRange, /Contents, поддержка нескольких подписей в одном документе и словаря /DSS (DSS dictionary).
  • S/MIME — почтовые сообщения multipart/signed. Расширения: .eml, .p7m, .mime, .msg.
  • XMLDSig / XAdES — XML-файлы (.xml) с алгоритмами ГОСТ или RSA; поддерживаются преобразования c14n, exc-c14n и enveloped-signature.
  • OOXML.docx, .xlsx, .pptx с поддержкой RelationshipTransform по ECMA-376 §13.
  • ZIP-архивы.zip распаковывается на один уровень: документы и подписи внутри сопоставляются по содержимому (хеш) и по имени; поддержка имён в кодировке CP866. Зашитые внутрь архива другие архивы хранятся как опаковые байтовые блобы и отдельно не распаковываются. Применяются защитные лимиты: число записей, размер записи, кумулятивный размер, коэффициент сжатия (zip-bomb), глубина вложенности папок и потенциальной рекурсии (см. CleanSign:Limits).

Версионирование

Канонические пути API располагаются под префиксом /api/v{N}/. Контракт v1 зафиксирован: в существующие ответы могут добавляться новые необязательные поля, но имена и типы существующих полей не изменяются и не удаляются. Несовместимое изменение (переименование поля, изменение типа, удаление секции ответа) выпускается параллельной версией /api/v2; /api/v1 продолжает работать в прежнем виде.

Незаверсионированные пути /api/verify и /api/cert/check — это псевдонимы, ведущие на текущую актуальную версию. Они сохраняются для обратной совместимости со старыми интеграциями. В новых интеграциях используйте только версионированные пути, чтобы зафиксировать контракт.

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

Доступ к API авторизуется по токену. Токен выдаётся при подключении и передаётся в заголовке Authorization: Bearer <token>. Запросы без валидного токена отклоняются с кодом 401 Unauthorized.

Все запросы выполняются по HTTPS. Максимальный размер тела запроса — 200 МБ.

Коды ошибок

HTTPКогдаЧто вернётся
200 OKЗапрос обработан. Невалидная подпись — это штатный результат проверки, статус по каждому файлу возвращается в items[i].status.JSON: VerificationResponse или CertificateCheckResponse
400 Bad RequestЗапрос не в формате multipart/form-data, отсутствует поле с файлами или повреждена форма.{ "error": "..." }
413 Payload Too LargeПревышен один из лимитов: размер запроса, размер записи в архиве, число записей, коэффициент сжатия (защита от zip-bomb).{ "error": "..." } с указанием конкретного лимита
500 Internal Server ErrorВнутренняя ошибка сервиса.{ "error": "..." }
Важно: отрицательный результат проверки подписи возвращается с кодом 200 OK, а не 4xx. Сам запрос обработан корректно; результат проверки находится в полях items[i].isValid и items[i].status.

POST /api/v1/verify

Проверяет одну или несколько связок «документ + подпись». Принимает ZIP-архивы (распаковываются рекурсивно), пары вида «doc.pdf + doc.pdf.sig», PDF со встроенной PAdES-подписью, .eml с S/MIME, файлы .docx, .xlsx, .pptx и .xml (XMLDSig).

POST /api/v1/verify
multipart/form-data → application/json

Параметры запроса (query или поле формы)

ПолеТипОписание
filesfile[]Один или несколько файлов. Документ и подпись могут передаваться отдельными частями формы либо одним ZIP-архивом. Имя поля формы — files.
returnSignatureFileboolЕсли true, в каждый элемент результата добавляется signatureFileBase64 — байты файла подписи в base64 (для отделённой подписи), внутренний CMS (для PAdES и S/MIME) либо файл sig*.xml (для OOXML). Значение по умолчанию — false.
returnCertificateFileboolЕсли true, в каждом подписанте возвращается поле certificateBase64 с DER-представлением сертификата подписанта в base64. Значение по умолчанию — false.

Пример запроса

curl -X POST 'https://api.cleanvoice.ru/cleansign/api/v1/verify?returnCertificateFile=true' \
  -F 'files=@invoice.pdf' \
  -F 'files=@invoice.pdf.sig' \
  -H 'Authorization: Bearer YOUR_KEY'
import requests

files = [
    ('files', ('invoice.pdf',     open('invoice.pdf',     'rb'))),
    ('files', ('invoice.pdf.sig', open('invoice.pdf.sig', 'rb'))),
]
resp = requests.post(
    'https://api.cleanvoice.ru/cleansign/api/v1/verify',
    params={'returnCertificateFile': 'true'},
    files=files,
    headers={'Authorization': 'Bearer YOUR_KEY'},
)
data = resp.json()
print(data['summary']['validlySigned'], 'valid of', data['summary']['totalDocuments'])
const fd = new FormData();
fd.append('files', pdfFile,  'invoice.pdf');
fd.append('files', sigFile,  'invoice.pdf.sig');

const r = await fetch('https://api.cleanvoice.ru/cleansign/api/v1/verify?returnCertificateFile=true', {
  method: 'POST',
  body: fd,
});
const data = await r.json();
console.log(data.summary.validlySigned + ' / ' + data.summary.totalDocuments);
using var http = new HttpClient { BaseAddress = new Uri("https://api.cleanvoice.ru/cleansign/") };
http.DefaultRequestHeaders.Authorization = new("Bearer", "YOUR_KEY");

using var form = new MultipartFormDataContent();
form.Add(new ByteArrayContent(File.ReadAllBytes("invoice.pdf")),     "files", "invoice.pdf");
form.Add(new ByteArrayContent(File.ReadAllBytes("invoice.pdf.sig")), "files", "invoice.pdf.sig");

var resp = await http.PostAsync("api/v1/verify?returnCertificateFile=true", form);
var json = await resp.Content.ReadAsStringAsync();

Пример ответа (200 OK)

{
  "summary": {
    "totalDocuments":    1,
    "signed":            1,
    "validlySigned":     1,
    "invalidSignatures": 0,
    "notSigned":         0,
    "orphanSignatures":  0
  },
  "items": [
    {
      "documentFile":           "invoice.pdf",
      "documentSize":            182734,
      "signatureFile":           "invoice.pdf.sig",
      "isSigned":                true,
      "isValid":                 true,
      "status":                  "Valid",
      "documentHashAlgorithm":   "GOST R 34.11-2012 (256)",
      "documentHashHex":         "8E5C…",
      "messageDigestMatches":    true,
      "isPowerOfAttorney":       false,
      "signers": [
        {
          "subjectCommonName":     "Иванов Иван Иванович",
          "subjectType":           "ЮЛ",
          "signerShortName":       "Иванов И. И.",
          "signingTime":           "2026-04-30T17:42:11+00:00",
          "signatureValid":        true,
          "trustStatus":           "Trusted",
          "chainTrusted":          true,
          "trustedRootSubject":    "CN=Минцифры России",
          "classification":        { "kind": "КЭП", "kindFull": "Квалифицированная электронная подпись",
                                     "classes": ["КС1"], "subjectSignTool": "КриптоПро CSP (5.0.12000)",
                                     "usesGost": true, "issuedByAccreditedUc": true, "isGoskey": false,
                                     "deprecationWarnings": [] },
          "attributes":            { "inn": "772372861423", "innLe": "7709000010",
                                     "ogrn": "1047709098315", "snils": "14233464635",
                                     "email": "i.ivanov@example.com",
                                     "givenName": "Иван Иванович", "surname": "Иванов",
                                     "organization": "ООО «Пример»" },
          "accreditation":         { "currentStatus": "Accredited", "atSigningTimeStatus": "Accredited" },
          "certificateBase64":     "MIIH…"   // только если returnCertificateFile=true
        }
      ],
      "errors":   [],
      "warnings": []
    }
  ]
}

POST /api/v1/cert/check

Проверка только сертификата, без документа. Эндпоинт оптимизирован для регулярных запусков из cron. Принимает .cer, .crt, .pem, .der или CMS-файл (.sig); во втором случае сертификат подписанта извлекается по SignerID. Возвращает срок действия, число дней до истечения, аккредитацию УЦ, статус OCSP и CRL, классификацию.

POST /api/v1/cert/check
multipart/form-data → application/json

Пример: ежедневный мониторинг

#!/bin/bash
# Завершиться с ошибкой, если до истечения сертификата осталось менее 30 дней.
RESP=$(curl -sf -F files=@/etc/ssl/edo.cer https://api.cleanvoice.ru/cleansign/api/v1/cert/check)
DAYS=$(echo "$RESP" | jq '.items[0].daysUntilExpiry')
[ "$DAYS" -lt 30 ] && echo "ALERT: cert expires in $DAYS days" && exit 1

Пример ответа

{
  "summary": { "total": 1, "currentlyValid": 1, "expiringSoon": 0, "expired": 0,
               "trusted": 1, "untrusted": 0, "revoked": 0 },
  "items": [{
    "fileName":          "edo.cer",
    "source":            "X509",
    "subjectCommonName": "ООО «Пример»",
    "issuer":            "CN=Удостоверяющий центр Федерального казначейства",
    "notBefore":         "2025-08-12T08:14:00+00:00",
    "notAfter":          "2026-08-12T08:14:00+00:00",
    "isCurrentlyValid":  true,
    "daysUntilExpiry":   97,
    "publicKeyAlgorithm":"GOST R 34.10-2012 (256)",
    "classification":    { "kind": "КЭП", "classes": ["КС1"], "issuedByAccreditedUc": true },
    "trust":             { "status": "Trusted", "trusted": true,
                           "rootSubject": "CN=Минцифры России",
                           "chain": [...] },
    "accreditation":     { "currentStatus": "Accredited" },
    "revocation":        null,
    "revocationCrl":     null
  }]
}

VerificationResponse

Ответ POST /api/v1/verify.

ПолеТипОписание
summary object Сводка по всему запросу.
summary.totalDocuments intСколько документов было распознано.
summary.signed intИз них подписанных (любым статусом, включая невалидные).
summary.validlySigned intИз подписанных — прошедших полную проверку (status=Valid).
summary.invalidSignatures intПодписанных с фейлом (хэш не совпал, недоверенная цепочка, пр.).
summary.notSigned intДокументов, для которых не нашлось подписи.
summary.orphanSignatures intПодписей без сопоставленного документа.
items DocumentVerificationResult[] Результат по каждому документу/паре. См. ниже.

DocumentVerificationResult

ПолеТипОписание
documentFile string Имя/путь документа (включая путь внутри архива, если это ZIP).
documentSize long Размер документа в байтах.
signatureFile string? Имя/путь файла подписи. null для NotSigned. Для встроенной подписи — синтетическое имя вроде doc.pdf (PAdES).
isSigned bool Найдена ли вообще какая-либо подпись.
isValid bool Прошла ли подпись все обязательные проверки. true ↔ status=Valid.
status string Один из: Valid, Untrusted, DocumentHashMismatch, InvalidSignature, InvalidSignatureContainer, OrphanSignature, NotSigned, UnverifiedXmlSignature.
documentHashAlgorithm string? Человекочитаемое имя алгоритма (например, «GOST R 34.11-2012 (256)»).
documentHashHex string? Hex-представление вычисленного хеша документа.
messageDigestMatches bool? Совпал ли хеш документа с подписанным атрибутом messageDigest. false = «приклеили чужую подпись».
isPowerOfAttorney bool Файл является МЧД (машиночитаемой доверенностью) — определяется по имени ON_EMCHD_*.xml.
signers SignerInfoResult[]Информация по каждому подписанту. Обычно один элемент.
errors string[] Ошибки, делающие подпись невалидной.
warnings string[] Предупреждения (deprecated алгоритмы, отсутствие OCSP-эндпойнта и т. п.).
signatureFileBase64 string? Заполняется только при returnSignatureFile=true.

SignerInfoResult

Полная карточка подписанта. Поля сгруппированы для удобства.

Идентификация

subjectCommonNamestringCN из Subject DN.
subject stringПолный Subject DN.
issuer stringПолный Issuer DN.
serialNumber stringСерийный номер сертификата (hex).
subjectType string?«Физлицо» / «ИП» / «ЮЛ» / null — определяется по российским OID-ам.
signerShortName string?Компактное «Иванов И. И.» если есть фамилия и имя в attributes.
attributes RussianSubjectAttributesИНН, ИНН ЮЛ, ОГРН, ОГРНИП, СНИЛС, email, surname, givenName, organization, organizationUnit, country, locality, title.

Срок действия и алгоритмы

certNotBefore datetimeНачало срока действия сертификата (ISO-8601 UTC).
certNotAfter datetimeКонец срока действия.
certificateTimeValid bool Был ли сертификат действителен в момент подписания.
digestAlgorithmOid string OID алгоритма хеширования.
digestAlgorithmName string Человекочитаемое имя.
signatureAlgorithmOid string OID алгоритма подписи.
signatureAlgorithmName string Имя.
signingTime datetime?Из подписанного атрибута signingTime (если есть).

Криптопроверка и доверие

signatureValid bool Прошла ли криптоматематика подписи.
signatureError string? Текст ошибки, если signatureValid=false.
trustStatus string Один из: Trusted, UntrustedRoot, BrokenChain, SignatureFailure, Expired, TrustStoreEmpty.
chainTrusted bool Завершилась ли цепочка на закреплённом anchor-е (ГУЦ Минцифры).
trustedRootSubject string? Subject корневого сертификата, если он в trust-store.
chain CertificateChainLink[]Цепочка leaf → ... → root. Каждый узел: subject, issuer, serialNumber, notBefore, notAfter, inTrustStore.
trustErrors string[]Подробности проблем доверия.

Расширенная информация

classification SignatureClassificationkind (КЭП/НЭП/Иная), kindFull, reason, classes (КС1/КС2/КС3), subjectSignTool (СКЗИ), usesGost, issuedByAccreditedUc, isGoskey, deprecationWarnings.
cades CadesProfile? Уровень CAdES: BES, EPES, T, C, X-L, X Long Type 1, A.
timestamps TimestampResult[]Метки времени с проверенной TSA-подписью.
revocation OcspResult? OCSP-проверка (опционально, off by default).
revocationCrl CrlResult? CRL-проверка (опционально).
accreditation AccreditationCheck?Аккредитация УЦ: currentStatus + atSigningTimeStatus.
counterSignatures CounterSignatureInfo[]Контр-подписи (id-aa-counterSignature).
signingCertBinding object? Проверка signingCertificateV2 (RFC 5126): Verified / Mismatch / Malformed / NotPresent.
certificateBase64 string? DER сертификата в base64 — только при returnCertificateFile=true.

CertificateCheckResponse

Ответ POST /api/v1/cert/check. Структура простая:

summary.total intСколько файлов прислали.
summary.currentlyValid intДействительных сейчас.
summary.expiringSoon intИстекают в ближайшие 30 дней.
summary.expired intУже истекли.
summary.trusted intЦепочка ведёт к закреплённому anchor-у.
summary.untrusted intЦепочка не выстроилась или anchor другой.
summary.revoked intОтозваны (по OCSP или CRL, если включены).
items[i] CertificateCheckResultfileName, source, subject, issuer, serialNumber, notBefore, notAfter, isCurrentlyValid, daysUntilExpiry, publicKeyAlgorithm, signatureAlgorithm, deprecationWarnings, classification, trust, accreditation, revocation, revocationCrl, attributes. Производный признак «истекает скоро» вычисляется на стороне клиента из daysUntilExpiry по своему порогу.

Типичные интеграции

Сценарии, в которых API применяется на практике.

Учётные системы (1С, SAP, ERP)

При приёме входящего УПД, акта или счёта-фактуры файл автоматически направляется на /api/v1/verify; проводка блокируется, если подпись контрагента невалидна или сертификат отозван.

Операторы ЭДО

Кросс-проверка пакетов от смежных операторов и ФНС: PDF + .sig, ON_DOCNPNO, KV-квитанции, confirmation.*. Автоматическое сопоставление по содержимому, единый формат отчёта.

Финтех, банки, факторинг

Перед выкупом дебиторской задолженности выполняется автоматическая проверка договора поставки: валидная КЭП обеих сторон, цепочка до ГУЦ Минцифры, аккредитация УЦ на момент подписания.

Госорганы и B2G

Приём электронных обращений: проверка подписи заявителя, классификация (КЭП, НЭП), привязка к ФЛ, ИП или ЮЛ по ИНН, СНИЛС и ОГРН, выявление машиночитаемой доверенности (МЧД).

Мониторинг сертификатов через cron

Эндпоинт /api/v1/cert/check запускается раз в сутки по сертификатам ЭДО и API-партнёров; формирует оповещение за Х дней до истечения, при отзыве сертификата или при потере аккредитации УЦ.

curl -F files=@cert.cer \
  https://api.cleanvoice.ru/cleansign/api/cert/check \
  | jq '.items[0].daysUntilExpiry < 30'

Долгосрочное хранение

При помещении документа в архив фиксируется уровень CAdES (от BES до A), валидируются метки времени, сохраняется цепочка сертификатов и снимок реестра аккредитации УЦ в качестве доказательственной базы.

Состав подписки

Подписка включает не только доступ к API, но и операционное обслуживание сервиса в режиме 24/7:

КомпонентСостав
Актуальный trust-storeАвтоматическое обновление: загрузка новых промежуточных сертификатов через AIA, обработка ротации ключей УЦ, актуальные точки распространения CRL.
Синхронизация с реестром МинцифрыЗагрузка обновлений с e-trust.gosuslugi.ru: добавление новых аккредитованных УЦ, аннулирования, изменения статуса.
Сопровождение форматовАдаптация движка к новым форматам (Goskey 2.x, новые OID Минцифры, изменения 63-ФЗ). Обновления применяются на стороне сервиса без действий со стороны клиента.
ПроизводительностьГоризонтальное масштабирование под пиковую нагрузку.
SLA и поддержкаЦелевая доступность 99.95%.
Журналы и метрикиПанель статистики статусов проверки, настраиваемое хранение, аудит.

Запросить стоимость

В письме укажите сценарии использования и ожидаемый объём верификаций в месяц.