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

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

Матеріал з K2 ERP Wiki
Версія від 14:36, 7 травня 2026, створена R (обговорення | внесок) (Створена сторінка: {{DISPLAYTITLE:Технічне завдання: Накладення електронного підпису за допомогою Приват24 / SmartID для Python}} {{SEO |title=Технічне завдання: Накладення електронного підпису за допомогою Приват24 / SmartID для Python |description=Технічне завдання на реалізацію Python-сервісу для накл...)
(різн.) ← Попередня версія | Поточна версія (різн.) | Новіша версія → (різн.)

)

"signature_request_id": request.id,


!; |- | file_hash_sha256 | Hash документа.; {

  • реалізувати get_service_certificate;
  • реалізувати create_session;
  • реалізувати create_signature_request;
  • реалізувати get_session_status;
  • реалізувати get_signature_result;
  • реалізувати обробку помилок.; Тип

!;

 payload={"external_document_id": command.external_document_id},

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

</div>

== 11.; Єдина логіка кольорів ==

* створює запис документа;
* створює версію документа;
* розраховує hash;
* створює заявку на підпис;
* створює сесію SmartID;
* очікує підтвердження користувачем;
* отримує результат підписання;
* зберігає підпис;
* перевіряє підпис;
* змінює статус документа на VERIFIED.; | платформа не дублює результат.;=== 27.3.; Проблемні документи ===
 event_type="SMARTID_SIGNATURE_SESSION_CREATED",
<syntaxhighlight lang="python">
 return {"status": "ok"}
GET /api/v1/smartid-signature/documents/{document_id}/signed-file

 "signer_id": command.signer_id,

 except Exception as exc:
== 10.; Статуси сесії підписання ==
 new_status="MANUAL_REVIEW",
class SmartIDSignatureClient:
 payload={"signature_request_id": str(request.id)},
!; |-
| Перевірка підпису
| Високий
| Потрібна для фінального статусу.; audit_logger.log(

 new_status = smartid_status_mapper.from_api(status_response.status)

* отримати офіційну технічну документацію;
* отримати тестові credentials;
* погодити callback URL або polling-сценарій;
* перевірити тестовий сценарій;
* визначити формат результату підписання;
* визначити правила перевірки підпису.; |-
| AC-23
| є собою прострочені заявки.; |-
| Audit Event
| Подія журналу.; # Чи потрібна інтеграційні функціональні можливості з ЕДО-системами після підписання?; |}

== 3.; Що таке SmartID / електронний підпис Приват24 у межах інтеграції ==

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

!; |-
| Confirmation Service
| Керує сесією підтвердження підпису користувачем.; |-
| SignerMismatchError
| Підписант не відповідає очікуваному.; "status": "CREATING",

async def create_smartid_signature_session(signature_request_id: str, db: "Session") -> None:

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

* створює задачу на підпис;
* показує її у списку задач K2 ERP;
* контролює строк підписання;
* нагадує про прострочення;
* зберігає аудит дій.;<pre>

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

!; {| class="wikitable"

* реалізувати Verification Service;
* реалізувати статуси перевірки;
* реалізувати ручну перевірку;
* реалізувати журнал перевірок.; |
 | 1.; |-
| Signature Request
| Заявка на підписання.; Збереження, перевірка, статус
sha256(file_bytes)
def verify_signature(signature_request_id: str, signature_file_id: str, db: "Session") -> None:
 external_document_id=command.external_document_id,

 verify_ssl: bool = True

 pass
1.; Компонент

=== 27.2.; Приклад dashboard ===
5.; |}

[[Категорія:Електронний документообіг]]

=== 24.2.; Створення сесії SmartID ===

 verification_queue.enqueue(
 pass
== 29.; Логування та аудит ==
=== 30.2.; Документ ===
 session.status = "COMPLETED"
 data={
 smartid_session_id=payload ["session_id"],
!; |-
| Рекомендація
| Використовувати як fallback-сценарій.; Причина
 document_version = document_version_repository.get_by_id(db, request.document_version_id)
|-
| Документів за день
| 184
| style="background:#e3f2fd;" | відомості
|-
| Очікують підпису
| 32
| style="background:#fff9c4;" | Увага
|-
| Підписано через SmartID
| 118
| style="background:#c8e6c9;" | Норма
|-
| Завантажено вручну
| 10
| style="background:#e3f2fd;" | відомості
|-
| Перевірено
| 126
| style="background:#c8e6c9;" | Норма
|-
| Відхилено
| 8
| style="background:#ffcc80;" | Потрібна дія
|-
| Прострочено
| 10
| style="background:#ffcc80;" | Потрібна дія
|-
| Помилки callback/API
| 3
| style="background:#ef9a9a;" | Критично
|-
| Ручна перевірка
| 2
| style="background:#f3e5f5;" | Контроль
|}

 "file_type": "signature",

 "signer_name": result.signer_name,
== 31. MVP ==
<pre>
=== 23.1. smartid_signature_integrations ===
!; |-
| signer_name
| varchar
| ПІБ підписанта з сертифіката.; |}

 session = signature_session_repository.create(

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

!; Створити сесію підписання.; | style="background:#c8e6c9;" | Норма
|-
| Перевірено
| Підпис пройшов перевірку.; |}

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

!; характеристика
 result = await smartid_client.get_signature_result(session.smartid_session_id)
Перевіряється:
!; Поле
GET /api/v1/smartid-signature/documents/{document_id}/signature-file

 try:

!; характеристика
!; Код
 "file_id": "file-001",
</div>
</div>

'''Критично істотно:''' платформа не повинна зберігати пароль користувача до КЕП, приватний ключ або секрети підпису.; |}

2.; Параметр
POST /api/v1/smartid-signature/documents/{document_id}/upload-signature
async def poll_smartid_session(signature_session_id: str, db: "Session") -> None:
</pre>
SMARTID_SERVICE_CERTIFICATE_PATH=/run/secrets/smartid_service_cert.pem
!; Коментар

class SmartIDSignatureSettings(BaseSettings):

!; |-
| Signer
| Підписант.; |-
| created_by
| uuid
| Хто створив заявку.;<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
|-
| id
| uuid
| ID події.; | style="background:#e3f2fd;" | відомості
|-
| Очікують підпису
| Документи з активною сесією.; |}

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

!; | style="background:#c8e6c9;" | Зелений
|-
| Відхилена
| DECLINED
| користувач системи відхилив дію.; |-
| AC-3
| Credentials неправильні.; "external_document_id": "K2-DOC-2026-000123",
"raw_result": result.raw,
Signature Integration - idempotency_key varchar Ключ дедублікації.; Колір - VerificationError Підпис не пройшов перевірку.; Поле
  • масове підписання великого пакета документів;
  • складний UI документообігу;
  • власний кваліфікований надавач електронних довірчих послуг;
  • повна юридична експертиза документів;
  • інтеграційні функціональні можливості з усіма зовнішніми ЕДО-системами;
  • автоматичне виправлення документів;
  • архів довгострокового зберігання за окремими регламентами.; | Помилка підписання, помилка перевірки.; | Зупинити інтеграцію і повідомити адміністратора.; entity_type="signature_request",
request.document.status = "VERIFIED"
;
  • створити FastAPI-проєкт;
  • налаштувати PostgreSQL;
  • створити моделі документів, заявок, сесій, підписів;
  • налаштувати Alembic;
  • реалізувати healthcheck.; |-
Канал користувача style="background:#e3f2fd;" | відомості
request = signature_request_repository.create(

Варіант 1.; 5.1.; Пряма API-інтеграція зі SmartID

; Код

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

- Signature File }
if not callback_security_service.is_valid(request, payload):
- Кінцева платформа - document_date date - Document Version реліз документа, яка передана на підпис.; Дія - signature_request_id uuid Заявка.; Тип

23.3. sign_document_versions

30.6. Callback / polling

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

;== 32.; Етапи реалізації == def create_session(self, payload: "CreateSessionPayload") -> "SignatureSessionResponse": платформа:
; Створюється signature_request.; Стан
AC-21 - Прострочені сесії - Polling статусу Середній Статус MANUAL_REVIEW або VERIFY_ERROR.; | Статус стає EXPIRED.; №
retry_count: int = 3
"email": "client@example.com",
07.05.2026 Договір №123 Іван Петренко Прострочено користувач системи не завершив підписання Створити нову заявку
07.05.2026 Акт №45 Олена Сидоренко Помилка перевірки Hash документа не збігається Ручна перевірка
07.05.2026 Заява №77 ТОВ «Альфа» Ручна перевірка Неможливо автономно визначити підписанта Перевірити сертифікат
signature_session=signature_session,

* HTTPS для всіх endpoint-ів;
* перевірку SSL;
* зберігання секретів тільки в secret storage;
* шифрування файлів підпису;
* шифрування документів або контроль доступу до них;
* обмеження доступу до callback endpoint;
* перевірку callback signature / secret;
* ідемпотентність callback;
* журнал усіх дій;
* маскування персональних даних у логах;
* контроль доступу до документів;
* окремі права на створення заявки;
* окремі права на повторне підписання;
* окремі права на ручне завантаження підпису;
* окремі права на ручну перевірку;
* заборону підписання зміненої версії документа;
* заборону зберігання пароля користувача до SmartID.; Тип помилки
Приват24 / SmartID
!; | style="background:#f3e5f5;" | Контроль
|-
| Ручне завантаження
| Підписи, завантажені користувачем вручну.; Verification Service перевіряє підпис.; характеристика
користувач системи відкриває документ у K2 ERP або на сайті та натискає кнопку «Підписати через Приват24 / SmartID».; користувач системи підтверджує підпис у Приват24 / SmartID.; !; я хочу бачити статус підписання документа, 

=== 24.6.; Перевірка підпису ===

!; | TTL, нагадування, повторна заявка.; Колір
8.; характеристика
!; |-
| raw_request
| jsonb
| Запит до SmartID.; характеристика
|-
| Тип сервісу
| Хмарний кваліфікований електронний підпис.; |-
| AC-2
| Адміністратор перевіряє підключення.; | Статус стає VERIFIED.; Підписант
=== 8.1.; користувач системи підписує документ ===
'''Критично істотно:''' callback і polling повинні бути ідемпотентними.; Очікуваний результат
{| class="wikitable"
!; |-
| document_id
| uuid
| Документ.; |}

 db.commit()

def create_signature_request(command: "CreateSignatureRequestCommand", db: "Session") -> "SignatureRequest":
!; Очікуваний результат
!; №
</div>
=== 13.1.; Призначення ===

def upload_manual_signature(
Retry дозволений для:
 )

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

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

<syntaxhighlight lang="python">
 task_name="verify_signature",
 signature_validator.validate_document_for_signing(document, command)

 document = document_repository.get_by_id(db, document_id)

!; Критерій
=== 8.4.; Керівник бачить dashboard ===
<syntaxhighlight lang="python">
 },
!; |-
| expires_at
| timestamp
| Строк дії.; Критерій
 "document_id": str(document.id),
 if not signature_session:
Співробітник компанії підписує внутрішній документ.; | Статус VERIFY_ERROR.; {| class="wikitable"
Перед створенням заявки платформа повинна перевірити:
{{SEO
|title=Технічне завдання: Накладення електронного підпису за допомогою Приват24 / SmartID для Python
|description=Технічне завдання на реалізацію Python-сервісу для накладення електронного підпису за допомогою КЕП ПриватБанку / SmartID: документи, hash, сесії підписання, callback, p7s, перевірка підпису, журналювання, dashboard та безпека.
|keywords=Python, Приват24, ПриватБанк, SmartID, КЕП, електронний підпис, хмарний підпис, підписання документів, FastAPI, K2 ERP, p7s, електронний документообіг
}}
 signature_request_id=session.signature_request_id,
 if callback_repository.exists(callback_id):
 )
 entity_id=request.id,

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

new_status varchar Статус стає HASH_MISMATCH або VERIFY_ERROR.; Поле
 finally:
!; Поле
<pre>

 "full_name": "Іван Петренко",
!; |-
| AC-5
| Документ перевищує ліміт розміру.;<syntaxhighlight lang="python">
 callback_event = callback_repository.create_raw_event(payload)
 result = signature_verifier.verify(

=== 19.1.; Callback-сценарій ===

 return existing
!; pass

== 33.; Ризики ==
=== 19.2.; Polling-сценарій ===
'''Рекомендовано для K2 ERP:''' реалізувати ключовий режим через API SmartID, а додатково резервний режим ручного завантаження p7s / підписаного контейнера з подальшою перевіркою.; | style="background:#ffcc80;" | Помаранчевий
|-
| Помилка підписання
| SIGN_ERROR
| Помилка під час підписання.; | style="background:#ef9a9a;" | Критично
|-
| Ручна перевірка
| Потрібне втручання адміністратора.; | style="background:#c8e6c9;" | Зелений
|-
| Підпис перевірено
| VERIFIED
| Підпис пройшов перевірку.; №

Приклад `.env`:
 document_version = document_version_repository.get_by_id(db, request.document_version_id)


=== 30.4.; Ручне завантаження ===
 "document_name": "Договір поставки №123",
користувач системи підписує декілька документів в одному бізнес-процесі.; | Очікує підпису, активна сесія.; |-
| Verification Service
| Перевірка підпису та цілісності.; |-
| Збереження підпису
| Критичний
| Юридично значущий результат.; | style="background:#f3e5f5;" | Фіолетовий
|}

 )

 "document_version_id": document.current_version_id,

!; Результат
|-
| ValidationError
| Документ або підписант невалідний.; signature_file_id=signature_file.file_id,
 stored_file = file_storage.save(signature_file)
!; | style="background:#fff9c4;" | Увага
|-
| Підписано
| Підпис отримано.; new_status="CREATING",

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

<syntaxhighlight lang="python">
== 25.; Обробка помилок ==

 "file_mime_type": "application/pdf",

== 5.; Варіанти реалізації ==
 },
 },

!; |-
| signed_at
| timestamp
| Час підписання.; * Законодавчі вимоги до КЕП і електронного документообігу.; |-
| SignatureResultError
| Не вдалося отримати результат підпису.; | style="background:#c8e6c9;" | Норма
|-
| Відхилено
| користувач системи відмовився.; |}

 audit_logger.log(

 idempotency_key=command.idempotency_key,
=== 5.2.; Варіант 2.; Ручне підписання у Приват24 + завантаження підпису в систему ===
router = APIRouter()
{| class="wikitable"
|-
| id
| uuid
| ID заявки.; Параметр

{| class="wikitable"

from fastapi import APIRouter, Request, HTTPException
 def check_connection(self) -> "ConnectionStatus":
; Запустити перевірку підпису.; Дата
AC-1 Адміністратор створює інтеграцію SmartID.;
event_type="SIGNATURE_REQUEST_CREATED",
платформа показує AuthError і не створює сесії.; | style="background:#ef9a9a;" | Червоний
Помилка перевірки VERIFY_ERROR Підпис отримано, але перевірка не пройдена.; характеристика
  • реалізувати завантаження документа;
  • реалізувати версіонування;
  • реалізувати hash;
  • реалізувати валідацію;
  • реалізувати дедублікацію.; | Статус стає DECLINED_BY_USER.; |-
Отримання підпису file_id, hash підпису, час.; Python-сервіс перевіряє документ.; Дія системи
; 10.; Callback або polling Python-сервісу

Приклад hash:

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

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

Етап 3.; SmartID Client

1.; Ризик

Відхилити callback і записати подію.; Пріоритет

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

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

v
Чернетка DRAFT Документ створений, але ще не готовий до підпису.; document = document_repository.get_by_external_id(

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

30.5.; Перевірка

  • цілісність документа;
  • відповідність підпису конкретній версії документа;
  • валідність підпису;
  • валідність сертифіката;
  • інформаційні дані підписанта;
  • час підписання;
  • статус відкликання сертифіката, якщо доступно;
  • чи відповідає підписант очікуваному користувачу;
  • чи не минув строк сесії;
  • чи не змінювався документ після підпису.; |-
Обмеження - result varchar style="background:#bbdefb;" | Блакитний
Очікує підпису WAITING_SIGNATURE Створено заявку на підпис.;== 15.; API Python-сервісу ==
  • реалізувати callback endpoint;
  • реалізувати polling worker;
  • реалізувати перевірку callback;
  • реалізувати збереження результату;
  • реалізувати ідемпотентність;
  • реалізувати raw event storage.;
"signature_request_id": None, "status": "ACTIVE", entity_id=request.id, "expires_at": command.expires_at, Як керівник, ) !;=== 23.7. signature_verifications === '''Заборонено:''' зберігати partner_secret, приватні ключі, токени, callback secrets, паролі КЕП або інші секрети у коді, Git-репозиторії, frontend-змінних або відкритих логах.; Колір === 15.6.; Callback від SmartID === ) |- | Прийом callback | Критичний | Не можна втрачати результат підписання.; Як зменшити {| class="wikitable" elif new_status in ["DECLINED", "EXPIRED", "ERROR"]: data={ def get_service_certificate(self) -> "ServiceCertificateResponse": request = signature_request_repository.get_by_id(db, signature_request_id) === 15.9.; Ручне завантаження підпису ===
event_type="SIGNATURE_VERIFY_EXCEPTION",
if session.status in ["COMPLETED", "DECLINED", "EXPIRED", "ERROR"]:
document_version=document_version, "document_id": document.id,
;
=== 22.2.; Пріоритети задач ===
=== 6.3.; Підписання документа клієнтом ===

!; |-
| AC-6
| Документ змінено після створення заявки.; API SmartID / ПриватБанк
GET /api/v1/smartid-signature/signature-requests/{request_id}/status
Python-сервіс напряму інтегрується з API SmartID.; |-
| partner_secret_encrypted
| text
| Зашифрований секрет.; |}

 return {"status": "already_processed"}

3.; | платформа створює заявку на підпис.; {| class="wikitable"
 entity_type="document",
 task_name="verify_manual_signature",
 session_ttl_minutes: int = 15

SMARTID_MAX_DOCUMENT_SIZE_MB=10
 },
 base_url: str

SMARTID_CALLBACK_URL=https://example.com/api/v1/smartid/callback

 db=db,

!; |-
| certificate_info
| jsonb
| інформаційні дані сертифіката.; характеристика
SMARTID_TIMEOUT_SECONDS=30
!; Колір

платформа:

Варіант 3.; 5.3.; Комбінована схема

K2 ERP / CRM / Website

"tax_id": "1234567890"

POST /api/v1/smartid-signature/integrations 2.; | style="background:#ef9a9a;" | Червоний

Потребує ручної перевірки MANUAL_REVIEW - file_name varchar - Polling статусу style="background:#fff9c4;" | Жовтий
Завершена COMPLETED Сесія завершена успішно.;=== Етап 7.; Перевірка підпису === - signer_identifier varchar - file_size integer Розмір файлу.; K2 ERP створює документ.;=== 24.5.; Ручне завантаження підпису ===
"signer_identifier": result.signer_identifier,
entity_type="signature_request",
Створюється CREATING - source varchar }
def cancel_session(self, session_id: str) -> "CancelSessionResponse":
"external_signer_id": "CLIENT-001",
"document_type": "CONTRACT",
},
id uuid - актуалізація dashboard Середній - created_at timestamp - Callback Controller - file_hash_sha256 varchar Hash файлу.; №
)
  • відкриває сторінку підписання;
  • показує коротку інформацію про документ;
  • запускає сценарій підпису через Приват24 / SmartID;
  • замовник підтверджує підписання;
  • платформа отримує результат;
  • документ стає підписаним клієнтом.; |-
переважні аспекти Не потребує повної інтеграції з API SmartID.; Очікуваний результат - id uuid - Підтвердження користувачем - document_type varchar Версіонування і hash документа.; |}
payload={
- is_active boolean Активність.; №
data={
"signature_request_id": str(session.signature_request_id),
}

</syntaxhighlight>

- created_at timestamp Дата створення.; характеристика

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

max_document_size_mb: int = 10
Документів створено Загальна кількість документів.; Очікуваний результат

30.1.; інтеграційні функціональні можливості

db=db,
Перевести в SIGN_ERROR.; |- document_name varchar - source varchar style="background:#fff9c4;" | Жовтий
Підписується SIGNING }
"signed_at": result.signed_at,
},

це Python-клас або пакет, який інкапсулює роботу з API ПриватБанку / SmartID виступає ключовою рисою SmartID Client.; * реалізувати dashboard API;

  • реалізувати список проблемних документів;
  • реалізувати фільтри;
  • реалізувати експорт, якщо потрібно.; # Чи є собою офіційно затверджений API-доступ до SmartID для цього проєкту?; |-
document_version_id style="background:#ef9a9a;" | Червоний
Прострочений сертифікат CERT_EXPIRED - old_status varchar - created_by Хто створив версію.; Статус
entity_type="signature_request",
Метою задачі є собою створення Python-сервісу для накладення електронного підпису за допомогою КЕП ПриватБанку / SmartID / Приват24.; Очікуваний результат callback_processor.process_signature_result(
status_response = await smartid_client.get_session_status(session.smartid_session_id)
 document_file_id=document_version.file_id,

<syntaxhighlight lang="python">

 try:
 signature_record = signature_file_repository.create(
!; |-
| Document Service
| Робота з документами та версіями.; * Технічна документація SmartID API, яка надається після підключення.; |-
| Підходить для
| MVP без прямого API або резервного сценарію.; |-
| file_type
| varchar
| signature, signed_container, signed_pdf.; |-
| style="background:#fff9c4;" | Жовтий
| #fff9c4
| Очікування дії користувача або результату.; |-
| Callback
| callback_id, raw payload, статус перевірки.; |-
| Документ змінено після заявки
| Можна підписати неактуальну версію.; Де застосовується
[[Категорія:K2 ERP]]
</div>

 partner_secret: str | None = None
!; №

== 13. SmartID Client ==
!; | style="background:#bbdefb;" | Блакитний
|-
| Підписано
| SIGNED
| Підпис успішно отримано і збережено.; |-
| Створення сесії SmartID
| smartid_session_id, статус, expires_at.; |-
| Створення заявки
| Підписант, строк дії, ініціатор.; |-
| Audit Logger
| Журнал подій, callback-ів, помилок.; платформа повинна:
!; |-
| style="background:#eeeeee;" | Сірий
| #eeeeee
| Чернетка або архів.; |-
| base_url
| varchar
| URL API.; |-
| AC-20
| Callback недоступний, але polling увімкнений.; * Офіційна сторінка SmartID для бізнесу.; |-
| Перевірка підпису
| результат, підписант, сертифікат.; {| class="wikitable"

* Офіційна сторінка SmartID ПриватБанку.; |-
| AC-10
| Сесія прострочена.; | style="background:#ef9a9a;" | Червоний
|}

 "document_date": "2026-05-07",

== 4.; Передумови ==
GET /api/v1/smartid-signature/dashboard?date_from=2026-05-01&date_to=2026-05-31
=== 30.7. Dashboard ===
 return request
я хочу бачити callback-и, помилки API та технічний журнал, 
|-
| style="background:#c8e6c9;" | Зелений
| #c8e6c9
| Успішно: підписано, перевірено, завершено.; |-
| document_id
| uuid
| ID документа.; session.status = new_status

* додати rate limiting;
* додати alerting;
* додати dead letter queue;
* додати backup файлів;
* додати моніторинг callback / polling;
* додати безпечне зберігання секретів.; |-
| Результат
| Файл підпису, підписаний об'єкт або інший результат згідно з API SmartID.; Ключ

 )

 event_type="MANUAL_SIGNATURE_UPLOADED",
{| class="wikitable"
=== 30.3.; Підписання ===

платформа повинна не допускати дублювання заявок і підписів.; |-
| file_hash_sha256
| varchar
| Hash файлу.; 6.;<pre>

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


<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
 request = signature_request_repository.get_by_id(db, signature_request_id)
{| class="wikitable"

 # Перевірка callback signature / secret залежить від офіційної документації SmartID.; db: "Session",
</syntaxhighlight>
=== 6.5.; Ручне завантаження підпису ===

=== 6.4.; Підписання документа співробітником ===
 return {"status": "unknown_session"}
 payload={
 timeout_seconds: int = 30
POST /api/v1/smartid-signature/documents/{document_id}/verify
</syntaxhighlight>
 "callback_context": {
!; |}

 payload=result.raw_payload,

Signature Storage + Verification Service
 existing = signature_request_repository.get_by_idempotency_key(
=== 15.10.; Перевірка підпису ===
4.; |-
| status
| varchar
| Статус заявки.; характеристика
=== 8.2.; Менеджер контролює підписання ===
Валідний VALID style="background:#ffcc80;" | Потрібна дія
Прострочено - file_hash_sha256 - Ручне завантаження Хто завантажив, файл, hash.; Тип

SMARTID_SESSION_TTL_MINUTES=15 щоб оперативно знаходити причини невдалого підписання.; |-

current_version_id uuid }

платформа:

- callback_url varchar Callback URL.; Тип
"signature_request_id": request.id,
)
audit_logger.log(
external_document_id ID документа в K2 ERP.; "document_number": "123",

SMARTID_RETRY_COUNT=3

7.; Основні сутності

9.; | платформа створює сесію підписання.; | Ідемпотентність callback.; # Який точний формат результату підписання: p7s, ASIC, PDF з підписом або інший?; |-

mime_type varchar платформа отримує статус через polling worker.; Критично істотно: якщо офіційно затверджений API SmartID недоступний для конкретного бізнес-сценарію, потрібно передбачити альтернативний режим: користувач системи підписує документ вручну у Приват24 / SmartID, а платформа приймає підписаний файл або p7s на завантаження та виконує перевірку підпису.; | Статус стає VERIFIED.; характеристика

Якщо API не надсилає callback, Python-сервіс повинен періодично перевіряти статус сесії.; | платформа зберігає файл і запускає перевірку.; характеристика </syntaxhighlight>

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

)

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

- AC-12 Підпис відповідає документу.; характеристика

Етап 5.; Callback / polling та підпис

- provider varchar privatbank_smartid.; Показник

щоб підписати документ без завантаження приватного ключа в систему.; №


 db.commit()
 db.commit()
!; |-
| Нагадування про прострочення
| Низький
| Фоновий бізнес-процес.; Що зберігати

 "expires_at": "2026-05-07T14:30:00+03:00"
<syntaxhighlight lang="python">
=== Етап 4.; Документи ===
=== 24.4. Callback controller ===
 "signature_file_id": str(signature_record.id),

<pre>
 "file_id": stored_file.id,
замовник отримує посилання на документ.; | платформа приймає callback.; характеристика

 return
Як менеджер, 
=== Етап 8.; Dashboard та аудит ===

'''істотно:''' назви методів у Python-клієнті є собою внутрішньою абстракцією.; | платформа повертає успішний або помилковий статус.; | Статус стає MANUAL_REVIEW або VERIFY_ERROR.; | Створення сесії, підписання.; | Не створювати сесію.; | Заявка не створюється.; |-
| AC-9
| користувач системи відхиляє підписання.; payload={"uploaded_by": str(current_user.id)},
 },
{| class="wikitable"
 audit_logger.log(

!; |-
| raw_response
| jsonb
| Відповідь SmartID.; |-
| file_id
| uuid
| Файл документа.; new_status="SIGN_ERROR",

!; щоб контролювати електронний документообіг.; |-
| raw_result
| jsonb
| Повний результат перевірки.; | Передбачити fallback: ручне завантаження підпису.; Як користувач системи, 

== 1.; Мета ==
 payload = await request.json()
 entity_id=document.id,
 audit_logger.log(

!; |-
| Callback Event
| Подія, отримана від сервісу підпису.; |-
| Рекомендація
| ключовий production-сценарій, якщо API доступний.; Критерій
; Поле
"source": "MANUAL_UPLOAD",
"certificate_info": result.certificate_info,
}

27.; Dashboard керівника

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

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

23.6. signature_files

pass
; Поле
payload={"error": str(exc)},
request.status = "VERIFIED"
db.commit()

2.; Область сфера застосування

</syntaxhighlight>

SmartID у межах цього ТЗ розглядається як хмарний КЕП ПриватБанку, який користувач системи створює та використовує через Приват24.; |}

платформа підтримує роботу обидва режими:

private_key_path: str | None = None

23.2. sign_documents

request.status = "VERIFY_ERROR"
; Тип

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

)

</syntaxhighlight>

"k2_entity": "contract",

6.; | Статус стає VERIFY_ERROR.; |}

request.status = "WAITING_SIGNATURE"
Статус EXPIRED, дозволити створити нову.; |- Блакитний #bbdefb - document_version_id uuid реліз документа.; # Який максимальний розмір документа?; Поле
id uuid ID перевірки.; Можливі результати:
  • невалідного документа;
  • документа, який змінився;
  • простроченої сесії;
  • відхилення користувачем;
  • невірного callback signature;
  • невідповідності підписанта;
  • вже фінального статусу VERIFIED.; |-
Невідповідність підписанта - file_id uuid - created_at timestamp - smartid_session_id - entity_type varchar - status varchar Статус документа.; Тип
def create_signature_request(self, session_id: str, payload: "SignaturePayload") -> "SignatureRequestResponse":

POST /api/v1/smartid-signature/documents/{document_id}/signature-requests

db=db,
signature_verification_repository.create(
Retry, якщо безпечно.; KPI

async def smartid_signature_callback(request: Request):

30. Acceptance Criteria

db=db,
v

26.; Retry-логіка

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

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

До MVP входить:

; Задача
session = signature_session_repository.get_by_id(db, signature_session_id)

</syntaxhighlight>

}

[[Категорія:Технічні завдання]]
== 16.; Приклад запиту на створення заявки на підпис ==
=== 24.3.; Polling статусу сесії ===
== 35.; Джерела ==
 "expires_at": response.expires_at,
 if new_status == "COMPLETED":
=== 23.4. signature_requests ===

!; | Callback retry, polling статусу, журнал raw events.; Значення
 signature_file = signature_storage.save_signature_result(
=== 15.3.; Створення документа ===

=== 13.2.; Основні методи ===
!; | Скасувати заявку або створити нову.; | style="background:#c8e6c9;" | Зелений
|-
| Відхилено користувачем
| DECLINED_BY_USER
| користувач системи не підтвердив підписання.; Поле
{| class="wikitable"
{| class="wikitable"
 )

!; {| class="wikitable"

 db=db,

* договорів;
* актів виконаних робіт;
* рахунків;
* заяв;
* анкет;
* кадрових документів;
* первинних документів;
* податкових і бухгалтерських документів;
* документів ЕДО;
* документів K2 ERP;
* документів CRM;
* документів особистого кабінету клієнта;
* підтвердження юридично значущих дій користувача.; |-
| DocumentChangedError
| Документ змінено після заявки.; |-
| Ручна перевірка
| хто перевірив, рішення для бізнесу, коментар.; |-
| name
| varchar
| Назва інтеграції.; |-
| Помилка перевірки
| Підпис отримано, але не підтверджено.; | Вони підсвічуються помаранчевим.; Сутність
|-
| AC-7
| користувач системи натискає «Підписати через Приват24 / SmartID».; |-
| AC-22
| є собою помилки підписання.; |-
| CallbackValidationError
| Callback не пройшов перевірку.; |-
| Створення сесії
| Високий
| ключовий сценарій користувача.; | Перевести в SIGN_ERROR або NEEDS_RETRY.; def get_signature_result(self, session_id: str) -> "SignatureResultResponse":

<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
!; |-
| style="background:#ffcc80;" | Помаранчевий
| #ffcc80
| Потрібна дія або є собою ризик.; характеристика

@router.post("/api/v1/smartid-signature/callback")

підписання документів забезпечується через ПриватБанк описує SmartID як КЕП, що має змогу використовуватись; додатково реалізовано звітів, підтвердження особистості й отримання послуг онлайн.; |-
| version_number
| integer
| Номер версії.; |-
| partner_id
| varchar
| ID партнера.; | style="background:#c8e6c9;" | Зелений
|-
| Невалідний
| INVALID
| Підпис не пройшов перевірку.; характеристика

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

SMARTID_PARTNER_ID=********
!; |}

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

!; |-
| updated_at
| timestamp
| Дата актуалізація.; | Вони підсвічуються червоним.; Подія

 )
 request.status = "MANUAL_REVIEW"
 pass
<syntaxhighlight lang="json">
 raise BusinessError("Document cannot accept signature in current status")
retry_backoff_seconds: int = 5
До MVP не входить:
; користувач системи підтверджує підписання
request.status = "SIGN_ERROR"
 |
 | 5.; | Попередня заявка стає INVALIDATED або скасовується.; |}

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

 )

* автоматичне створення сесії підписання через SmartID API;
* ручне завантаження підписаного документа, якщо API недоступне або користувач системи підписав документ поза системою.; характеристика

* доступ до сервісу SmartID / хмарного КЕП ПриватБанку;
* офіційну технічну документацію API;
* тестове середовище, якщо доступне;
* ідентифікатор партнера / клієнта API;
* технічні ключі або сертифікати сервісу;
* правила авторизації;
* правила шифрування запитів;
* правила отримання сесії підписання;
* правила формування запиту на підпис;
* правила отримання результату;
* правила перевірки підпису;
* допустимі формати документів;
* максимальний розмір документа;
* callback URL або polling-сценарій;
* контакт технічної підтримки ПриватБанку.; | Перевірка даних сертифіката.; Призначення

* створення інтеграції SmartID / Приват24;
* перевірка підключення;
* створення документа;
* збереження версії документа;
* розрахунок hash;
* створення заявки на підпис;
* створення сесії підписання, якщо доступний API;
* polling або callback для отримання результату;
* збереження результату підписання;
* ручне завантаження p7s / підписаного контейнера як fallback;
* базова перевірка підпису;
* статуси документа;
* журнал подій;
* dashboard API;
* retry для технічних помилок;
* ідемпотентність callback / polling;
* unit-тести;
* mock SmartID client.;</div>
|-
| AC-14
| Підпис валідний.; | style="background:#f3e5f5;" | Фіолетовий
|}

 )

користувач системи сам підписує документ через Приват24 або SmartID, а потім завантажує підписаний документ / файл підпису в K2 ERP.; |-
| style="background:#ef9a9a;" | Червоний
| #ef9a9a
| Помилка або негативний результат.; service_certificate_path: str | None = None

 "file_hash_sha256": stored_file.sha256,
<pre>

 return signature_record

!; |}

!; |-
| Signature Session
| Сесія взаємодії зі SmartID.; | style="background:#eeeeee;" | Сірий
|-
| Готовий до підпису
| READY_TO_SIGN
| Документ перевірено і можна створювати заявку.; | Показати користувачу помилку.; !; |-
| AuthError
| Невірні credentials SmartID.;
v
verification_queue.enqueue( ) db.commit() current_user: "User",

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

entity_type="signature_session",
if existing:
- expires_at timestamp - status varchar Статус сесії.; Очікуваний результат

POST /api/v1/smartid-signature/callback

Підходить для - service_certificate_path varchar Шлях до сертифіката сервісу.; Значення

</syntaxhighlight>

v

from pydantic_settings import BaseSettings

K2 ERP / Dashboard / електронний документообіг

v
;
payload = smartid_mapper.to_signature_session_payload(

Етап 6.; Ручне завантаження підпису

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

signature_file: "UploadedFile",
task_name="create_smartid_signature_session",
- AC-15 }
signature_file = signature_file_repository.get_by_id(db, signature_file_id)
new_status="ACTIVE", "result": result.code, callback_url: str | None = None if result.code == "VALID":
id uuid - AC-18 Callback повторився.;== 14.; Конфігурація ==

23.; Модель даних

SMARTID_BASE_URL=https://acsk.privatbank.ua/cloud/api/back

  • створити пакет документів;
  • перевірити всі документи;
  • створити окрему заявку на кожен документ або одну пакетну заявку, якщо це підтримується API;
  • отримати результат по кожному документу;
  • показати частково підписані або помилкові документи;
  • не втратити статус окремого документа.; |-
AC-13 Підпис не відповідає документу.; event_type="SMARTID_SIGNATURE_SESSION_ERROR",
API Layer style="background:#fff9c4;" | Жовтий
Очікує результат WAITING_RESULT платформа отримує результат і зберігає підпис.; |- entity_id uuid Він бачить документи, підписи, помилки, прострочення.; |- Signature Storage style="background:#bbdefb;" | Блакитний
Активна ACTIVE style="background:#ef9a9a;" | Червоний
Не той підписант SIGNER_MISMATCH DRAFT, archived.; характеристика

платформа повинна логувати:

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

callback_event.status = "UNKNOWN_SESSION"

3.; |}

SMARTID_PRIVATE_KEY_PATH=/run/secrets/smartid_private_key.pem

22.; Черга обробки

db=db,

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

id uuid - created_at timestamp - document_number varchar class="wikitable"
entity_id=session.id,

5.; Реальні endpoint-и, шифрування, payload і response потрібно взяти з офіційної документації ПриватБанку / SmartID.; |-

AC-19 - signer_id uuid - signature_request_id uuid } - callback_event_id - AC-24 є собою документи на ручній перевірці.; Документ на підпис
payload={"error": str(exc)},
- EncryptionError - payload jsonb Технічні інформаційні дані.; Критерій

Управлінський результат: відповідальна особа повинна бачити, які документи очікують підпису через Приват24 / SmartID, які підписані, які відхилені, які прострочені, які мають помилки підписання, які потребують повтору або ручної перевірки.; |-

created_at Дата створення версії.; HTML
session.signature_request.status = "SIGNED"
entity_id=request.id,
"k2_entity_id": "contract-001"
AC-17 - Signature Request Service інтеграційні функціональні можливості зберігається в системі.; |}

 signature_session = signature_session_repository.get_by_smartid_session_id(
<pre>
'''істотно:''' точні API endpoint-и, криптографічні формати, правила шифрування запитів, параметри сесії та callback потрібно брати з офіційної технічної документації ПриватБанку / SmartID, яку надають після підключення до сервісу.; Після отримання фінального статусу зберегти результат.; Поле
 session.signature_request.status = smartid_status_mapper.to_request_status(new_status)
!; |-
| Обмеження
| Менше автоматизації, більше ручних дій.; | style="background:#ffcc80;" | Помаранчевий
|-
| Помилка
| ERROR
| Технічна помилка.; Signature Storage зберігає підпис.; |-
| Невідомий формат підпису
| Неможливо зберегти/перевірити результат.; | style="background:#ffcc80;" | Помаранчевий
|-
| Прострочена
| EXPIRED
| Сесія не завершена у строк.; |-
| created_at
| timestamp
| Дата перевірки.; |-
| SmartID Client
| Python-клієнт для API SmartID.; Документ
 document_id: str,
 response = await smartid_client.create_session(payload)
=== 23.8. signature_events ===
|-
| AC-11
| користувач системи завантажує p7s або підписаний контейнер.; Критерій

{{DISPLAYTITLE:Технічне завдання: Накладення електронного підпису за допомогою Приват24 / SmartID для Python}}
платформа повинна забезпечити:
 "signature_file_id": str(signature_file.id),
4.; | Вони підсвічуються фіолетовим.; | платформа повертає помилку і записує подію.; |-
| Status Sync Service
| актуалізація статусів у K2 ERP.; |-
| created_at
| timestamp
| Дата створення.; |-
| переважні аспекти
| Контроль статусів, сесій, результатів і callback.; Тип
 "smartid_session_id": response.session_id,
я хочу натиснути кнопку «Підписати через Приват24 / SmartID», 
 pass
 except Exception as exc:

) -> "SignatureFile":
; * Документація K2 ERP щодо документів і бізнес-процесів.; характеристика

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

; Критерій

7.; |-

external_document_id varchar Уточнити формат за документацією SmartID.; |- created_at timestamp - FileTooLargeError - mime_type - Дублювання callback - Polling Worker Періодична перевірка статусу, якщо callback не застосовується.; # Чи потрібен fallback зі ручним завантаженням p7s?; Результат підписання

15.11. Dashboard

"raw_response": response.raw_payload,
- smartid_session_id varchar - created_at timestamp Дата створення.; SMARTID_PARTNER_SECRET=********
)
"idempotency_key": command.idempotency_key,
; Тип

Callback endpoint повинен:

  • створення заявки на підписання документа;
  • підготовку документа до підпису;
  • розрахунок hash документа;
  • створення сесії підписання;
  • передачу документа або hash у сервіс підписання;
  • ініціацію підтвердження підпису користувачем у Приват24 / SmartID;
  • отримання результату підписання;
  • збереження файлу підпису;
  • збереження підписаного контейнера, якщо він повертається сервісом;
  • перевірку підпису;
  • перевірку цілісності документа;
  • актуалізація статусу документа в K2 ERP або іншій системі;
  • журналювання всіх подій;
  • контроль помилок;
  • dashboard для відповідальних осіб.; callback_id = callback_service.get_callback_id(payload)
  • реалізувати upload endpoint;
  • реалізувати перевірку типу файлу;
  • реалізувати збереження p7s / контейнера;
  • реалізувати зв'язок із документом;
  • реалізувати перевірку підпису.; | MANUAL_REVIEW.; :contentReference [oaicite:1]{index=1}
if document.status not in ["READY_TO_SIGN", "WAITING_SIGNATURE", "SIGN_ERROR"]:

12.1.; Загальна схема

document_version_id style="background:#ffcc80;" | Потрібна дія
Помилки }
"file_name": "contract_123.pdf",
;=== 23.5. signature_sessions ===

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

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

  • приймає файл підпису або підписаний контейнер;
  • перевіряє hash вихідного документа;
  • перевіряє підпис;
  • визначає підписанта;
  • змінює статус документа;
  • зберігає результат перевірки.; | MANUAL_REVIEW і аудит.; Критично істотно: якщо документ змінено після створення заявки на підпис, попередня заявка повинна бути скасована або переведена в статус INVALIDATED.; характеристика

Python Privat24 / SmartID Signature Service

POST /api/v1/smartid-signature/documents

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

; Критерій - Verification Result - file_size - ключовий сценарій style="background:#ef9a9a;" | Червоний
Не той документ HASH_MISMATCH class="wikitable"
id uuid - signer_id Підписант.;== 28.; Безпека ==
raise HTTPException(status_code=401, detail="Invalid callback signature")

8. User Story

data={
Немає API-доступу SmartID Без доступу неможливо реалізувати повну автоматичну інтеграцію.; Колір
payload={"smartid_session_id": response.session_id},

платформа:

)
"signer": {
; Валідація, hash, створення заявки

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

"phone": "+380671112233",
- SessionExpiredError - Dashboard API style="background:#fff9c4;" | Жовтий
Очікує підтвердження WAITING_USER_CONFIRMATION користувач системи має підтвердити підпис у Приват24 / SmartID.; Параметр

19.; Callback або polling

Етап 1.; Аналіз інтеграції SmartID

signature_queue.enqueue(
"raw_request": payload,
  • приймати тільки HTTPS-запити;
  • перевіряти підпис або секрет callback, якщо передбачено API;
  • перевіряти session_id;
  • перевіряти request_id;
  • перевіряти idempotency callback;
  • зберігати raw payload;
  • оновлювати статус сесії;
  • зберігати файл підпису або посилання на результат;
  • запускати перевірку підпису;
  • повертати коректний HTTP status.; !; |-
event_type varchar style="background:#ffcc80;" | Помаранчевий
Прострочено EXPIRED - AC-16 - TimeoutError - AC-8 - idempotency_key - signature_request_id uuid Заявка.; Очікуваний результат
  • наявність external_document_id;
  • наявність idempotency_key;
  • наявність файлу документа;
  • файл доступний у сховищі;
  • файл не порожній;
  • розмір файлу не перевищує ліміт;
  • MIME type дозволений;
  • документ не був змінений після створення заявки;
  • hash документа збережений;
  • підписант визначений;
  • строк підписання не минув;
  • документ ще не підписаний цим підписантом;
  • бізнес-процес надає можливість підписання;
  • користувач системи має право ініціювати підписання;
  • телефон або ідентифікатор підписанта відповідає даним користувача, якщо це потрібно для SmartID-сценарію.; |-
Фіолетовий #f3e5f5 style="background:#ef9a9a;" | Червоний
Ручна перевірка MANUAL_REVIEW - Callback втрачено Відхилено, прострочено.; |- Document Dashboard, список документів, картка документа.;=== 22.1.; Логіка черги ===
expected_hash=document_version.file_hash_sha256,

Див.; 36.; додатково

payload=payload,
Створення документа Тип, номер, реліз, hash.; характеристика - Помилка код, повідомлення, stack trace без секретів.; користувач системи підтверджує підписання у Приват24 / SmartID, а Python-сервіс зберігає тільки результат підписання, технічний статус, audit log і файл підпису.; Створюється signature_session.; Статус
else:

27.1.; Основні KPI

Етап 9.; Production hardening

AC-4 Документ валідний.; Код

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

partner_id: str