Перейти до вмісту

Накладення електронного підпису за допомогою Дія в Python

Матеріал з K2 ERP Wiki Ukraine — База знань з автоматизації та санкцій в Україні


SEO title: Технічне завдання: Накладення електронного підпису за допомогою Дія.Підпис у Python SEO description: Технічне завдання на реалізацію Python-сервісу для інтеграції з Дія.Підпис: підписання документів, авторизація, QR/deep link, статуси, callback, p7s, перевірка підпису, журналювання, dashboard та безпека. SEO keywords: Python, Дія.Підпис, Diia.Signature, КЕП, електронний підпис, підписання документів, FastAPI, K2 ERP, callback, p7s, електронний документообіг Alternative to:



Головна ідея: розробити Python-сервіс, який дозволяє користувачам підписувати документи за допомогою Дія.Підпис із подальшим збереженням підписаного документа, файлу підпису, статусу підписання, журналу дій і результату перевірки підпису.

Критично важливо: система не повинна вважати документ підписаним тільки після відкриття QR-коду або переходу в застосунок Дія. Документ вважається підписаним лише після отримання підтвердженого результату підписання, збереження підпису та успішної перевірки цілісності.

Важливо: точні endpoint-и, формат callback, формат підписаного контейнера, параметри deep link / QR та правила взаємодії потрібно брати з офіційної документації Дії, яку надають після підключення партнера.

Технічний стек: Python 3.11+, FastAPI, PostgreSQL, SQLAlchemy, Alembic, httpx, Pydantic, Celery/RQ/APScheduler, Redis, Docker, S3-compatible file storage.

Управлінський результат: відповідальна особа повинна бачити, які документи очікують підпису, які підписані, які відхилені, які прострочені, які мають помилки callback, які потребують повтору або ручної перевірки.

1. Мета

Метою задачі є створення Python-сервісу для накладення електронного підпису за допомогою Дія.Підпис.

Сервіс повинен забезпечити:

  • створення заявки на підписання документа;
  • підготовку документа до підпису;
  • розрахунок hash документа, якщо це вимагається інтеграцією;
  • створення сесії підписання;
  • генерацію QR-коду або deep link для переходу в застосунок Дія;
  • відображення користувачу статусу підписання;
  • отримання callback / webhook від Дії;
  • отримання результату підписання;
  • збереження підпису;
  • збереження підписаного документа або контейнера;
  • перевірку підпису;
  • перевірку цілісності документа;
  • оновлення статусу документа в K2 ERP або іншій системі;
  • журналювання всіх подій;
  • контроль помилок;
  • dashboard для відповідальних осіб.

2. Область застосування

Інтеграція може використовуватись для:

  • договорів;
  • актів виконаних робіт;
  • рахунків;
  • заяв;
  • анкет;
  • кадрових документів;
  • первинних документів;
  • документів ЕДО;
  • документів K2 ERP;
  • документів, які формуються в CRM;
  • авторизації користувача через Дія.Підпис;
  • підтвердження дії користувача в системі.

3. Що таке Дія.Підпис у межах інтеграції

Дія.Підпис у межах цього ТЗ розглядається як зовнішній сервіс, який дозволяє користувачу підтвердити свою дію та накласти електронний підпис через застосунок Дія.

Параметр Опис
Тип сервісу Електронний підпис через застосунок Дія.
Основний сценарій Користувач відкриває QR/deep link, підтверджує підписання в застосунку, система отримує результат.
Результат Підпис, підписаний контейнер або дані підписання згідно з API Дії.
Формат результату Уточнюється за офіційною документацією Дії. Для багатьох КЕП-сценаріїв типовим є окремий файл підпису або контейнер.
Кінцева система K2 ERP / CRM / документообіг / сайт / мобільний застосунок.

Критично важливо: Дія.Підпис не повинен підміняти внутрішню систему зберігання документів. Python-сервіс повинен сам зберігати документ, підпис, статус, аудит і результат перевірки.

4. Передумови

Для реалізації задачі необхідно отримати:

  • партнерський доступ до інтеграції Дії;
  • офіційну документацію Дія.Підпис;
  • тестове середовище, якщо доступне;
  • client_id або аналогічний ідентифікатор партнера;
  • client_secret або інший секрет доступу;
  • сертифікати, якщо вони потрібні для взаємодії;
  • endpoint-и API Дії;
  • callback URL, який буде приймати результат;
  • правила формування QR/deep link;
  • правила формування запиту на підпис;
  • допустимі формати документів;
  • максимальний розмір документа;
  • правила зберігання результату підписання;
  • правила перевірки підпису;
  • контакт технічної підтримки Дії.

Критично важливо: без офіційної документації партнера Дії не можна фіксувати production endpoint-и, назви параметрів і формат callback як остаточні.

5. Основні сценарії інтеграції

5.1. Підписання одного документа

Користувач відкриває документ у K2 ERP або на сайті, натискає кнопку «Підписати через Дія.Підпис».

Система:

  • створює запис документа;
  • створює сесію підписання;
  • генерує QR/deep link;
  • показує QR користувачу;
  • очікує callback;
  • отримує результат;
  • зберігає підпис;
  • перевіряє підпис;
  • змінює статус документа на SIGNED.

5.2. Підписання пакета документів

Користувач підписує декілька документів за один бізнес-процес.

Система повинна:

  • створити пакет документів;
  • перевірити всі документи;
  • передати пакет на підписання, якщо це підтримується;
  • отримати результат по кожному документу;
  • показати частково підписані або помилкові документи;
  • не втратити статус окремого документа.

5.3. Підписання документа клієнтом

Клієнт отримує посилання на документ.

Система:

  • відкриває сторінку підписання;
  • показує коротку інформацію про документ;
  • показує QR/deep link;
  • клієнт підтверджує підписання в Дії;
  • система отримує результат;
  • документ стає підписаним клієнтом.

5.4. Підписання документа співробітником

Співробітник компанії підписує внутрішній документ.

Система:

  • створює задачу на підпис;
  • показує її у списку задач;
  • контролює строк підписання;
  • нагадує про прострочення;
  • зберігає аудит дій.

5.5. Авторизація через Дія.Підпис

Дія.Підпис може використовуватись не тільки для документа, а й для авторизації або підтвердження дії.

Система:

  • створює authorization session;
  • показує QR/deep link;
  • отримує підтвердження;
  • ідентифікує користувача згідно з дозволеним обсягом даних;
  • створює або оновлює сесію користувача.

6. Основні сутності

Сутність Опис
Signature Integration Налаштування підключення до Дія.Підпис.
Document Документ, який потрібно підписати.
Document Version Версія документа, яка передана на підпис.
Signature Request Заявка на підписання.
Signature Session Сесія взаємодії з Дією.
Signer Підписант.
Callback Event Подія, отримана від Дії.
Signature File Файл підпису або підписаний контейнер.
Verification Result Результат перевірки підпису.
Audit Event Подія журналу.

7. User Story

7.1. Користувач підписує документ

Як користувач, я хочу натиснути кнопку «Підписати через Дія.Підпис», щоб підписати документ без завантаження ключів у систему.

7.2. Менеджер контролює підписання

Як менеджер, я хочу бачити статус підписання документа, щоб знати, чи клієнт підписав документ.

7.3. Адміністратор перевіряє помилки

Як адміністратор, я хочу бачити callback-и, помилки API та технічний журнал, щоб швидко знаходити причини невдалого підписання.

7.4. Керівник бачить dashboard

Як керівник, я хочу бачити кількість документів на підписі, підписаних, відхилених і прострочених, щоб контролювати документообіг.

8. Статуси документа

Статус Код Опис Колір
Чернетка DRAFT Документ створений, але ще не готовий до підпису. Сірий
Готовий до підпису READY_TO_SIGN Документ перевірено і можна створювати заявку. Блакитний
Очікує підпису WAITING_SIGNATURE Користувачу створено QR/deep link. Жовтий
Підписується SIGNING Користувач відкрив процес підписання. Блакитний
Підписано SIGNED Підпис успішно отримано і збережено. Зелений
Підпис перевірено VERIFIED Підпис пройшов перевірку. Зелений
Відхилено користувачем DECLINED_BY_USER Користувач не підтвердив підписання. Помаранчевий
Прострочено EXPIRED Строк сесії підписання минув. Помаранчевий
Помилка підписання SIGN_ERROR Помилка під час підписання. Червоний
Помилка перевірки VERIFY_ERROR Підпис отримано, але перевірка не пройдена. Червоний
Ручна перевірка MANUAL_REVIEW Потрібна перевірка адміністратором. Фіолетовий

9. Статуси сесії підписання

Статус Код Опис Колір
Створюється CREATING Система створює сесію підписання. Блакитний
Активна ACTIVE QR/deep link доступний користувачу. Жовтий
Очікує callback WAITING_CALLBACK Користувач перейшов у Дію, система очікує результат. Жовтий
Завершена COMPLETED Сесія завершена успішно. Зелений
Відхилена DECLINED Користувач відхилив дію. Помаранчевий
Прострочена EXPIRED Сесія не завершена у строк. Помаранчевий
Помилка ERROR Технічна помилка. Червоний

10. Єдина логіка кольорів

Колір HTML Значення Де використовується
Зелений #c8e6c9 Успішно: підписано, перевірено, завершено. Dashboard, список документів, картка документа.
Блакитний #bbdefb Операція виконується. Створення сесії, підписання.
Жовтий #fff9c4 Очікування дії користувача або callback. Очікує підпису, активна сесія.
Помаранчевий #ffcc80 Потрібна дія або є ризик. Відхилено, прострочено.
Червоний #ef9a9a Помилка або негативний результат. Помилка підписання, помилка перевірки.
Фіолетовий #f3e5f5 Ручна перевірка або нестандартний сценарій. MANUAL_REVIEW.
Сірий #eeeeee Чернетка або архів. DRAFT, archived.

11. Архітектура рішення

11.1. Загальна схема

K2 ERP / CRM / Website
        |
        | 1. Документ на підпис
        v
Python Diia.Sign Integration Service
        |
        | 2. Валідація, hash, створення сесії
        v
Diia Adapter
        |
        | 3. API Дії / QR / deep link
        v
Застосунок Дія
        |
        | 4. Користувач підтверджує підписання
        v
Callback URL Python-сервісу
        |
        | 5. Результат підписання
        v
Signature Storage + Verification Service
        |
        | 6. Збереження, перевірка, статус
        v
K2 ERP / Dashboard / Документообіг

11.2. Основні компоненти Python-сервісу

Компонент Опис
API Layer REST API для створення заявок на підпис.
Document Service Робота з документами та версіями.
Signature Request Service Створення заявки на підписання.
Diia Client Python-клієнт для API Дії.
QR / Deep Link Service Генерація посилання або QR.
Callback Controller Прийом callback від Дії.
Signature Storage Зберігання підпису, контейнера, документа.
Verification Service Перевірка підпису та цілісності.
Status Sync Service Оновлення статусів у K2 ERP.
Audit Logger Журнал подій, callback-ів, помилок.
Dashboard API Дані для керівника та відповідальних осіб.

12. Diia Client

12.1. Призначення

Diia Client — це Python-клас або пакет, який інкапсулює роботу з API Дія.Підпис.

12.2. Основні методи

class DiiaSignatureClient:
    def check_connection(self) -> "ConnectionStatus":
        pass

    def authenticate(self) -> "AuthResult":
        pass

    def create_signature_session(self, payload: "CreateSignatureSessionPayload") -> "SignatureSessionResponse":
        pass

    def get_signature_session_status(self, session_id: str) -> "SignatureSessionStatusResponse":
        pass

    def get_signature_result(self, session_id: str) -> "SignatureResultResponse":
        pass

    def cancel_signature_session(self, session_id: str) -> "CancelSignatureSessionResponse":
        pass

Важливо: назви методів у Python-клієнті є внутрішньою абстракцією. Реальні endpoint-и і payload потрібно взяти з офіційної документації Дії для партнера.

13. Конфігурація

from pydantic_settings import BaseSettings


class DiiaSignatureSettings(BaseSettings):
    base_url: str
    client_id: str
    client_secret: str
    callback_url: str
    redirect_url: str | None = None
    timeout_seconds: int = 30
    retry_count: int = 3
    retry_backoff_seconds: int = 5
    verify_ssl: bool = True
    session_ttl_minutes: int = 15
    max_document_size_mb: int = 10

Приклад `.env`:

DIIA_SIGNATURE_BASE_URL=https://partner-api.example.diia
DIIA_SIGNATURE_CLIENT_ID=********
DIIA_SIGNATURE_CLIENT_SECRET=********
DIIA_SIGNATURE_CALLBACK_URL=https://example.com/api/v1/diia-signature/callback
DIIA_SIGNATURE_REDIRECT_URL=https://example.com/signature/result
DIIA_SIGNATURE_TIMEOUT_SECONDS=30
DIIA_SIGNATURE_RETRY_COUNT=3
DIIA_SIGNATURE_SESSION_TTL_MINUTES=15
DIIA_SIGNATURE_MAX_DOCUMENT_SIZE_MB=10

Заборонено: зберігати client_secret, приватні ключі, токени, callback secrets або інші секрети у коді, Git-репозиторії, frontend-змінних або відкритих логах.

14. API Python-сервісу

14.1. Створення інтеграції

POST /api/v1/diia-signature/integrations

14.2. Перевірка підключення

POST /api/v1/diia-signature/integrations/{integration_id}/check-connection

14.3. Створення документа

POST /api/v1/diia-signature/documents

14.4. Створення заявки на підпис

POST /api/v1/diia-signature/documents/{document_id}/signature-requests
GET /api/v1/diia-signature/signature-requests/{request_id}/link

14.6. Отримання статусу заявки

GET /api/v1/diia-signature/signature-requests/{request_id}/status

14.7. Callback від Дії

POST /api/v1/diia-signature/callback

14.8. Завантаження підписаного документа

GET /api/v1/diia-signature/documents/{document_id}/signed-file

14.9. Завантаження файлу підпису

GET /api/v1/diia-signature/documents/{document_id}/signature-file

14.10. Перевірка підпису

POST /api/v1/diia-signature/documents/{document_id}/verify

14.11. Dashboard

GET /api/v1/diia-signature/dashboard?date_from=2026-05-01&date_to=2026-05-31

15. Приклад запиту на створення заявки на підпис

{
  "external_document_id": "K2-DOC-2026-000123",
  "idempotency_key": "K2-DOC-2026-000123-sign-v1",
  "document_type": "CONTRACT",
  "document_name": "Договір поставки №123",
  "document_number": "123",
  "document_date": "2026-05-07",
  "file_id": "file-001",
  "file_name": "contract_123.pdf",
  "file_mime_type": "application/pdf",
  "signer": {
    "external_signer_id": "CLIENT-001",
    "full_name": "Іван Петренко",
    "phone": "+380671112233",
    "email": "client@example.com",
    "tax_id": "1234567890"
  },
  "callback_context": {
    "k2_entity": "contract",
    "k2_entity_id": "contract-001"
  },
  "expires_at": "2026-05-07T14:30:00+03:00"
}

16. Валідація документа перед підписом

Перед створенням заявки система повинна перевірити:

  • наявність external_document_id;
  • наявність idempotency_key;
  • наявність файлу документа;
  • файл доступний у сховищі;
  • файл не порожній;
  • розмір файлу не перевищує ліміт;
  • MIME type дозволений;
  • документ не був змінений після створення заявки;
  • hash документа збережений;
  • підписант визначений;
  • строк підписання не минув;
  • документ ще не підписаний цим підписантом;
  • бізнес-процес дозволяє підписання;
  • користувач має право ініціювати підписання.

Критично важливо: якщо документ змінено після створення заявки на підпис, попередня заявка повинна бути скасована або переведена в статус INVALIDATED. Не можна підписувати старий hash для нової версії документа.

17. Hash документа і версії

Для кожного документа потрібно зберігати:

Поле Опис
document_version_id ID версії документа.
file_hash_sha256 Hash файлу.
file_size Розмір файлу.
mime_type MIME type.
created_at Дата створення версії.
created_by Хто створив версію.

Приклад hash:

sha256(file_bytes)

18. Callback від Дії

Callback endpoint повинен:

  • приймати тільки HTTPS-запити;
  • перевіряти підпис або секрет callback, якщо передбачено API;
  • перевіряти session_id;
  • перевіряти request_id;
  • перевіряти idempotency callback;
  • зберігати raw payload;
  • оновлювати статус сесії;
  • зберігати файл підпису або посилання на результат;
  • запускати перевірку підпису;
  • повертати коректний HTTP status.

Критично важливо: callback повинен бути ідемпотентним. Якщо Дія або мережа повторно надішле той самий callback, система не повинна дублювати підпис або повторно змінювати фінальний статус некоректно.

19. Перевірка підпису

Після отримання результату підписання система повинна виконати перевірку.

Перевіряється:

  • цілісність документа;
  • відповідність підпису конкретній версії документа;
  • валідність підпису;
  • валідність сертифіката;
  • дані підписанта;
  • час підписання;
  • статус відкликання сертифіката, якщо доступно;
  • чи відповідає підписант очікуваному користувачу;
  • чи не минув строк сесії;
  • чи не змінювався документ після підпису.

Можливі результати:

Результат Код Опис Колір
Валідний VALID Підпис пройшов перевірку. Зелений
Невалідний INVALID Підпис не пройшов перевірку. Червоний
Не той документ HASH_MISMATCH Hash документа не збігається. Червоний
Не той підписант SIGNER_MISMATCH Підписант не відповідає очікуваному. Червоний
Потребує ручної перевірки MANUAL_REVIEW Неможливо автоматично визначити результат. Фіолетовий

20. Дедублікація

Система повинна не допускати дублювання заявок і підписів.

Ключі дедублікації:

Ключ Призначення
external_document_id ID документа в K2 ERP.
document_version_id Версія документа.
signer_id Підписант.
idempotency_key Унікальний ключ заявки.
diia_session_id ID сесії в Дії.
callback_event_id ID callback-події, якщо надається.
file_hash_sha256 Hash документа.

21. Черга обробки

21.1. Логіка черги

1. K2 ERP створює документ.
2. Користувач натискає «Підписати через Дія».
3. Python-сервіс перевіряє документ.
4. Створюється signature_request.
5. Створюється signature_session.
6. Користувачу показується QR/deep link.
7. Callback Controller приймає результат.
8. Signature Storage зберігає підпис.
9. Verification Service перевіряє підпис.
10. K2 ERP отримує фінальний статус.

21.2. Пріоритети задач

Задача Пріоритет Коментар
Прийом callback Критичний Не можна втрачати результат підписання.
Збереження підпису Критичний Юридично значущий результат.
Перевірка підпису Високий Потрібна для фінального статусу.
Створення сесії Високий Основний сценарій користувача.
Оновлення dashboard Середній Контроль.
Нагадування про прострочення Низький Фоновий процес.

22. Модель даних

22.1. diia_signature_integrations

Поле Тип Опис
id uuid ID інтеграції.
provider varchar diia_signature.
name varchar Назва інтеграції.
base_url varchar URL API.
client_id varchar ID партнера.
client_secret_encrypted text Зашифрований секрет.
callback_url varchar Callback URL.
redirect_url varchar URL повернення користувача.
is_active boolean Активність.
created_at timestamp Дата створення.
updated_at timestamp Дата оновлення.

22.2. sign_documents

Поле Тип Опис
id uuid ID документа.
external_document_id varchar ID документа в K2 ERP.
document_type varchar CONTRACT, ACT, APPLICATION тощо.
document_name varchar Назва документа.
document_number varchar Номер документа.
document_date date Дата документа.
current_version_id uuid Поточна версія.
status varchar Статус документа.
created_at timestamp Дата створення.

22.3. sign_document_versions

Поле Тип Опис
id uuid ID версії.
document_id uuid ID документа.
file_id uuid Файл документа.
file_name varchar Назва файлу.
mime_type varchar MIME type.
file_size integer Розмір файлу.
file_hash_sha256 varchar Hash файлу.
version_number integer Номер версії.
created_at timestamp Дата створення.

22.4. signature_requests

Поле Тип Опис
id uuid ID заявки.
document_id uuid Документ.
document_version_id uuid Версія документа.
signer_id uuid Підписант.
idempotency_key varchar Ключ дедублікації.
status varchar Статус заявки.
expires_at timestamp Строк дії.
created_by uuid Хто створив заявку.
created_at timestamp Дата створення.

22.5. signature_sessions

Поле Тип Опис
id uuid ID сесії.
signature_request_id uuid Заявка.
diia_session_id varchar ID сесії в Дії.
qr_payload text Дані QR, якщо зберігаються.
deep_link text Deep link.
status varchar Статус сесії.
raw_request jsonb Запит до Дії.
raw_response jsonb Відповідь Дії.
created_at timestamp Дата створення.
expires_at timestamp Дата завершення.

22.6. signature_files

Поле Тип Опис
id uuid ID файлу підпису.
signature_request_id uuid Заявка.
file_id uuid Файл у сховищі.
file_type varchar signature, signed_container, signed_pdf.
file_hash_sha256 varchar Hash файлу.
created_at timestamp Дата створення.

22.7. signature_verifications

Поле Тип Опис
id uuid ID перевірки.
signature_request_id uuid Заявка.
result varchar VALID, INVALID, HASH_MISMATCH тощо.
signer_name varchar ПІБ підписанта з сертифіката.
signer_identifier varchar Ідентифікатор підписанта, якщо доступний.
signed_at timestamp Час підписання.
certificate_info jsonb Дані сертифіката.
raw_result jsonb Повний результат перевірки.
created_at timestamp Дата перевірки.

22.8. signature_events

Поле Тип Опис
id uuid ID події.
entity_type varchar document, request, session, callback, verification.
entity_id uuid ID сутності.
event_type varchar Тип події.
old_status varchar Попередній статус.
new_status varchar Новий статус.
source varchar K2_ERP, PYTHON_SERVICE, DIIA, USER.
payload jsonb Технічні дані.
created_at timestamp Дата події.

23. Приклад Python-логіки

23.1. Створення заявки на підпис

from hashlib import sha256
from datetime import datetime, timezone


def create_signature_request(command: "CreateSignatureRequestCommand", db: "Session") -> "SignatureRequest":
    existing = signature_request_repository.get_by_idempotency_key(
        db=db,
        idempotency_key=command.idempotency_key,
    )

    if existing:
        return existing

    document = document_repository.get_by_external_id(
        db=db,
        external_document_id=command.external_document_id,
    )

    signature_validator.validate_document_for_signing(document, command)

    request = signature_request_repository.create(
        db=db,
        data={
            "document_id": document.id,
            "document_version_id": document.current_version_id,
            "signer_id": command.signer_id,
            "idempotency_key": command.idempotency_key,
            "status": "CREATING",
            "expires_at": command.expires_at,
        },
    )

    signature_queue.enqueue(
        task_name="create_diia_signature_session",
        payload={"signature_request_id": str(request.id)},
    )

    audit_logger.log(
        entity_type="signature_request",
        entity_id=request.id,
        event_type="SIGNATURE_REQUEST_CREATED",
        new_status="CREATING",
        payload={"external_document_id": command.external_document_id},
    )

    db.commit()
    return request

23.2. Створення сесії Дія.Підпис

async def create_diia_signature_session(signature_request_id: str, db: "Session") -> None:
    request = signature_request_repository.get_by_id(db, signature_request_id)
    document_version = document_version_repository.get_by_id(db, request.document_version_id)

    try:
        payload = diia_mapper.to_signature_session_payload(
            request=request,
            document_version=document_version,
        )

        response = await diia_client.create_signature_session(payload)

        session = signature_session_repository.create(
            db=db,
            data={
                "signature_request_id": request.id,
                "diia_session_id": response.session_id,
                "qr_payload": response.qr_payload,
                "deep_link": response.deep_link,
                "status": "ACTIVE",
                "raw_request": payload,
                "raw_response": response.raw_payload,
                "expires_at": response.expires_at,
            },
        )

        request.status = "WAITING_SIGNATURE"

        audit_logger.log(
            entity_type="signature_session",
            entity_id=session.id,
            event_type="DIIA_SIGNATURE_SESSION_CREATED",
            new_status="ACTIVE",
            payload={"diia_session_id": response.session_id},
        )

    except Exception as exc:
        request.status = "SIGN_ERROR"
        audit_logger.log(
            entity_type="signature_request",
            entity_id=request.id,
            event_type="DIIA_SIGNATURE_SESSION_ERROR",
            new_status="SIGN_ERROR",
            payload={"error": str(exc)},
        )

    finally:
        db.commit()

23.3. Callback controller

from fastapi import APIRouter, Request, HTTPException

router = APIRouter()


@router.post("/api/v1/diia-signature/callback")
async def diia_signature_callback(request: Request):
    payload = await request.json()

    # Перевірка callback signature / secret залежить від офіційної документації Дії.
    if not callback_security_service.is_valid(request, payload):
        raise HTTPException(status_code=401, detail="Invalid callback signature")

    callback_id = callback_service.get_callback_id(payload)

    if callback_repository.exists(callback_id):
        return {"status": "already_processed"}

    callback_event = callback_repository.create_raw_event(payload)

    signature_session = signature_session_repository.get_by_diia_session_id(
        diia_session_id=payload["session_id"],
    )

    if not signature_session:
        callback_event.status = "UNKNOWN_SESSION"
        return {"status": "unknown_session"}

    callback_processor.process_signature_result(
        signature_session=signature_session,
        payload=payload,
    )

    return {"status": "ok"}

23.4. Обробка результату підписання

def process_signature_result(signature_session: "SignatureSession", payload: dict) -> None:
    request = signature_session.signature_request

    if payload.get("status") == "declined":
        signature_session.status = "DECLINED"
        request.status = "DECLINED_BY_USER"
        return

    if payload.get("status") != "signed":
        signature_session.status = "ERROR"
        request.status = "SIGN_ERROR"
        return

    signature_file = signature_storage.save_signature_result(
        signature_request_id=request.id,
        payload=payload,
    )

    signature_session.status = "COMPLETED"
    request.status = "SIGNED"

    verification_queue.enqueue(
        task_name="verify_signature",
        payload={
            "signature_request_id": str(request.id),
            "signature_file_id": str(signature_file.id),
        },
    )

23.5. Перевірка підпису

def verify_signature(signature_request_id: str, signature_file_id: str, db: "Session") -> None:
    request = signature_request_repository.get_by_id(db, signature_request_id)
    document_version = document_version_repository.get_by_id(db, request.document_version_id)
    signature_file = signature_file_repository.get_by_id(db, signature_file_id)

    try:
        result = signature_verifier.verify(
            document_file_id=document_version.file_id,
            signature_file_id=signature_file.file_id,
            expected_hash=document_version.file_hash_sha256,
        )

        verification = signature_verification_repository.create(
            db=db,
            data={
                "signature_request_id": request.id,
                "result": result.code,
                "signer_name": result.signer_name,
                "signer_identifier": result.signer_identifier,
                "signed_at": result.signed_at,
                "certificate_info": result.certificate_info,
                "raw_result": result.raw,
            },
        )

        if result.code == "VALID":
            request.status = "VERIFIED"
            request.document.status = "VERIFIED"
        else:
            request.status = "VERIFY_ERROR"

    except Exception as exc:
        request.status = "MANUAL_REVIEW"
        audit_logger.log(
            entity_type="signature_request",
            entity_id=request.id,
            event_type="SIGNATURE_VERIFY_EXCEPTION",
            new_status="MANUAL_REVIEW",
            payload={"error": str(exc)},
        )

    finally:
        db.commit()

24. Обробка помилок

Тип помилки Опис Дія системи
ValidationError Документ або підписант невалідний. Не створювати сесію.
AuthError Невірні credentials Дії. Зупинити інтеграцію і повідомити адміністратора.
DocumentChangedError Документ змінено після заявки. Скасувати заявку або створити нову.
FileTooLargeError Документ перевищує ліміт. Показати користувачу помилку.
SessionExpiredError Сесія підписання прострочена. Статус EXPIRED, дозволити створити нову.
CallbackValidationError Callback не пройшов перевірку. Відхилити callback і записати подію.
SignatureResultError Не вдалося отримати результат підпису. Перевести в SIGN_ERROR або NEEDS_RETRY.
VerificationError Підпис не пройшов перевірку. Статус VERIFY_ERROR.
SignerMismatchError Підписант не відповідає очікуваному. Статус MANUAL_REVIEW або VERIFY_ERROR.
TimeoutError API недоступне або timeout. Retry, якщо безпечно.

25. Retry-логіка

Retry дозволений для:

  • timeout;
  • HTTP 429;
  • HTTP 500;
  • HTTP 502;
  • HTTP 503;
  • HTTP 504;
  • тимчасової помилки створення сесії;
  • тимчасової помилки отримання статусу;
  • тимчасової помилки перевірки підпису;
  • повторного callback з тим самим callback_id.

Retry заборонений для:

  • невалідного документа;
  • документа, який змінився;
  • простроченої сесії;
  • відхилення користувачем;
  • невірного callback signature;
  • невідповідності підписанта;
  • вже фінального статусу VERIFIED.

26. Dashboard керівника

26.1. Основні KPI

KPI Опис Колір
Документів створено Загальна кількість документів. Інформація
Очікують підпису Документи з активною сесією. Увага
Підписано Підпис отримано. Норма
Перевірено Підпис пройшов перевірку. Норма
Відхилено Користувач відмовився. Потрібна дія
Прострочено Сесія не завершена вчасно. Потрібна дія
Помилки Помилки підписання або callback. Критично
Ручна перевірка Потрібне втручання адміністратора. Контроль

26.2. Приклад dashboard

Показник Значення Стан
Документів за день 184 Інформація
Очікують підпису 32 Увага
Підписано 128 Норма
Перевірено 126 Норма
Відхилено 8 Потрібна дія
Прострочено 10 Потрібна дія
Помилки callback 3 Критично
Ручна перевірка 2 Контроль

26.3. Проблемні документи

Дата Документ Підписант Статус Причина Дія
07.05.2026 Договір №123 Іван Петренко Прострочено Користувач не завершив підписання Створити нову заявку
07.05.2026 Акт №45 Олена Сидоренко Помилка перевірки Hash документа не збігається Ручна перевірка
07.05.2026 Заява №77 ТОВ «Альфа» Ручна перевірка Неможливо автоматично визначити підписанта Перевірити сертифікат

27. Безпека

Система повинна забезпечити:

  • HTTPS для всіх endpoint-ів;
  • перевірку SSL;
  • зберігання секретів тільки в secret storage;
  • шифрування файлів підпису;
  • шифрування документів або контроль доступу до них;
  • обмеження доступу до callback endpoint;
  • перевірку callback signature / secret;
  • ідемпотентність callback;
  • журнал усіх дій;
  • маскування персональних даних у логах;
  • контроль доступу до документів;
  • окремі права на створення заявки;
  • окремі права на повторне підписання;
  • окремі права на ручну перевірку;
  • заборону підписання зміненої версії документа.

28. Логування та аудит

Система повинна логувати:

Подія Що зберігати
Створення документа Тип, номер, версія, hash.
Створення заявки Підписант, строк дії, ініціатор.
Створення сесії Дія diia_session_id, статус, expires_at.
Відкриття QR/deep link request_id, час.
Callback callback_id, raw payload, статус перевірки.
Отримання підпису file_id, hash підпису, час.
Перевірка підпису результат, підписант, сертифікат.
Помилка код, повідомлення, stack trace без секретів.
Ручна перевірка хто перевірив, рішення, коментар.

29. Acceptance Criteria

29.1. Інтеграція

Критерій Очікуваний результат
AC-1 Адміністратор створює інтеграцію Дія.Підпис. Інтеграція зберігається в системі.
AC-2 Адміністратор перевіряє підключення. Система повертає успішний або помилковий статус.
AC-3 Credentials неправильні. Система показує AuthError і не створює сесії.

29.2. Документ

Критерій Очікуваний результат
AC-4 Документ валідний. Система створює заявку на підпис.
AC-5 Документ перевищує ліміт розміру. Заявка не створюється.
AC-6 Документ змінено після створення заявки. Попередня заявка стає INVALIDATED або скасовується.

29.3. Підписання

Критерій Очікуваний результат
AC-7 Користувач натискає «Підписати через Дія». Система показує QR/deep link.
AC-8 Користувач підписує документ. Система отримує callback і зберігає підпис.
AC-9 Користувач відхиляє підписання. Статус стає DECLINED_BY_USER.
AC-10 Сесія прострочена. Статус стає EXPIRED.

29.4. Перевірка

Критерій Очікуваний результат
AC-11 Підпис валідний. Статус стає VERIFIED.
AC-12 Hash документа не збігається. Статус стає VERIFY_ERROR.
AC-13 Підписант не відповідає очікуваному. Статус стає MANUAL_REVIEW або VERIFY_ERROR.

29.5. Callback

Критерій Очікуваний результат
AC-14 Callback має правильний підпис/секрет. Система приймає callback.
AC-15 Callback повторився. Система не дублює результат.
AC-16 Callback невалідний. Система повертає помилку і записує подію.

29.6. Dashboard

Критерій Очікуваний результат
AC-17 Керівник відкриває dashboard. Він бачить документи, підписи, помилки, прострочення.
AC-18 Є помилки підписання. Вони підсвічуються червоним.
AC-19 Є прострочені заявки. Вони підсвічуються помаранчевим.
AC-20 Є документи на ручній перевірці. Вони підсвічуються фіолетовим.

30. MVP

До MVP входить:

  • створення інтеграції Дія.Підпис;
  • перевірка підключення;
  • створення документа;
  • збереження версії документа;
  • розрахунок hash;
  • створення заявки на підпис;
  • створення сесії підписання;
  • QR/deep link;
  • callback endpoint;
  • збереження результату підписання;
  • базова перевірка підпису;
  • статуси документа;
  • журнал подій;
  • dashboard API;
  • retry для технічних помилок;
  • ідемпотентність callback;
  • unit-тести;
  • mock Diia client.

До MVP не входить:

  • масове підписання великого пакета документів;
  • складний UI документообігу;
  • власний кваліфікований надавач електронних довірчих послуг;
  • повна юридична експертиза документів;
  • інтеграція з усіма зовнішніми ЕДО-системами;
  • автоматичне виправлення документів;
  • архів довгострокового зберігання за окремими регламентами.

31. Етапи реалізації

Етап 1. Аналіз інтеграції Дія.Підпис

  • отримати партнерську документацію;
  • отримати тестові credentials;
  • погодити callback URL;
  • перевірити тестовий сценарій;
  • визначити формат результату підписання;
  • визначити правила перевірки підпису.

Етап 2. Базовий Python-сервіс

  • створити FastAPI-проєкт;
  • налаштувати PostgreSQL;
  • створити моделі документів, заявок, сесій, підписів;
  • налаштувати Alembic;
  • реалізувати healthcheck.

Етап 3. Diia Client

  • реалізувати authenticate;
  • реалізувати create_signature_session;
  • реалізувати get_signature_session_status;
  • реалізувати get_signature_result;
  • реалізувати обробку помилок.

Етап 4. Документи

  • реалізувати завантаження документа;
  • реалізувати версіонування;
  • реалізувати hash;
  • реалізувати валідацію;
  • реалізувати дедублікацію.

Етап 5. Callback та підпис

  • реалізувати callback endpoint;
  • реалізувати перевірку callback;
  • реалізувати збереження результату;
  • реалізувати ідемпотентність;
  • реалізувати raw event storage.

Етап 6. Перевірка підпису

  • реалізувати Verification Service;
  • реалізувати статуси перевірки;
  • реалізувати ручну перевірку;
  • реалізувати журнал перевірок.

Етап 7. Dashboard та аудит

  • реалізувати dashboard API;
  • реалізувати список проблемних документів;
  • реалізувати фільтри;
  • реалізувати експорт, якщо потрібно.

Етап 8. Production hardening

  • додати rate limiting;
  • додати alerting;
  • додати dead letter queue;
  • додати backup файлів;
  • додати моніторинг callback;
  • додати безпечне зберігання секретів.

32. Ризики

Ризик Опис Як зменшити
Немає партнерського доступу Без доступу неможливо реалізувати production інтеграцію. Отримати доступ до старту розробки.
Документ змінено після заявки Можна підписати неактуальну версію. Версіонування і hash документа.
Callback втрачено Система не дізнається про результат. Callback retry, polling статусу, журнал raw events.
Дублювання callback Може повторно змінити статус. Ідемпотентність callback.
Невідомий формат підпису Неможливо зберегти/перевірити результат. Уточнити формат за документацією Дії.
Невідповідність підписанта Документ підписала не та особа. Перевірка даних сертифіката.
Помилка перевірки Підпис отримано, але не підтверджено. MANUAL_REVIEW і аудит.
Прострочені сесії Користувач не завершив підписання. TTL, нагадування, повторна заявка.

33. Відкриті питання

  1. Чи вже є партнерський доступ до Дія.Підпис?
  2. Який точний формат результату підписання: p7s, ASIC, PDF з підписом або інший?
  3. Чи потрібно підписувати PDF, XML, DOCX або будь-який файл?
  4. Який максимальний розмір документа?
  5. Чи потрібне пакетне підписання?
  6. Чи потрібна авторизація через Дія.Підпис?
  7. Чи потрібно підписувати документи клієнтами, співробітниками або обома?
  8. Чи потрібно перевіряти РНОКПП / ЄДРПОУ підписанта?
  9. Чи потрібна інтеграція з K2 ERP?
  10. Чи потрібно зберігати підписані документи в архіві довгострокового зберігання?
  11. Чи потрібен UI для підписанта?
  12. Чи потрібні email/SMS-нагадування?
  13. Який строк дії сесії підписання?
  14. Який callback security mechanism надає Дія?
  15. Чи потрібна інтеграція з ЕДО-системами після підписання?

34. Джерела

  • Офіційна сторінка інтеграції Дії.
  • Офіційна сторінка Дія.Підпис для партнерів.
  • Офіційний FAQ Дія.Підпис.
  • Офіційний сервіс КЕП Дії.
  • Партнерська API-документація Дії, яка надається після підключення.
  • Документація K2 ERP щодо документів і бізнес-процесів.

35. Див. також