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

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

Матеріал з K2 ERP Wiki
 

'''критично:''' назви методів у Python-клієнті виступає як внутрішньою абстракцією. SEO-опис
 db.commit()

 "callback_context": {
Як користувач системи, 
 callback_event.status = "UNKNOWN_SESSION"

 return

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

== 20. Дедублікація ==
! Стан
 )
8. |-
| current_version_id
| uuid
| Поточна реліз системи. | style="background:#fff9c4;" | Жовтий
|-
| Завершена
| COMPLETED
| Сесія завершена успішно. |-
| id
| uuid
| ID інтеграції. Ключ

<syntaxhighlight lang="python">

 db=db,
 payload={
 session_ttl_minutes: int = 15

 },

 return
</syntaxhighlight>
 existing = signature_request_repository.get_by_idempotency_key(

 request.status = "SIGN_ERROR"

 payload = diia_mapper.to_signature_session_payload(
 "external_signer_id": "CLIENT-001",
'''Управлінський результат:''' відповідальна особа повинна бачити, які документи очікують підпису, які підписані, які відхилені, які прострочені, які мають помилки callback, які потребують повтору або ручної перевірки. |-
| style="background:#bbdefb;" | Блакитний
| #bbdefb
| операційна дія виконується. |-
| Verification Result
| Результат перевірки підпису. # Який максимальний розмір документа? |-
| file_hash_sha256
| Hash файлу. ! async def create_diia_signature_session(signature_request_id: str, db: "Session") -> None:

== 25. Retry-логіка ==
! |-
| Document
| Документ, який потрібно підписати. | Статус стає DECLINED_BY_USER. )

* [[Python]]
* [[FastAPI]]
* [[K2 ERP]]
* [[Дія]]
* [[Дія.Підпис]]
* [[Diia.Signature]]
* [[КЕП]]
* [[Електронний підпис]]
* [[Електронний документообіг]]
* [[Callback]]
* [[Webhook]]
* [[p7s]]
* [[Підписання документів]]
* [[API інтеграція]]

! |}

diia_session_id=payload ["session_id"],

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

</syntaxhighlight> def process_signature_result(signature_session: "SignatureSession", payload: dict) -> None: |- | id | uuid | ID перевірки. |- | Формат результату | Уточнюється за офіційною документацією Дії. я хочу бачити callback-и, помилки API та технічний журнал,

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

signature_file = signature_file_repository.get_by_id(db, signature_file_id)

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

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

платформа: |- | Валідний | VALID | Підпис пройшов перевірку. ! |- | signer_id | uuid | Підписант. |- | event_type | varchar | Тип події. |}

signature_session.status = "COMPLETED"

</syntaxhighlight>

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

)
else:

|- | AC-11 | Підпис валідний. | Ідемпотентність callback. Поле

signature_request_id=request.id,

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

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

! |-
| file_hash_sha256
| varchar
| Hash файлу. |-
| old_status
| varchar
| Попередній статус. |-
| Створення сесії
| Високий
| базовий сценарій користувача. | MANUAL_REVIEW. |-
| is_active
| boolean
| Активність. |-
| Ручна перевірка
| хто перевірив, рішення для бізнесу, коментар. Документ вважається підписаним лише після отримання підтвердженого результату підписання. Результат підписання
__TOC__
 if not signature_session:
 |
 | 6. | style="background:#f3e5f5;" | Контроль
|}

 )

from hashlib import sha256
! |-
| Diia Client
| Python-клієнт для API Дії. | Статус EXPIRED, дозволити створити нову. SEO-опис

=== 22.1. diia_signature_integrations ===
 event_type="DIIA_SIGNATURE_SESSION_ERROR",
GET /api/v1/diia-signature/documents/{document_id}/signed-file
 def get_signature_session_status(self, session_id: str) -> "SignatureSessionStatusResponse":
|-
| id
| uuid
| ID сесії. |-
| new_status
| varchar
| Новий статус. |}

! | платформа показує AuthError і не створює сесії. |-
| created_at
| timestamp
| Дата створення. |}

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

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

 task_name="create_diia_signature_session",
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
 if existing:
щоб підписати документ без завантаження ключів у систему. |-
| VerificationError
| Підпис не пройшов перевірку. №
 request.status = "SIGNED"

<pre>

 "signer_id": command.signer_id,
{| class="wikitable"
 db=db,
== 16. Валідація документа перед підписом ==
'''Критично критично:''' без офіційної документації партнера Дії не можна фіксувати production endpoint-и, назви параметрів і формат callback як остаточні. | Очікує підпису, активна сесія. |-
| document_version_id
| uuid
| реліз системи документа. |-
| Callback Event
| Подія, отримана від Дії. |-
| document_version_id
| реліз системи документа. # Чи потрібен UI для підписанта? |-
| Збереження підпису
| Критичний
| Юридично значущий результат. | інтеграційні функції ERP зберігається в системі. {| class="wikitable"

* реалізувати dashboard API;
* реалізувати список проблемних документів;
* реалізувати фільтри;
* реалізувати експорт, якщо потрібно. Документ на підпис
платформа повинна не допускати дублювання заявок і підписів. |-
| source
| varchar
| K2_ERP, PYTHON_SERVICE, DIIA, USER. | Він бачить документи, підписи, помилки, прострочення. Поле

! |-
| AC-9
| користувач системи відхиляє підписання. Підписант

! |-
| name
| varchar
| Назва інтеграції. |
 | 3. result = signature_verifier.verify(

=== 29.3. Підписання ===
платформа повинна забезпечити:
=== 14.1. Створення інтеграції ===

 "tax_id": "1234567890"
<pre>
! |-
| created_at
| timestamp
| Дата створення. |-
| signed_at
| timestamp
| Час підписання. |-
| expires_at
| timestamp
| Дата завершення. |-
| file_name
| varchar
| Назва файлу. event_type="SIGNATURE_REQUEST_CREATED",
 new_status="ACTIVE",
<div style="border-left: 6px solid #f57c00; background: #fff3e0; padding: 12px 16px; margin: 16px 0;">
== 12. Diia Client ==

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

== 14. API Python-сервісу ==
=== 23.3. Callback controller ===
== 19. Перевірка підпису ==
 },
{| class="wikitable"
 def authenticate(self) -> "AuthResult":
1. |-
| external_document_id
| ID документа в K2 ERP. Тип

* Офіційна сторінка інтеграції Дії. |-
| document_id
| uuid
| Документ. | платформа повертає помилку і записує подію. | Статус стає VERIFIED. |-
| external_document_id
| varchar
| ID документа в K2 ERP. |-
| Audit Logger
| Журнал подій, callback-ів, помилок. K2 ERP / CRM / Website
 |
 | 2. |-
| document_type
| varchar
| CONTRACT, ACT, APPLICATION тощо. | style="background:#bbdefb;" | Блакитний
|-
| Активна
| ACTIVE
| QR/deep link доступний користувачу. | Статус MANUAL_REVIEW або VERIFY_ERROR. |-
| Відкриття QR/deep link
| request_id, час. * створює запис документа;
* створює сесію підписання;
* генерує QR/deep link;
* показує QR користувачу;
* очікує callback;
* отримує результат;
* зберігає підпис;
* перевіряє підпис;
* змінює статус документа на SIGNED. Signature Storage зберігає підпис. |-
| idempotency_key
| Унікальний ключ заявки. | Скасувати заявку або створити нову. |-
| Отримання підпису
| file_id, hash підпису, час. KPI
 v
 return {"status": "ok"}

== 29. Acceptance Criteria ==
 if payload.get("status") == "declined":
 idempotency_key=command.idempotency_key,

! |-
| created_at
| timestamp
| Дата створення. |-
| базовий сценарій
| користувач системи відкриває QR/deep link, підтверджує підписання в застосунку, платформа отримує результат. Колір
 try:
|-
| Документів за день
| 184
| style="background:#e3f2fd;" | інформаційні матеріали
|-
| Очікують підпису
| 32
| style="background:#fff9c4;" | Увага
|-
| Підписано
| 128
| style="background:#c8e6c9;" | Норма
|-
| Перевірено
| 126
| style="background:#c8e6c9;" | Норма
|-
| Відхилено
| 8
| style="background:#ffcc80;" | Потрібна дія
|-
| Прострочено
| 10
| style="background:#ffcc80;" | Потрібна дія
|-
| Помилки callback
| 3
| style="background:#ef9a9a;" | Критично
|-
| Ручна перевірка
| 2
| style="background:#f3e5f5;" | Контроль
|}

entity_id=request.id,

</syntaxhighlight> ! |- | entity_id | uuid | ID сутності. До MVP не входить:

! SEO-опис ! | Статус стає VERIFY_ERROR. Пріоритет

! Документ ! |- | Перевірка підпису | Високий | Потрібна для фінального статусу. |- | AC-3 | Credentials неправильні. # Чи потрібно підписувати PDF, XML, DOCX або будь-який файл? |}

v
payload={"diia_session_id": response.session_id},

22.3. sign_document_versions

AC-4 Документ валідний. Verification Service перевіряє підпис. }, Співробітник компанії підписує внутрішній документ.
callback_event = callback_repository.create_raw_event(payload)
)
Signature Integration конфігурація підключення до Дія.Підпис. GET /api/v1/diia-signature/signature-requests/{request_id}/link
"signer_name": result.signer_name,
}
payload={"signature_request_id": str(request.id)},

5. |-

file_hash_sha256 - Dashboard API інформаційні дані для керівника та відповідальних осіб. Задача Уточнити формат за документацією Дії. "document_id": document.id,

sha256(file_bytes)

платформа:

  • відкриває сторінку підписання;
  • показує коротку інформацію про документ;
  • показує QR/deep link;
  • клієнт ERP підтверджує підписання в Дії;
  • платформа отримує результат;
  • документ стає підписаним клієнтом. Значення
"raw_request": payload,
request.status = "SIGN_ERROR"

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

AC-16 платформа не дублює результат. request.status = "VERIFIED" я хочу бачити статус підписання документа,
  • створити пакет документів;
  • перевірити всі документи;
  • передати пакет на підписання, якщо це підтримується;
  • отримати результат по кожному документу;
  • показати частково підписані або помилкові документи;
  • не втратити статус окремого документа. |-
Фіолетовий #f3e5f5 - version_number integer style="background:#fff9c4;" | Жовтий
Очікує callback WAITING_CALLBACK - created_at - signer_identifier varchar - signer_id style="background:#ef9a9a;" | Червоний
Ручна перевірка MANUAL_REVIEW }
callback_id = callback_service.get_callback_id(payload)
"phone": "+380671112233",
entity_type="signature_request",

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

Document Service - Document Version style="background:#ffcc80;" | Помаранчевий
Прострочена EXPIRED - created_by uuid Хто створив заявку.

7. | style="background:#ffcc80;" | Помаранчевий

Прострочено EXPIRED Відхилено, прострочено. | Перевести в SIGN_ERROR або NEEDS_RETRY. Значення

async def diia_signature_callback(request: Request):

v

Python Diia.Sign Integration Service

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

"signature_request_id": request.id,
платформа показує QR/deep link. SEO-опис Що зберігати

router = APIRouter() GET /api/v1/diia-signature/signature-requests/{request_id}/status

"file_mime_type": "application/pdf",

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

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

34. Джерела

Статус стає MANUAL_REVIEW або VERIFY_ERROR. |}

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

  • timeout;
  • HTTP 429;
  • HTTP 500;
  • HTTP 502;
  • HTTP 503;
  • HTTP 504;
  • тимчасової помилки створення сесії;
  • тимчасової помилки отримання статусу;
  • тимчасової помилки перевірки підпису;
  • повторного callback з тим самим callback_id. |-
created_at timestamp Дата події. payload = await request.json() Вони підсвічуються червоним. SEO-опис - AC-13 Підписант не відповідає очікуваному. Тип помилки

32. Ризики

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

платформа створює заявку на підпис. | Показати користувачу помилку. # Чи потрібні email/SMS-нагадування? |- AuthError Невірні credentials Дії. Колір
- Audit Event - Помилка код, повідомлення, stack trace без секретів. Очікуваний результат

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


! | Dashboard, список документів, картка документа. |-
| FileTooLargeError
| Документ перевищує ліміт. |}

 "signer": {

{| class="wikitable"
 signature_session = signature_session_repository.get_by_diia_session_id(
 max_document_size_mb: int = 10

!<pre>
== 30. MVP ==
|-
| AC-14
| Callback має правильний підпис/секрет. Тип

<div style="border-left: 6px solid #f57c00; background: #fff3e0; padding: 12px 16px; margin: 16px 0;">
{| class="wikitable"


 except Exception as exc:
 "status": "CREATING",
! Сутність
=== 21.2. Пріоритети задач ===
=== 11.1. Загальна схема ===
|-
| id
| uuid
| ID події.</syntaxhighlight>

* додати rate limiting;
* додати alerting;
* додати dead letter queue;
* додати backup файлів;
* додати моніторинг callback;
* додати безпечне зберігання секретів. | style="background:#ef9a9a;" | Червоний
|-
| Не той документ
| HASH_MISMATCH
| Hash документа не збігається. |}

4. Дія системи
щоб оперативно знаходити причини невдалого підписання. |-
| updated_at
| timestamp
| Дата оновлення версій. Поле
платформа повинна логувати:

 "qr_payload": response.qr_payload,
 payload=payload,
 "raw_result": result.raw,
Як керівник, 
=== 23.5. Перевірка підпису ===
! * Партнерська API-документація Дії, яка надається після підключення. |-
| callback_url
| varchar
| Callback URL. "expires_at": "2026-05-07T14:30:00+03:00"

<pre>

 signature_session.status = "DECLINED"
 )
=== 22.4. signature_requests ===
<syntaxhighlight lang="json">
|-
| Документів створено
| Загальна кількість документів. {| class="wikitable"

* реалізувати callback endpoint;
* реалізувати перевірку callback;
* реалізувати збереження результату;
* реалізувати ідемпотентність;
* реалізувати raw event storage. | style="background:#c8e6c9;" | Зелений
|-
| Відхилено користувачем
| DECLINED_BY_USER
| користувач системи не підтвердив підписання. | Перевірка даних сертифіката. | Статус VERIFY_ERROR. Поле
|-
| API Layer
| REST API для створення заявок на підпис. Retry дозволений для:
@router.post("/api/v1/diia-signature/callback")


== 15. Приклад запиту на створення заявки на підпис ==
== 27. Безпека ==
=== 14.5. Отримання QR/deep link ===
"file_id": "file-001",

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

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

11. технічна архітектура рішення для бізнесу

new_status="SIGN_ERROR",

from datetime import datetime, timezone

timeout_seconds: int = 30

Критично критично: платформа не повинна вважати документ підписаним тільки після відкриття QR-коду або переходу в застосунок Дія. SEO-опис

Етап 8. Production hardening

}
verification_queue.enqueue(
  1. Чи вже виступає як партнерський доступ до Дія.Підпис? expected_hash=document_version.file_hash_sha256,

1. Мета

db=db,

22.6. signature_files

DIIA_SIGNATURE_CLIENT_ID=******** До MVP входить:

)
document_version_id - AC-5 style="background:#ffcc80;" | Помаранчевий
Помилка ERROR - document_name varchar Назва документа. SEO-опис
except Exception as exc:
verify_ssl: bool = True

</syntaxhighlight>

  • створення заявки на підписання документа;
  • підготовку документа до підпису;
  • розрахунок hash документа, якщо це вимагається інтеграцією;
  • створення сесії підписання;
  • генерацію QR-коду або deep link для переходу в застосунок Дія;
  • відображення користувачу статусу підписання;
  • отримання callback / webhook від Дії;
  • отримання результату підписання;
  • збереження підпису;
  • збереження підписаного документа або контейнера;
  • перевірку підпису;
  • перевірку цілісності документа;
  • оновлення версій статусу документа в K2 ERP або іншій системі;
  • журналювання всіх подій;
  • контроль помилок;
  • dashboard для відповідальних осіб. |-
file_size - file_type varchar style="background:#eeeeee;" | Сірий
Готовий до підпису READY_TO_SIGN Документ перевірено і можна створювати заявку. SEO-опис

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

POST /api/v1/diia-signature/callback

- created_by Хто створив версію. Diia Adapter - idempotency_key varchar - payload jsonb } Як менеджер,
request.status = "VERIFY_ERROR"
request.status = "DECLINED_BY_USER"
"full_name": "Іван Петренко",
- Signature Request Service Створення заявки на підписання. # Чи потрібна авторизація через Дія.Підпис? Де застосовується для payload=payload, "file_name": "contract_123.pdf", DIIA_SIGNATURE_TIMEOUT_SECONDS=30 Дія.Підпис у межах цього ТЗ розглядається як зовнішній сервіс, який дає можливість користувачу підтвердити свою дію та накласти електронний підпис через застосунок Дія. Статус from pydantic_settings import BaseSettings
Заявка не створюється. | Отримати доступ до старту розробки. |- certificate_info jsonb - CallbackValidationError Callback не пройшов перевірку. Призначення платформа приймає callback. Реальні endpoint-и і payload потрібно взяти з офіційної документації Дії для партнера. # Який точний формат результату підписання: p7s, ASIC, PDF з підписом або інший? |- redirect_url varchar URL повернення користувача. Поле
  • створює задачу на підпис;
  • показує її у списку задач;
  • контролює строк підписання;
  • нагадує про прострочення;
  • зберігає аудит дій. "signed_at": result.signed_at,
  • створення інтеграції Дія.Підпис;
  • перевірка підключення;
  • створення документа;
  • збереження версії документа;
  • розрахунок hash;
  • створення заявки на підпис;
  • створення сесії підписання;
  • QR/deep link;
  • callback endpoint;
  • збереження результату підписання;
  • базова перевірка підпису;
  • статуси документа;
  • журнал подій;
  • dashboard API;
  • retry для технічних помилок;
  • ідемпотентність callback;
  • unit-тести;
  • mock Diia client. |-
оновлення версій dashboard Середній Контроль. ! Поле Тип
"document_type": "CONTRACT",
"signature_file_id": str(signature_file.id),

14.11. Dashboard

signature_file = signature_storage.save_signature_result(
)

Signature Storage + Verification Service

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

signature_queue.enqueue(

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

Колір
  • отримати партнерську документацію;
  • отримати тестові credentials;
  • погодити callback URL;
  • перевірити тестовий сценарій;
  • визначити формат результату підписання;
  • визначити правила перевірки підпису. request=request,
- AC-8 - raw_request jsonb Відхилити callback і записати подію. | платформа повертає успішний або помилковий статус. |- Signature Request Заявка на підписання. Очікуваний результат
if not callback_security_service.is_valid(request, payload):
return request
redirect_url: str | None = None
audit_logger.log(

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

db=db,
signature_validator.validate_document_for_signing(document, command)
)

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

Як адміністратор,

request.status = "WAITING_SIGNATURE"

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

2. Область сценарії використання

щоб контролювати електронний документообіг. # Чи потрібно зберігати підписані документи в архіві довгострокового зберігання? |-

deep_link text - AC-12 Hash документа не збігається. Колір
db.commit()
  • договорів;
  • актів виконаних робіт;
  • рахунків;
  • заяв;
  • анкет;
  • кадрових документів;
  • первинних документів;
  • документів ЕДО;
  • документів K2 ERP;
  • документів, які формуються в CRM;
  • авторизації користувача через Дія.Підпис;
  • підтвердження дії користувача в системі. Критерій

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

v
def create_signature_session(self, payload: "CreateSignatureSessionPayload") -> "SignatureSessionResponse":
"document_date": "2026-05-07",

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

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

7. User Story

payload={"error": str(exc)},
request = signature_request_repository.create(
користувач системи підтверджує підписання SEO-опис
if callback_repository.exists(callback_id):

18. Callback від Дії

 db=db,
</pre>
{| class="wikitable"
{| class="wikitable"
=== 12.1. Призначення ===

! Критерій
 pass
 v
== 35. Див. так само ==
=== 7.4. Керівник бачить dashboard ===
|-
| 07.05.2026
| Договір 123
| Іван Петренко
| style="background:#ffcc80;" | Прострочено
| користувач системи не завершив підписання
| Створити нову заявку
|-
| 07.05.2026
| Акт 45
| Олена Сидоренко
| style="background:#ef9a9a;" | Помилка перевірки
| Hash документа не збігається
| Ручна перевірка
|-
| 07.05.2026
| Заява 77
| ТОВ «Альфа»
| style="background:#f3e5f5;" | Ручна перевірка
| Неможливо автоматизовано визначити підписанта
| Перевірити сертифікат
|}

def verify_signature(signature_request_id: str, signature_file_id: str, db: "Session") -> None:

<pre>

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

<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
 audit_logger.log(
DIIA_SIGNATURE_REDIRECT_URL=https://example.com/signature/result
=== 29.6. Dashboard ===
|-
| Прийом callback
| Критичний
| Не можна втрачати результат підписання. Подія
 audit_logger.log(
=== 26.1. Основні KPI ===
== 31. Етапи реалізації ==
 "k2_entity_id": "contract-001"
 response = await diia_client.create_signature_session(payload)
 payload={"external_document_id": command.external_document_id},
{| class="wikitable"
 finally:
! # Чи потрібно підписувати документи клієнтами, співробітниками або обома? | style="background:#ef9a9a;" | Критично
|-
| Ручна перевірка
| Потрібне втручання адміністратора. |}

 payload={"error": str(exc)},

{| class="wikitable"
 "expires_at": response.expires_at,
 )
 event_type="SIGNATURE_VERIFY_EXCEPTION",
|-
| AC-17
| Керівник відкриває dashboard. |}

! |-
| qr_payload
| text
| інформаційні дані QR, якщо зберігаються. | Попередня заявка стає INVALIDATED або скасовується. HTML
! SEO-опис
'''Технічний стек:''' Python 3.11+, FastAPI, PostgreSQL, SQLAlchemy, Alembic, httpx, Pydantic, Celery/RQ/APScheduler, Redis, Docker, S3-compatible file storage. | Версіонування і hash документа. Компонент
 "signature_request_id": request.id,
 )
<pre>
=== 14.6. Отримання статусу заявки ===

! SEO-опис
POST /api/v1/diia-signature/documents
 v
=== 26.2. Приклад dashboard ===

 audit_logger.log(

! | DRAFT, archived. Коментар
</pre>
! def check_connection(self) -> "ConnectionStatus":

* створити FastAPI-проєкт;
* налаштувати PostgreSQL;
* створити моделі документів, заявок, сесій, підписів;
* налаштувати Alembic;
* реалізувати healthcheck. | style="background:#ffcc80;" | Потрібна дія
|-
| Помилки
| Помилки підписання або callback. Тип
<pre>
|-
| id
| uuid
| ID файлу підпису. Callback Controller приймає результат. Результат
10. Валідація, hash, створення сесії
! |-
| signature_request_id
| uuid
| Заявка. |-
| Прострочені сесії
| користувач системи не завершив підписання. |-
| SignerMismatchError
| Підписант не відповідає очікуваному. |-
| created_at
| timestamp
| Дата створення. |-
| signer_name
| varchar
| ПІБ підписанта з сертифіката. * офіційний сервіс КЕП Дії. Критерій
 )
Retry заборонений для:
 document_version=document_version,
 "external_document_id": "K2-DOC-2026-000123",
 "status": "ACTIVE",
 data={
! 

! Поле
</pre>

 request.document.status = "VERIFIED"

 callback_url: str
</div>
2. },
</div>
! |-
| mime_type
| MIME type. | style="background:#ef9a9a;" | Червоний
|-
| Не той підписант
| SIGNER_MISMATCH
| Підписант не відповідає очікуваному. | style="background:#c8e6c9;" | Норма
|-
| Перевірено
| Підпис пройшов перевірку. |-
| file_id
| uuid
| Файл у сховищі. |-
| AC-2
| Адміністратор перевіряє підключення. | style="background:#ffcc80;" | Потрібна дія
|-
| Прострочено
| Сесія не завершена вчасно. користувач системи натискає «Підписати через Дія».=== Етап 3. Diia Client ===

=== 29.1. інтеграційні функції ERP ===

POST /api/v1/diia-signature/integrations/{integration_id}/check-connection
 entity_id=request.id,
! Python-сервіс повинен сам зберігати документ, підпис, статус, аудит і результат перевірки. |-
| document_date
| date
| Дата документа. |-
| entity_type
| varchar
| document, request, session, callback, verification. Код
я хочу натиснути кнопку «Підписати через Дія.Підпис», 
[[Категорія:API]]
|-
| id
| uuid
| ID версії. Колір

 return existing
 raise HTTPException(status_code=401, detail="Invalid callback signature")

! |}

 db.commit()

 "idempotency_key": "K2-DOC-2026-000123-sign-v1",

DIIA_SIGNATURE_MAX_DOCUMENT_SIZE_MB=10
 return {"status": "unknown_session"}
 |
 | 1. |-
| created_at
| timestamp
| Дата створення. | MANUAL_REVIEW і аудит. |-
| SessionExpiredError
| Сесія підписання прострочена. # Який строк дії сесії підписання? Очікуваний результат
|-
| Тип сервісу
| Електронний підпис через застосунок Дія. Створюється signature_request. | Помилка підписання, помилка перевірки. |}

! Якщо Дія або мережа повторно надішле той самий callback, платформа не повинна дублювати підпис або повторно змінювати фінальний статус некоректно. ! Поле
=== 7.2. Менеджер контролює підписання ===
GET /api/v1/diia-signature/documents/{document_id}/signature-file

 request = signature_session.signature_request
POST /api/v1/diia-signature/documents/{document_id}/signature-requests
 event_type="DIIA_SIGNATURE_SESSION_CREATED",
 "document_version_id": document.current_version_id,
=== 22.8. signature_events ===

{| class="wikitable"
=== 14.9. Завантаження файлу підпису ===
</pre>
<pre>
 session = signature_session_repository.create(
!</pre>

 pass

<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">

! pass
! |-
| file_hash_sha256
| varchar
| Hash файлу. Тип

[[Категорія:КЕП]]
 base_url: str
== 8. Статуси документа ==

 finally:

 document_version = document_version_repository.get_by_id(db, request.document_version_id)
Можливі результати:
=== 26.3. Проблемні документи ===
Перед створенням заявки платформа повинна перевірити:
9. K2 ERP створює документ. Створюється signature_session. Код

 "document_number": "123",
 request = signature_request_repository.get_by_id(db, signature_request_id)
 def cancel_signature_session(self, session_id: str) -> "CancelSignatureSessionResponse":
<div style="border-left: 6px solid #1565c0; background: #e3f2fd; padding: 12px 16px; margin: 16px 0;">
=== Авторизація через Дія. 5.5.Підпис ===
 document = document_repository.get_by_external_id(
! |-
| style="background:#ef9a9a;" | Червоний
| #ef9a9a
| Помилка або негативний результат.</pre>
 "document_name": "Договір поставки №123",
! |-
| Signature File
| Файл підпису або підписаний контейнер. |-
| diia_session_id
| ID сесії в Дії. |-
| AC-19
| виступає як прострочені заявки.</pre>

* реалізувати Verification Service;
* реалізувати статуси перевірки;
* реалізувати ручну перевірку;
* реалізувати журнал перевірок. Причина
<syntaxhighlight lang="python">
<pre>
! |-
| Status Sync Service
| оновлення версій статусів у K2 ERP. Код

=== 29.5. Callback ===

* приймати тільки HTTPS-запити;
* перевіряти підпис або секрет callback, якщо передбачено API;
* перевіряти session_id;
* перевіряти request_id;
* перевіряти idempotency callback;
* зберігати raw payload;
* оновлювати статус сесії;
* зберігати файл підпису або посилання на результат;
* запускати перевірку підпису;
* повертати коректний HTTP status. | Вони підсвічуються помаранчевим. |-
| SignatureResultError
| Не вдалося отримати результат підпису. |-
| Нагадування про прострочення
| Низький
| Фоновий бізнес-процес. |-
| AC-18
| виступає як помилки підписання. class DiiaSignatureSettings(BaseSettings):

! |-
| mime_type
| varchar
| MIME type. |-
| Verification Service
| Перевірка підпису та цілісності. |-
| created_at
| timestamp
| Дата створення. |-
| style="background:#ffcc80;" | Помаранчевий
| #ffcc80
| Потрібна дія або виступає як ризик. |-
| signature_request_id
| uuid
| Заявка. |-
| Перевірка підпису
| результат, підписант, сертифікат. | Створення сесії, підписання. | Вони підсвічуються фіолетовим. |}

<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">

Ключі дедублікації:
== 28. Логування та аудит ==
! |-
| Signer
| Підписант. API Дії / QR / deep link
! Дія
Перевіряється:
 retry_backoff_seconds: int = 5
== 33. Відкриті питання ==
|-
| AC-7
| користувач системи натискає «Підписати через Дія». |-
| AC-10
| Сесія прострочена. |-
| DocumentChangedError
| Документ змінено після заявки. 6. SEO-опис

[[Категорія:K2 ERP]]

 "email": "client@example.com",

* наявність external_document_id;
* наявність idempotency_key;
* наявність файлу документа;
* файл доступний у сховищі;
* файл не порожній;
* розмір файлу не перевищує ліміт;
* MIME type дозволений;
* документ не був змінений після створення заявки;
* hash документа збережений;
* підписант визначений;
* строк підписання не минув;
* документ ще не підписаний цим підписантом;
* бізнес-процес дає можливість підписання;
* користувач системи має право ініціювати підписання. * Документація K2 ERP щодо документів і бізнес-процесів. | style="background:#bbdefb;" | Блакитний
|-
| Очікує підпису
| WAITING_SIGNATURE
| Користувачу створено QR/deep link. | style="background:#ef9a9a;" | Червоний
|-
| Помилка перевірки
| VERIFY_ERROR
| Підпис отримано, але перевірка не пройдена. |-
| expires_at
| timestamp
| Строк дії. 
{| class="wikitable"

користувач системи підписує декілька документів за один бізнес-процес. Тип
! * офіційний FAQ Дія.Підпис. # Чи потрібне пакетне підписання? |-
| base_url
| varchar
| URL API. | style="background:#f3e5f5;" | Фіолетовий
|}

{| class="wikitable"

 "raw_response": response.raw_payload,
 external_document_id=command.external_document_id,
 },
Для реалізації задачі необхідно отримати:
! Показник

{| class="wikitable"
користувач системи відкриває документ у K2 ERP або на сайті, натискає кнопку «Підписати через Дія.Підпис». |-
| client_secret_encrypted
| text
| Зашифрований секрет. data={
  • створює authorization session;
  • показує QR/deep link;
  • отримує підтвердження;
  • ідентифікує користувача згідно з дозволеним обсягом даних;
  • створює або оновлює сесію користувача. |-
diia_session_id varchar - Callback Controller Прийом callback від Дії. ! SEO-опис
entity_id=request.id,


{| class="wikitable"
== 21. Черга обробки ==

 # Перевірка callback signature / secret залежить від офіційної документації Дії. SEO-опис

[[Категорія:Python]]

}
 )
 entity_type="signature_request",

=== 22.7. signature_verifications ===
=== 7.1. користувач системи підписує документ ===
=== 22.5. signature_sessions ===
! |-
| Невідповідність підписанта
| Документ підписала не та особа. |-
| raw_result
| jsonb
| Повний результат перевірки. | style="background:#fff9c4;" | Жовтий
|-
| Підписується
| SIGNING
| користувач системи відкрив бізнес-процес підписання. Diia Client — це Python-клас або пакет, який інкапсулює роботу з API Дія.Підпис. SEO-опис

def create_signature_request(command: "CreateSignatureRequestCommand", db: "Session") -> "SignatureRequest":

! |-
| document_number
| varchar
| Номер документа. |-
| Невідомий формат підпису
| Неможливо зберегти/перевірити результат. SEO-опис

* цілісність документа;
* відповідність підпису конкретній версії документа;
* валідність підпису;
* валідність сертифіката;
* інформаційні дані підписанта;
* час підписання;
* статус відкликання сертифіката, якщо доступно;
* чи відповідає підписант очікуваному користувачу;
* чи не минув строк сесії;
* чи не змінювався документ після підпису. |-
| document_id
| uuid
| ID документа. ! ! SEO-опис
Приклад hash:
{{SEO
|title=Технічне завдання: Накладення електронного підпису за допомогою Дія.Підпис у Python
|description=Технічне завдання на реалізацію Python-сервісу для інтеграції з Дія.Підпис: підписання документів, авторизація, QR/deep link, статуси, callback, p7s, перевірка підпису, журналювання, dashboard та безпека.
|keywords=Python, Дія.Підпис, Diia.Signature, КЕП, електронний підпис, підписання документів, FastAPI, K2 ERP, callback, p7s, електронний документообіг
}}

! |-
| file_size
| integer
| Розмір файлу. |-
| status
| varchar
| Статус сесії. | TTL, нагадування, повторна заявка. №
 try:
Callback URL Python-сервісу
|-
| style="background:#c8e6c9;" | Зелений
| #c8e6c9
| Успішно: підписано, перевірено, завершено. |-
| AC-6
| Документ змінено після створення заявки. "certificate_info": result.certificate_info,

* масове підписання великого пакета документів;
* складний UI документообігу;
* власний кваліфікований надавач електронних довірчих послуг;
* повна юридична експертиза документів;
* інтеграційні функції ERP з усіма зовнішніми ЕДО-системами;
* автоматичне виправлення документів;
* архів довгострокового зберігання за окремими регламентами. |-
| style="background:#fff9c4;" | Жовтий
| #fff9c4
| Очікування дії користувача або callback. Поле
!== 23. Приклад Python-логіки ==

платформа:

! |-
| created_at
| timestamp
| Дата перевірки. | style="background:#ef9a9a;" | Червоний
|}

 retry_count: int = 3

 verification = signature_verification_repository.create(
! | style="background:#bbdefb;" | Блакитний
|-
| Підписано
| SIGNED
| Підпис успішно отримано і збережено. # Який callback security mechanism надає Дія? Критерій
 "expires_at": command.expires_at,
|-
| AC-1
| Адміністратор створює інтеграцію Дія.Підпис. )

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

{| class="wikitable"
щоб знати, чи клієнт ERP підписав документ. |-
| Callback втрачено
| платформа не дізнається про результат. |}

</syntaxhighlight>

 client_secret: str

DIIA_SIGNATURE_SESSION_TTL_MINUTES=15

 document_file_id=document_version.file_id,

<div style="border-left: 6px solid #2e7d32; background: #e8f5e9; padding: 12px 16px; margin: 16px 0;">
 )
 entity_type="signature_session",
POST /api/v1/diia-signature/documents/{document_id}/verify

 callback_processor.process_signature_result(
== 13. Конфігурація ==

! |-
| Створення сесії Дія
| diia_session_id, статус, expires_at. |}

платформа:

 signature_session.status = "ERROR"
== 24. Обробка помилок ==
 new_status="MANUAL_REVIEW",
! | style="background:#c8e6c9;" | Зелений
|-
| Підпис перевірено
| VERIFIED
| Підпис пройшов перевірку. |-
| QR / Deep Link Service
| Генерація посилання або QR. |-
| Кінцева платформа
| K2 ERP / CRM / електронний документообіг / сайт / мобільний застосунок. |-
| provider
| varchar
| diia_signature. | платформа отримує callback і зберігає підпис. Очікуваний результат
! |-
| Створення заявки
| Підписант, строк дії, ініціатор. |-
| AC-15
| Callback повторився. # Чи потрібно перевіряти РНОКПП / ЄДРПОУ підписанта? |-
| result
| varchar
| VALID, INVALID, HASH_MISMATCH тощо. |-
| status
| varchar
| Статус заявки. |-
| style="background:#eeeeee;" | Сірий
| #eeeeee
| Чернетка або архів. | style="background:#ffcc80;" | Помаранчевий
|-
| Помилка підписання
| SIGN_ERROR
| Помилка під час підписання. |-
| callback_event_id
| ID callback-події, якщо надається. Ризик

DIIA_SIGNATURE_BASE_URL=https://partner-api.example.diia

{| class="wikitable"
<syntaxhighlight lang="python">
 pass

 if payload.get("status") != "signed":

інтеграційні функції ERP здатна використовуватись для:
<pre>
я хочу бачити кількість документів на підписі, підписаних, відхилених і прострочених, 

 signature_session=signature_session,

=== 14.7. Callback від Дії ===
<pre>
DIIA_SIGNATURE_RETRY_COUNT=3

</div>

! |-
| file_id
| uuid
| Файл документа. | Статус стає EXPIRED. |-
| status
| varchar
| Статус документа. | style="background:#c8e6c9;" | Зелений
|-
| Відхилена
| DECLINED
| користувач системи відхилив дію. Для багатьох КЕП-сценаріїв типовим виступає як окремий файл підпису або контейнер. |-
| Signature Storage
| Зберігання підпису, контейнера, документа. Статус
{
 return {"status": "already_processed"}
{| class="wikitable"

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

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

POST /api/v1/diia-signature/integrations

task_name="verify_signature",
request.status = "MANUAL_REVIEW"
ValidationError Документ або підписант невалідний. Приклад `.env`:

DIIA_SIGNATURE_CALLBACK_URL=https://example.com/api/v1/diia-signature/callback

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

)
- Документ змінено після заявки Callback retry, polling статусу, журнал raw events. |}

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

Статус

документа забезпечується через Дія.Підпис здатна використовуватись не тільки; так само реалізовано а й для авторизації або підтвердження дії. | Не створювати сесію. |-

Чернетка DRAFT Документ створений, але ще не готовий до підпису. №
id uuid - Signature Session Сесія взаємодії з Дією. Параметр
Створюється CREATING - TimeoutError - Помилка перевірки Підпис отримано, але не підтверджено. Дата

Застосунок Дія

request = signature_request_repository.get_by_id(db, signature_request_id)

from fastapi import APIRouter, Request, HTTPException

data={

29.4. Перевірка

"idempotency_key": command.idempotency_key,
style="background:#e3f2fd;" | інформаційні матеріали
Очікують підпису style="background:#ef9a9a;" | Червоний
Потребує ручної перевірки MANUAL_REVIEW Retry, якщо безпечно. # Чи потрібна інтеграційні функції ERP з K2 ERP? Python-сервіс перевіряє документ. | style="background:#c8e6c9;" | Зелений
Невалідний INVALID - client_id varchar - signature_request_id uuid class="wikitable"

клієнт ERP отримує посилання на документ. pass K2 ERP / Dashboard / електронний документообіг

pass
- AC-20 style="background:#f3e5f5;" | Фіолетовий

<syntaxhighlight lang="python">

document_version = document_version_repository.get_by_id(db, request.document_version_id)

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

Callback endpoint повинен: Після отримання результату підписання платформа повинна виконати перевірку. |}

"result": result.code, "diia_session_id": response.session_id,
entity_id=session.id,
new_status="CREATING",

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

== 5. Основні сценарії інтеграції ==
if result.code == "VALID":

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

"k2_entity": "contract",
"signature_request_id": str(request.id),
"deep_link": response.deep_link,
- Дублювання callback здатна повторно змінити статус. "signer_identifier": result.signer_identifier,

22.2. sign_documents

29.2. Документ

Немає партнерського доступу - raw_response jsonb style="background:#fff9c4;" | Увага
Підписано - Callback }

<syntaxhighlight lang="python">

- Результат Підпис, підписаний контейнер або інформаційні дані підписання згідно з API Дії. entity_type="signature_request",

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

DIIA_SIGNATURE_CLIENT_SECRET=********

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

Створення документа Зупинити інтеграцію і повідомити адміністратора. SEO-опис

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

3. |}

client_id: str
},
signature_file_id=signature_file.file_id,

<syntaxhighlight lang="python">

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

id uuid ID документа. Критерій
  • невалідного документа;
  • документа, який змінився;
  • простроченої сесії;
  • відхилення користувачем;
  • невірного callback signature;
  • невідповідності підписанта;
  • вже фінального статусу VERIFIED. | style="background:#c8e6c9;" | Норма
Відхилено користувач системи відмовився. Очікуваний результат
def get_signature_result(self, session_id: str) -> "SignatureResultResponse":