| external_order_id
|
-
|
Зміна API
|
-
|
DuplicateShipmentError
|
-
|
Друк ярлика
|
-
|
weight
|
numeric
|
Вага.;=== Етап 8.; Production hardening ===
user_token: str
self.user_token = user_token
Критично істотно: інтеграційні функціональні можливості не повинна створювати дублікати відправлень.; | Черга, API-статуси, транспортування.; Як зменшити
|
-
|
provider
|
varchar
|
ukrposhta.; Код
|
|
Статус змінюється на LABEL_PRINTED.; Подія
verify_ssl: bool = True
24.1.; Основні KPI
| AC-7
|
K2 ERP передає валідне замовлення.; Колір
9.; Типи відправлень
|
-
|
Невідомі статуси
|
-
|
Directory Sync Worker
|
style="background:#f3e5f5;" | Фіолетовий
|
| Скасовано
|
CANCELLED
|
style="background:#c8e6c9;" | Зелений
|
| Зареєстровано
|
REGISTERED
|
-
|
AC-17
|
API повертає невідомий статус.; entity_type="ukrposhta_shipment",
"address": {
method=method,
щоб контролювати якість логістики, повернення, затримки та помилки.; характеристика
|
| Неправильний token
|
інтеграційні функціональні можливості не працюватиме.; Розділ API
щоб наклеїти його на посилку.; !; |-
|
Адресний класифікатор
|
UNKNOWN_STATUS, ручна перевірка.; Worker створює адресу відправника, якщо її ще немає.; |-
|
Міжнародні відправлення складніші
|
Потрібні митні й країнові поля.; Компонент
"region": "Київська",
|
; K2 ERP створює замовлення.; Одержувач
}
"raw_request": command.model_dump(),
Ключі дедублікації:
|
| id
|
uuid
|
Dashboard, список відправлень, картка замовлення.; | платформа повертає успішний або помилковий статус.; Очікуваний результат
"declared_price": 1500.00,
створення відправлень забезпечується через Головна ідея: розробити Python-сервіс, який інтегрує K2 ERP / CRM / інтернет-магазин / WMS з API Укрпошти; додатково реалізовано адрес, клієнтів, друку супровідних ярликів, розрахунку вартості, трекінгу статусів і контролю доставки.; Сутність
"Content-Type": "application/json",
- timeout;
- HTTP 429;
- HTTP 500;
- HTTP 502;
- HTTP 503;
- HTTP 504;
- тимчасової недоступності API;
- тимчасової помилки друку ярлика;
- тимчасової помилки синхронізації статусів.; # Чи потрібно зберігати адреси одержувачів у K2 ERP?; Тип
GET /api/v1/ukrposhta/post-offices?postcode=01001
4.; shipment.status = "NEEDS_RETRY"
def create_address(self, payload: "AddressPayload") -> "AddressResponse":
- інший формат створення;
- митний характеристика;
- категорію вкладення;
- країну призначення;
- англомовні адресні поля;
- обмеження по вазі;
- додаткові статуси;
- друк митних або супровідних документів.; Тип
"client_id": "sender-client-id",
6.1.; Створення відправлення з K2 ERP
):
|
-
|
old_status
|
varchar
|
Barcode зберігається в K2 ERP.; |-
|
print_count
|
integer
|
}
POST /api/v1/ukrposhta/directories/sync
3.; Основні функціональні можливості API Укрпошти
"postpay_amount": command.delivery.postpay_amount,
pass
UKRPOSHTA_BASE_URL=https://www.ukrposhta.ua/ecom/0.0.1/
|
| AC-11
|
-
|
AuthError
|
-
|
ukrposhta_status
|
varchar
|
-
|
sms_enabled
|
boolean
|
-
|
Audit Logger
|
Check-connection і повідомлення адміністратору.; API повертає shipment_id / barcode.; Поле
|
; Очікуваний результат
</div>
shipment.delivered_at = utc_now()
=== 24.3.; Проблемні відправлення ===
=== Етап 4.; Адреси та клієнти ===
<pre>
},
!; |-
| актуалізація довідників
| Низький
| Регламентна задача.; shipment.error_message = str(exc)
bearer_token: str,
<syntaxhighlight lang="python">
bearer_token: str
{
=== 22.2.; Створення відправлення ===
try:
}
shipment = shipment_repository.create(
!; |-
| style="background:#bbdefb;" | Блакитний
| #bbdefb
| операційна дія виконується або доставка в процесі.; |-
| printed_by
| uuid
| користувач системи.;[[Категорія:K2 ERP]]
* додати rate limiting;
* додати моніторинг;
* додати alerting;
* додати dead letter queue;
* додати резервне копіювання;
* додати безпечне зберігання секретів.;
|
-
|
name
|
varchar
|
-
|
height
|
numeric
|
-
|
Tracking Worker
|
-
|
address_id
|
uuid
|
Адреса.; Коментар
10.; Статуси відправлень
31.; Відкриті питання
15.5.; Пошук відділень
shipment = shipment_repository.get_by_barcode(db, barcode)
| ; Поле
|
style="background:#c8e6c9;" | Зелений
|
| Ярлик надруковано
|
LABEL_PRINTED
|
-
|
AC-9
|
}
|
Повернення, retry, неправильна адреса.; | style="background:#fff9c4;" | Жовтий
|
| Доставлено
|
DELIVERED
|
-
|
raw_response
|
jsonb
|
інтеграційні функціональні можливості зберігається в системі.; |-
|
entity_id
|
uuid
|
style="background:#eeeeee;" | Сірий
|
| Очікує створення
|
PENDING_CREATE
|
-
|
Пошук відділень та індексів
|
-
|
building
|
varchar
|
Будинок.; headers=headers,
pass
def create_shipment(self, payload: "ShipmentPayload") -> "ShipmentResponse":
15.3.; Синхронізація адресних довідників
14.; "shipment_type": "DOMESTIC_PARCEL",
Retry заборонений для:
|
-
|
AC-19
|
-
|
AC-2
|
Очікує створення, прибуло.; Частота актуалізація
entity_id=shipment.id,
self,
|-
| ValidationError
| Некоректні інформаційні дані замовлення.; характеристика
"sender": {
10.; Критерій
db: "Session",
офіційно затверджений портал API Укрпошти містить такі ключові напрями:
pass
6.; |-
| raw_request
| jsonb
| Запит.; |-
| client_type
| varchar
| sender або recipient.; |-
| PhoneValidationError
| Некоректний телефон одержувача.; | Відправлення не створюється без виправлення.; {| class="wikitable"
!; | style="background:#ffcc80;" | Помаранчевий
|-
| Невідомий статус
| UNKNOWN_STATUS
| API повернув статус, якого немає в мапінгу.; Очікуваний результат
2.; |-
| AC-10
| Адреса некоректна.; |-
| Синхронізація статусів
| Середній
| Фоновий бізнес-процес.; |-
| AC-13
| Ярлик друкується повторно.; я хочу бачити статистику по доставках Укрпоштою,
delivery_queue.enqueue(
status_response = await ukrposhta_client.track_shipment(barcode)
|-
| Створення відправлення
| Високий
| ключовий бізнес-процес відвантаження.; Призначення
!; |}
UKRPOSHTA_TIMEOUT_SECONDS=30
import httpx
* створення інтеграції Укрпошти;
* перевірка user token і bearer token;
* створення адреси відправника;
* створення адреси одержувача;
* створення клієнта-відправника;
* створення клієнта-одержувача;
* створення внутрішнього відправлення по Україні;
* збереження shipment_id / barcode;
* друк супровідного ярлика;
* синхронізація статусів;
* дедублікація;
* retry-механізм;
* журнал подій;
* dashboard API;
* базові unit-тести;
* mock API для інтеграційних тестів.; !; | Перевести в NEEDS_CORRECTION.; характеристика
!; | Друге відправлення не створюється.; |-
| style="background:#ffcc80;" | Помаранчевий
| #ffcc80
| Потрібна дія або є собою ризик.; | Потрібен для UI та валідації.; |-
| default_sender_client_id
| varchar
| Клієнт-відправник за замовчуванням.; | має змогу бути окремим модулем.; |-
| Shipment
| Відправлення в API Укрпошти.;=== 15.9.; Скасування / видалення відправлення ===
== 23.; Обробка помилок ==
def track_shipment(self, barcode: str) -> "TrackingResponse":
Користувачі:
old_status=old_status,
return {}
|-
| Відправлення по Україні
| Створення внутрішніх поштових відправлень.;== 16.; Приклад запиту на створення відправлення ==
* неправильного user token;
* неправильного bearer token;
* помилок валідації;
* неправильного індексу;
* недоступного маршруту;
* некоректного телефону;
* відправлення, яке вже створене;
* відправлення, яке вже доставлене;
* відправлення, яке вже скасоване.; |-
| AC-15
| Відправлення доставлено.; Очікуваний результат
"middle_name": "Іванович",
=== 12.1.; Загальна схема ===
!; |-
| default_sender_address_id
| varchar
| Адреса відправника за замовчуванням.;== Див.; 33.; додатково ==
response = await client.request(
* отримати user token;
* отримати authorization bearer;
* перевірити доступ до API;
* отримати актуальну Swagger-документацію;
* перевірити створення адрес;
* перевірити створення клієнтів;
* перевірити створення тестового відправлення;
* перевірити друк ярлика;
* перевірити трекінг.; |-
| Друк ярлика
| Високий
| Потрібно для складу.; | застосовується розробниками.; |}
Ukrposhta API Client
"recipient": {
1.; | style="background:#ffcc80;" | Помаранчевий
|-
| Потребує виправлення
| NEEDS_CORRECTION
| Некоректна адреса, індекс або інформаційні дані одержувача.; | Помилка API, неправильний token, недоступний маршрут.; |-
| Типи відправлень
| 1 раз на добу або після зміни API
| Потрібні для валідації.; |}
4.; 6.; | style="background:#fff9c4;" | Контроль
|-
| Доставлено
| Успішні доставки.; | Потрібен для валідації адрес.; | style="background:#c8e6c9;" | Норма
|-
| Ярлики надруковано
| Готові до пакування відправлення.; |}
=== Етап 5.; Відправлення і валідація ===
# Який тип договору та доступу до API застосовується?; | Перевести в NEEDS_CORRECTION.; Укрпошта
<pre>
<pre>
Retry дозволений для:
!; |-
| Validation Layer
| Перевіряє одержувача, адресу, індекс, вагу, оплату.; |-
| Помилка API
| Код, повідомлення, raw-відповідь.; |-
| AC-16
| Відправлення повертається.;=== Етап 7.; Dashboard та аудит ===
self.bearer_token = bearer_token
UKRPOSHTA_LANGUAGE=ua
new_status = ukrposhta_status_mapper.from_api(status_response)
|-
| Чернетка
| DRAFT
| Замовлення є собою в K2 ERP, але відправлення ще не створено.; | Довідник відділень оновлюється.; !; |-
| Дублювання відправлень
| Повторний запит має змогу створити друге відправлення.; |-
| Label / Sticker
| Супровідний ярлик.; Дата
"apartment": null
== 6.; Основні бізнес-сценарії ==
PATCH /api/v1/ukrposhta/shipments/{shipment_id}
<pre>
{| class="wikitable"
{| class="wikitable"
"postpay_enabled": true,
5.; | Повернути існуюче відправлення.; | Статус стає RETURNING і підсвічується помаранчевим.; №
POST /api/v1/ukrposhta/tracking/sync
API-документація Укрпошти описує послідовність створення простого відправлення так:
{| class="wikitable"
if existing:
self.timeout_seconds = timeout_seconds
== 32.; Джерела ==
!; |-
| TimeoutError
| Перевищено час очікування.; |}
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
"external_order_id": "K2-ORDER-2026-000123",
<pre>
v
self.base_url = base_url.rstrip("/")
"length": 30,
shipment.error_message = str(exc)
[[Категорія:Технічні завдання]]
!; # Чи потрібно підтримувати декілька складів?; Тип
db=db,
if old_status != new_status:
"address_id": "sender-address-id",
== 27. Acceptance Criteria ==
== 17.; Валідація перед створенням відправлення ==
pass
db.commit()
"phone": "+380671112233",
finally:
!; |-
| Створення клієнта
| Тип клієнта, API ID, відповідь.; |}
new_status="CREATED",
!; характеристика
[[Категорія:Інтеграції]]
}
"status": "PENDING_CREATE",
"weight": 2.5,
UKRPOSHTA_RETRY_BACKOFF_SECONDS=5
== 5.; Базовий workflow створення відправлення ==
{| class="wikitable"
=== 21.2. ukrposhta_addresses ===
</div>
!; |-
| Swagger
| Технічна документація API.; :contentReference [oaicite:2]{index=2}
{| class="wikitable"
|-
| AC-14
| Tracking API повертає новий статус.; def get_label(self, shipment_id: str, format: str = "pdf") -> bytes:
* реалізувати dashboard API;
* реалізувати список проблемних відправлень;
* реалізувати фільтри;
* реалізувати експорт, якщо потрібно.; |-
| base_url
| varchar
| URL API.; | Потрібен для синхронізації з K2 ERP.; |}
return shipment
!; |-
| sent_at
| timestamp
| Дата створення в API.; !; # Чи потрібно автономно сповіщати клієнта?; |-
| declared_price
| numeric
| Оголошена вартість.; Ключ
"building": "10",
== 25.; Безпека ==
=== 27.5.; Статуси ===
pass
щоб платформа автономно створила відправлення без ручного введення в кабінеті або іншій системі.; |-
| AddressError
| Некоректна адреса.; Кожне замовлення.; old_status="CREATING",
task_name="send_ukrposhta_shipment",
== 14.; Конфігурація клієнта ==
existing = shipment_repository.get_by_idempotency_key(
pass
=== 15.2.; Перевірка підключення ===
!; Label Service отримує супровідний ярлик.; |-
| style="background:#fff9c4;" | Жовтий
| #fff9c4
| Очікування або прибуття.; Довідник
"postcode": "01001",
<div style="border-left: 6px solid #6a1b9a; background: #f3e5f5; padding: 12px 16px; margin: 16px 0;">
я хочу надрукувати супровідний ярлик по створеному відправленню,
Синхронізуються:
Міжнародні відправлення потрібно реалізовувати окремим модулем, з цієї причини що вони можуть мати:
if response.content:
shipment.sent_at = utc_now()
Як менеджер інтернет-магазину,
!; shipment.status = "CREATED"
)
class UkrposhtaSettings(BaseSettings):
"width": 20,
)
=== 21.4. ukrposhta_shipments ===
{| class="wikitable"
pass
=== 15.12. Dashboard ===
recipient_client = await client_service.ensure_recipient_client(shipment, recipient_address)
5.; | Зупинити інтеграцію, повідомити адміністратора.; Worker створює адресу одержувача.; | Статус стає UNKNOWN_STATUS і потрапляє в список ручної перевірки.; :contentReference [oaicite:3]{index=3}
== 20.; Черга створення відправлень ==
class UkrposhtaClient:
Приклад `.env`:
shipment.ukrposhta_status = status_response.status
__TOC__
!;== 28. MVP ==
* https://dev.ukrposhta.ua/
* https://dev.ukrposhta.ua/documentation
* https://dev.ukrposhta.ua/faq
* https://dev.ukrposhta.ua/for-business
* API documentation 2025.; Заборонено зберігати їх у коді, Git, frontend-змінних або відкритих логах.; Замовлення
</pre>
Потрібно зберігати:
== 29.; Етапи реалізації ==
[[Категорія:Укрпошта]]
</div>
!; Метою задачі є собою створення Python-сервісу для інтеграції з Укрпоштою з метою автоматизації процесів доставки.; Python-сервіс:
</pre>
=== 20.1.; Логіка черги ===
Python Ukrposhta Integration Service
</pre>
"postpay_amount": 1500.00,
<pre>
== 8. User Story ==
def delete_shipment(self, shipment_id: str) -> "DeleteShipmentResponse":
pass
!; command: "CreateUkrposhtaShipmentCommand",
== 19.; Дедублікація ==
|-
| API Layer
| REST API для прийому замовлень і команд із K2 ERP.; if new_status == "DELIVERED":
<pre>
raise UkrposhtaApiError(response.text)
<div style="border-left: 6px solid #1565c0; background: #e3f2fd; padding: 12px 16px; margin: 16px 0;">
"first_name": "Іван",
=== 15.1.; Створення інтеграції ===
|-
| Integration Account
| конфігурація API Укрпошти.; Створити відправлення або групу відправлень.; |-
| Відділення
| 1 раз на добу або за потреби
| Потрібні для вибору точки відправлення/видачі.; |-
| shipment_id
| ID відправлення в API Укрпошти.; |-
| entity_type
| varchar
| integration, shipment, address, client, label, directory.; |-
| shipment_hash
| Hash основних параметрів відправлення.; | Вони підсвічуються помаранчевим.;[[Категорія:Ukrposhta API]]
<pre>
платформа повинна логувати:
</pre>
return
я хочу бачити статус доставки прямо в K2 ERP,
!; |-
| district
| varchar
| Район.; | Print count збільшується, дія логуються.; Як керівник,
{| class="wikitable"
!; |-
| phone
| varchar
| Телефон.; Тип
* створити FastAPI-проєкт;
* налаштувати PostgreSQL;
* створити моделі інтеграції, адрес, клієнтів, відправлень, ярликів, подій;
* налаштувати Alembic;
* реалізувати healthcheck.; # Чи потрібно друкувати ярлики автономно після створення?; | Вони підсвічуються червоним.; | style="background:#ffcc80;" | Потрібна дія
|}
json: dict | None = None,
{| class="wikitable"
def search_post_offices(self, filters: dict) -> "PostOfficeListResponse":
Сервіс повинен забезпечити:
"name": "ТОВ «Відправник»",
|-
| Замовлень до відправки
| 42
| style="background:#fff9c4;" | Увага
|-
| Відправлень створено сьогодні
| 185
| style="background:#c8e6c9;" | Норма
|-
| Ярлики надруковано
| 172
| style="background:#c8e6c9;" | Норма
|-
| У дорозі
| 620
| style="background:#bbdefb;" | В роботі
|-
| Прибуло
| 88
| style="background:#fff9c4;" | Контроль
|-
| Доставлено
| 410
| style="background:#c8e6c9;" | Норма
|-
| Повернення
| 21
| style="background:#ffcc80;" | Потрібна дія
|-
| Помилки створення
| 5
| style="background:#ef9a9a;" | Критично
|-
| Потребують виправлення
| 9
| style="background:#ffcc80;" | Потрібна дія
|}
платформа повинна не допускати дублювання відправлень.; | style="background:#ef9a9a;" | Критично
|-
| Потребують виправлення
| Некоректні адреси, індекси, телефони.; Очікуваний результат
entity_type="ukrposhta_shipment",
pass
== 15.; API Python-сервісу ==
event_type="UKRPOSHTA_STATUS_SYNCED",
async def create_ukrposhta_shipment(
=== 8.3.; Контроль статусів ===
<pre>
sha256(external_order_id + recipient_phone + recipient_postcode + declared_price + weight)
{| class="wikitable"
=== 15.4.; Пошук індексів ===
)
audit_logger.log(
!; 7.;</pre>
"declared_price": command.delivery.declared_price,
"apartment": "5"
|-
| Внутрішня посилка
| DOMESTIC_PARCEL
| Відправлення по Україні.; |-
| shipment_id
| varchar
| ID відправлення в API Укрпошти.; |-
| PostcodeError
| Некоректний або недоступний індекс.; |-
| event_type
| varchar
| Тип події.; |-
| printed_at
| timestamp
| Дата друку.; | ключовий сценарій для MVP.; * API documentation: Internal letters.; Стан
{| class="wikitable"
=== 21.3. ukrposhta_clients ===
=== 15.8.; актуалізація відправлення ===
</pre>
{| class="wikitable"
params=params,
!;<div style="border-left: 6px solid #2e7d32; background: #e8f5e9; padding: 12px 16px; margin: 16px 0;">
* реалізувати створення відправлення;
* реалізувати мапінг K2 ERP → API Укрпошти;
* реалізувати валідацію;
* реалізувати hash відправлення;
* реалізувати дедублікацію.; |-
| AC-8
| API повертає barcode.; |-
| region
| varchar
| Область.;=== 22.3.; Worker створення відправлення ===
</pre>
"weight": command.delivery.weight,
* створено;
* зареєстровано;
* прийнято;
* у дорозі;
* прибуло;
* доставлено;
* вручено;
* повертається;
* повернуто;
* скасовано;
* помилка;
* невідомий статус.;=== 27.3.; Створення відправлення ===
{{SEO
|title=Технічне завдання: Інтеграція з Укрпоштою для Python
|description=Технічне завдання на реалізацію Python-сервісу для інтеграції K2 ERP, CRM або інтернет-магазину з API Укрпошти: створення відправлень, адреси, клієнти, ярлики, тарифи, статуси, трекінг, міжнародні відправлення, dashboard та журналювання.
|keywords=Python, Укрпошта, Ukrposhta API, API Укрпошта, ТТН, ярлик, відправлення, доставка, K2 ERP, CRM, інтернет-магазин, FastAPI, логістика, поштовий індекс, трекінг
}}
!; |-
| idempotency_key
| Унікальний ключ конкретної спроби створення відправлення.; |-
| Міжнародні відправлення
| Створення міжнародних відправлень.; Поле
!; |-
| Mapping Layer
| Перетворює структури K2 ERP у формат API Укрпошти.;== 11.; Єдина логіка кольорів ==
"height": 15,
</pre>
Критично істотно: якщо відправлення вже створене, повторний запит не повинен створювати нове відправлення.; |-
| apartment
|
varchar
|
-
|
created_at
|
timestamp
|
-
|
Post Office
|
Відділення Укрпошти.; 1.; №
<syntaxhighlight lang="python">
shipment = shipment_repository.get_by_id(db, shipment_id)
sender_address = await address_service.ensure_sender_address(shipment)
"sms": true
if not shipment:
!; |-
| style="background:#ef9a9a;" | Червоний
| #ef9a9a
| Помилка або негативний результат.; # Чи потрібно формувати групи відправлень?; Замовлення, замовник, адреса, вантаж
entity_id=shipment.id,
retry_backoff_seconds: int = 5
|
| 2.; |-
| external_address_id
| varchar
| ID адреси в API Укрпошти.; |-
| Створення відправлення
| Shipment ID, barcode, дата, відповідь API.; | платформа показує AuthError і не створює відправлення.; url=f"{self.base_url}/{path.lstrip('/')}",
'''Критично істотно:''' user token і authorization bearer потрібно зберігати тільки в зашифрованому вигляді або secret storage.; |}
user_token: str,
!; |-
| API Event
| Подія інтеграції.; |}
=== 6.3.; Синхронізація статусів ===
)
POST /api/v1/ukrposhta/routes/check-availability
{| class="wikitable"
for barcode in barcodes:
<pre>
|-
| id
| uuid
| ID інтеграції.; Колір
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
"last_name": "Петренко",
<syntaxhighlight lang="python">
я хочу натиснути кнопку «Створити відправлення Укрпошта»,
'''Для K2 ERP:''' цей workflow потрібно приховати від користувача.; # Чи потрібно підтримувати декілька відправників?; |-
| Delivery Order
| Замовлення на доставку в K2 ERP.; |-
| sender_client_id
| uuid
| Клієнт-відправник.; |-
| barcode
| Штрихкод / номер відправлення.; |-
| new_status
| varchar
| Новий статус.; |-
| barcode
| varchar
| Штрихкод / номер відправлення.; |-
| Sender Address
| Адреса відправника.; | Перевести в NEEDS_CORRECTION.; |-
| Client Service
| Створює та кешує клієнтів відправника й одержувача.; Для них потрібно передбачити окремий тип документа, оскільки листи мають інший життєвий цикл та власні параметри.; |-
| status
| varchar
| Статус K2 ERP.; Значення
=== 20.2.; Пріоритети задач ===
def create_client(self, payload: "ClientPayload") -> "ClientResponse":
Ukrposhta Client — це Python-клас або пакет, який інкапсулює роботу з API Укрпошти.; | style="background:#ffcc80;" | Помаранчевий
|-
| Помилка
| ERROR
| Помилка створення або синхронізації.; |-
| Dashboard API
| інформаційні дані для менеджера, складу та керівника.; Очікуваний результат
}
def create_shipment_group(self, payload: "ShipmentGroupPayload") -> "ShipmentGroupResponse":
shipment.shipment_id = response.id
shipment.status = new_status
K2 ERP / Dashboard / складський облік / Менеджер
!; Критерій
v
!; характеристика
<pre>
{| class="wikitable"
=== Етап 3.; Ukrposhta Client ===
path: str,
ukrposhta_validator.validate(command)
!; |-
| Shipment Service
| Створює відправлення або групи відправлень.; |-
| Отримання статусу
| Старий статус, новий статус, джерело.; |-
| Перевірка маршруту
| Середній
| Валідаційний бізнес-процес.; |-
| Recipient Client
| Клієнт-одержувач в API Укрпошти.; |-
| Створення адреси
| Тип адреси, API ID, відповідь.; * зберігання налаштувань інтеграції;
* перевірку підключення до API;
* створення адреси відправника;
* створення адреси одержувача;
* створення клієнта-відправника;
* створення клієнта-одержувача;
* створення відправлення або групи відправлень;
* друк супровідних документів / ярликів;
* розрахунок вартості доставки, якщо підтримується API;
* перевірку доступності маршруту доставки;
* пошук поштових індексів;
* пошук відділень;
* отримання статусів відправлень;
* синхронізацію статусів назад у K2 ERP;
* підтримку внутрішніх відправлень по Україні;
* підтримку міжнародних відправлень як окремого сценарію;
* журналювання всіх API-запитів;
* dashboard для контролю логістики.; | Черга, retry, dashboard помилок.; |-
| Tracking Status
| Статус доставки.; | style="background:#eeeeee;" | Сірий
|}
{| class="wikitable"
GET /api/v1/ukrposhta/shipments/{shipment_id}/label
self,
},
<pre>
<div style="border-left: 6px solid #2e7d32; background: #e8f5e9; padding: 12px 16px; margin: 16px 0;">
POST /api/v1/ukrposhta/shipments/{shipment_id}/cancel
|-
| style="background:#c8e6c9;" | Зелений
| #c8e6c9
| Успішно: створено, зареєстровано, ярлик надруковано, доставлено.; | Окремий сценарій із власними правилами.; |-
| external_client_id
| varchar
| ID клієнта в API Укрпошти.; |-
| Внутрішні листи
| Окремий API-сценарій для листів.; Надрукувати супровідні документи / ярлик.; Тип
=== 21.5. ukrposhta_labels ===
=== 6.2.; Друк ярлика ===
<syntaxhighlight lang="python">
* індекс;
* область;
* район;
* населений пункт;
* вулицю, якщо доступна;
* відділення, якщо прив'язане;
* ознаку активності;
* дату актуалізація.; |-
| Скасування відправлення
| Високий
| істотно до передачі посилки.; K2 ERP отримує номер відправлення.; # Чи потрібно експортувати журнал відправлень в Excel?; |-
| payload
| jsonb
| Технічні інформаційні дані.; Статус
recipient_address = await address_service.ensure_recipient_address(shipment)
* менеджер;
* комірник;
* оператор складу.; |-
| style="background:#eeeeee;" | Сірий
| #eeeeee
| Чернетка, скасовано або неактивно.; # Чи потрібні тільки внутрішні відправлення по Україні?; Колір
"description": "Одяг",
<pre>
!; | Повторити фоново.; характеристика
=== 8.1.; Створення відправлення ===
v
Python-сервіс регулярно отримує статуси відправлень і оновлює K2 ERP.; |-
| shipment_type
| varchar
| DOMESTIC_PARCEL, INTERNATIONAL_PARCEL тощо.; характеристика
!; характеристика
entity_id=shipment.id,
<pre>
</div>
До MVP входить:
|-
| id
| uuid
| ID події.; Коментар
payload=status_response.raw_payload,
POST /api/v1/ukrposhta/integrations/{integration_id}/check-connection
"city": "Львів",
== 1.; Мета ==
[[Категорія:Python]]
</pre>
sender_client=sender_client,
"street": "Хрещатик",
!; |-
| AC-3
| Token неправильний.; Причина
* перевіряє замовлення;
* перевіряє одержувача;
* перевіряє адресу та індекс;
* створює або знаходить адресу відправника;
* створює або знаходить адресу одержувача;
* створює або знаходить клієнта-відправника;
* створює або знаходить клієнта-одержувача;
* створює відправлення;
* зберігає barcode / shipment UUID / номер відправлення;
* формує супровідний ярлик;
* передає номер відправлення назад у K2 ERP.; |-
| Shipment Group
| Група відправлень.; |-
| Відстеження відправлень
| Отримання статусів доставки.; |-
| style="background:#f3e5f5;" | Фіолетовий
| #f3e5f5
| Спеціальний або невідомий статус.; Python-сервіс зберігає номер відправлення.;=== 13.1.; Призначення ===
* реалізувати створення адреси відправника;
* реалізувати створення адреси одержувача;
* реалізувати кешування адрес;
* реалізувати створення клієнтів;
* реалізувати повторне використання клієнтів.; | Валідація індексу до API-запиту.; |-
| Адресний класифікатор
| 1 раз на добу або за регламентом
| має змогу бути великим довідником.;=== 6.5.; Внутрішні листи ===
</pre>
params.setdefault("token", self.user_token)
shipment.status = "ERROR"
=== Етап 1.; Аналіз API Укрпошти ===
== 18.; Адресний класифікатор і довідники ==
shipment.barcode = response.barcode
!;</div>
* PDF або інший формат, який повертає API;
* файл зберігається у картці відправлення;
* статус змінюється на LABEL_PRINTED;
* дія логуються в аудиті.; |}
</pre>
== 22.; Приклад Python-логіки ==
<syntaxhighlight lang="python">
{{DISPLAYTITLE:Технічне завдання: Інтеграція з Укрпоштою для Python}}
headers = {
|-
| id
| uuid
| Внутрішній ID.; KPI
=== 27.2.; Довідники ===
!; |}
=== 15.7.; Створення відправлення ===
async def send_ukrposhta_shipment(shipment_id: str, db: "Session") -> None:
!; Поле
def check_connection(self) -> "ConnectionStatus":
інтеграційні функціональні можливості призначена для:
payload={"external_order_id": command.external_order_id},
|-
| Створення запиту на відправлення
| Замовлення, одержувач, індекс, адреса, сума.; Як менеджер,
=== 18.2.; Відділення ===
pass
</div>
=== 15.6.; Перевірка маршруту між індексами ===
shipment.status = "CREATING"
def __init__(
== 2.; Область сфера застосування ==
"idempotency_key": command.idempotency_key,
11.; shipment.raw_response = response.raw_payload
|
| 5.; base_url: str = "https://www.ukrposhta.ua/ecom/0.0.1/"
!; | style="background:#ffcc80;" | Важлива
|-
| Внутрішній лист
| DOMESTIC_LETTER
| Лист по Україні.; характеристика
=== 18.1.; Поштові індекси ===
!; |-
| raw_response
| jsonb
| Відповідь API.; Створити адресу одержувача.; def check_route_availability(self, sender_postcode: str, recipient_postcode: str) -> "RouteAvailabilityResponse":
v
=== Етап 6.; Статуси та друк ===
на `REGISTERED` виступає ключовою рисою У документації для міжнародних відправлень описується lifecycle із полями `status` та `statusDate`; після створення статус змінюється на `CREATED`, а після реєстрації.; | style="background:#ef9a9a;" | Червоний
|-
| Потребує повтору
| NEEDS_RETRY
| Технічна помилка, можна повторити.; | style="background:#c8e6c9;" | Норма
|-
| У дорозі
| Відправлення в транспортуванні.; |-
| error_message
| text
| Помилка.; |-
| Address Classifier
| Адресний класифікатор.; | style="background:#fff9c4;" | Додаткова
|-
| Група відправлень
| SHIPMENT_GROUP
| Пакетна передача декількох відправлень.; Поле
timeout_seconds: int = 30
[[Категорія:API]]
K2 ERP передає в Python-сервіс замовлення, інформаційні дані одержувача, адресу, індекс, параметри вантажу та оплату.; |-
| length
| numeric
| Довжина.; "delivery": {
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
)
timeout_seconds: int = 30,
) -> dict:
!; !; | style="background:#bbdefb;" | Блакитний
|-
| Створено
| CREATED
| Відправлення створено в API.; Дія системи
|-
| 07.05.2026
| K2-ORDER-123
| -
| Іван Петренко
| style="background:#ef9a9a;" | Помилка
| Некоректний індекс
| Виправити адресу
|-
| 07.05.2026
| K2-ORDER-124
| 0500000000000
| Олена Сидоренко
| style="background:#ffcc80;" | Повернення
| Не отримано
| Контроль повернення
|-
| 07.05.2026
| K2-ORDER-125
| 0500000000001
| ТОВ «Альфа»
| style="background:#f3e5f5;" | Невідомий статус
| Новий статус API без мапінгу
| Оновити мапінг
|}
[[Категорія:Логістика]]
"street": "Січових Стрільців",
* зберігання user token і bearer token тільки у secret storage або в зашифрованому вигляді;
* заборону логування token;
* HTTPS для всіх API-запитів;
* перевірку SSL;
* рольову модель доступу;
* окремі права на створення відправлення;
* окремі права на скасування відправлення;
* окремі права на друк ярлика;
* журнал усіх дій;
* захист від дублювання відправлень;
* маскування телефонів одержувачів у логах;
* контроль доступу до персональних даних.; |-
| Повторна операційна дія
| Хто запустив, причина, результат.; |-
| postcode
| varchar
| Поштовий індекс.; |-
| created_at
| timestamp
| Дата створення.; | Показати менеджеру.; |-
| street
| varchar
| Вулиця.; Менеджер натискає одну кнопку «Створити відправлення Укрпошта», а Python-сервіс сам виконує всі технічні кроки.; характеристика
'''Технічний стек:''' Python 3.11+, FastAPI, PostgreSQL, SQLAlchemy, Alembic, httpx, Pydantic, Celery/RQ/APScheduler, Redis, Docker.; Окремо варто відзначити кожне відправлення, повторний запит, друк ярлика, помилка API і зміна статусу повинні мати внутрішній ID, idempotency_key, журнал подій і контроль повторної обробки.; HTML
=== 27.4.; Друк ярлика ===
</div>
},
"address": {
== 26.; Логування та аудит ==
Як комірник,
23.1.; Типи помилок
base_url: str,
UKRPOSHTA_BEARER_TOKEN=********
22.4.; Синхронізація статусів
UKRPOSHTA_USER_TOKEN=********
UKRPOSHTA_LABEL_BASE_URL=https://www.ukrposhta.ua/ecom/0.0.1/
23.2.; Retry-логіка
3.; Тип помилки
label_base_url: str | None = None
24.2.; Приклад dashboard
| style="background:#ffcc80;" | Потрібна дія
|
| Помилки API
|
style="background:#fff9c4;" | Увага
|
| Відправлень створено
|
Кількість створених відправлень.; актуалізація статусів
def track_shipments(self, barcodes: list [str]) -> "TrackingListResponse":
def get_shipment(self, shipment_id: str) -> "ShipmentResponse":
pass
</syntaxhighlight>
щоб оперативно реагувати на повернення, затримки та проблемні доставки.; # Чи потрібна супровід внутрішніх листів?; |}
async with httpx.AsyncClient(timeout=self.timeout_seconds) as client:
27.6. Dashboard
- підписаний договір з Укрпоштою;
- user token;
- authorization bearer;
- доступ до API-документації;
- тестове середовище або тестові інформаційні дані, якщо надаються;
- інформаційні дані відправника;
- адресу відправника;
- контактну особу відправника;
- правила оплати доставки;
- правила післяплати;
- правила міжнародних відправлень, якщо потрібні;
- правила друку ярликів;
- правила актуалізація статусів;
- перелік сервісів доставки, які будуть використовуватись;
- вимоги K2 ERP до збереження номерів відправлень.; Колір
4.; Передумови
2.; |-
|
postpay_amount
|
numeric
|
Не створювати відправлення, показати список помилок.; Ризик
| -
|
Recipient Address
|
-
|
TrackingError
|
-
|
is_active
|
boolean
|
style="background:#c8e6c9;" | Зелений
|
| Повертається
|
RETURNING
|
-
|
Address Service
|
Створює та кешує адреси відправника й одержувача.; event_type="UKRPOSHTA_SHIPMENT_CREATED",
істотно: методи Python-клієнта є собою внутрішньою абстракцією.; * реалізувати синхронізацію статусів;
- реалізувати друк ярлика;
- реалізувати retry;
- реалізувати збереження PDF.; |}
if response.status_code >= 400:
except Exception as exc:
Офіційна інструкція «Як почати роботу з API» описує базовий workflow: створити адресу відправника, створити адресу одержувача, створити клієнта-відправника, створити клієнта-одержувача, створити відправлення або групу відправлень, після чого надрукувати супровідні документи.; | Версіонування клієнта і contract-тести.; |-
| shipment_id
|
uuid
|
Відправлення.; * інтернет-магазинів;
- CRM;
- ERP;
- WMS;
- складів;
- служб доставки;
- торгових компаній;
- дистриб'юторів;
- компаній, які створюють багато поштових відправлень;
- компаній, які хочуть контролювати доставку прямо з K2 ERP.; entity_type="ukrposhta_shipment",
</syntaxhighlight>
return existing
}
) -> "UkrposhtaShipment":
pass
db.commit()
|
-
|
file_id
|
uuid
|
UNKNOWN_STATUS і таблиця status_mapping.; },
def update_shipment(self, shipment_id: str, payload: "ShipmentPayload") -> "ShipmentResponse":
"idempotency_key": "K2-ORDER-2026-000123-ukrposhta-v1",
</syntaxhighlight>
6.4.; Міжнародні відправлення
|
| Поштові індекси
|
1 раз на добу або за потреби
|
style="background:#ffcc80;" | Помаранчевий
|
| Повернуто
|
RETURNED
|
-
|
external_order_id
|
varchar
|
-
|
AC-12
|
Відправлення не створюється, статус NEEDS_CORRECTION.; |-
|
email
|
varchar
|
-
|
updated_at
|
timestamp
|
-
|
Label Service
|
style="background:#fff9c4;" | Додаткова
|
| Рекомендований лист
|
REGISTERED_LETTER
|
-
|
Недоступність API
|
}
15.10.; Друк ярлика
def search_postcodes(self, filters: dict) -> "PostcodeListResponse":
UKRPOSHTA_RETRY_COUNT=3
payload = ukrposhta_mapper.to_shipment_payload(
|
| id
|
uuid
|
class="wikitable"
|
Він бачить замовлення, відправлення, доставки, повернення та помилки.; | K2 ERP оновлює статус відправлення.; |-
|
ApiError
|
API повернув помилку.; Tracking Worker оновлює статуси доставки.; Валідація, мапінг, дедублікація, черга
</syntaxhighlight>
|
-
|
bearer_token_encrypted
|
text
|
style="background:#c8e6c9;" | Базова
|
| Міжнародна посилка
|
INTERNATIONAL_PARCEL
|
Відправлення за кордон.; Показник
K2 ERP / CRM / Website / WMS
|
-
|
AC-6
|
-
|
Ukrposhta Client
|
Python-клієнт для API Укрпошти.; Тип
retry_count: int = 3
!; | Idempotency key і перевірка external_order_id.; |-
| Некоректний індекс
| Відправлення має змогу не створитись.; Що зберігати
* наявність external_order_id;
* наявність idempotency_key;
* чи не створено вже відправлення для цього замовлення;
* user token активний;
* bearer token активний;
* ПІБ або назву одержувача;
* телефон одержувача;
* індекс одержувача;
* адресу одержувача;
* індекс відправника;
* адресу відправника;
* доступність маршруту між індексами, якщо застосовується перевірка;
* вагу більше 0;
* габарити більше 0, якщо обов'язкові;
* оголошену вартість;
* післяплату, якщо застосовується;
* SMS-опцію, якщо застосовується;
* коректність типу відправлення;
* коректність міжнародних полів, якщо це міжнародне відправлення.; Значення
=== 12.2.; Основні компоненти Python-сервісу ===
db.commit()
!; Призначення
payload={
Результат:
class UkrposhtaClient:
class UkrposhtaApiError(Exception):
old_status = shipment.status
27.1.; інтеграційні функціональні можливості
|
-
|
recipient_client_id
|
uuid
|
Клієнт-одержувач.; event_type="UKRPOSHTA_SHIPMENT_QUEUED",
- реалізувати базовий request method;
- реалізувати create_address;
- реалізувати create_client;
- реалізувати create_shipment;
- реалізувати get_label;
- реалізувати track_shipment;
- реалізувати check_route_availability;
- реалізувати обробку помилок.; Критерій
|
| Замовлень до відправки
|
class="wikitable"
continue
- ID або код відділення;
- поштовий індекс;
- назву;
- адресу;
- населений пункт;
- координати, якщо доступні;
- графік роботи;
- ознаку активності;
- доступні сервіси.; | Архів, чернетки.; характеристика
30.; Ризики
|
style="background:#bbdefb;" | Блакитний
|
| Прибуло
|
ARRIVED
|
-
|
Скасування
|
}
except TemporaryUkrposhtaError as exc:
from pydantic_settings import BaseSettings
|
; Worker створює клієнта-одержувача.; Тип
audit_logger.log(
13.; new_status="PENDING_CREATE",
params: dict | None = None,
shipment=shipment,
12.; | style="background:#bbdefb;" | Блакитний
| У дорозі
|
IN_TRANSIT
|
Відправлення рухається.; характеристика
3.; |-
|
idempotency_key
|
varchar
|
Довідник індексів оновлюється.; |}
if shipment.status in ["CREATED", "REGISTERED", "DELIVERED"] and shipment.barcode:
async def sync_ukrposhta_statuses(barcodes: list [str], db: "Session") -> None:
idempotency_key=command.idempotency_key,
new_status=new_status,
| AC-4
|
платформа запускає синхронізацію індексів.; * Swagger-документація Укрпошти.; Статус K2 ERP
21.1. ukrposhta_integrations
"building": "1",
|
-
|
name
|
varchar
|
-
|
postpay_enabled
|
boolean
|
Чи є собою післяплата.; Тип задачі
)
Перед створенням відправлення платформа повинна перевірити:
Потрібно зберігати:
API Укрпошти має окрему документацію для внутрішніх листів.; Worker створює клієнта-відправника, якщо потрібно.; | style="background:#fff9c4;" | Жовтий
|
| Створюється
|
CREATING
|
-
|
delivered_at
|
timestamp
|
Дата доставки.; * API documentation: International shipments.; !; # Чи потрібні міжнародні відправлення?; API Укрпошти
pass
|
|
-
|
source
|
varchar
|
K2_ERP, PYTHON_SERVICE, UKRPOSHTA, USER.; Коментар
GET /api/v1/ukrposhta/dashboard?date_from=2026-05-01&date_to=2026-05-31
"postpay_enabled": command.delivery.postpay_enabled,
sender_client = await client_service.ensure_sender_client(shipment, sender_address)
8.2.; Друк ярлика
return response.json()
v
"shipment_type": command.shipment_type,
"shipment_id": shipment.shipment_id,
платформа повинна забезпечити:
22.1.; Базовий API-клієнт
json=json,
|
-
|
AC-20
|
є собою повернення.; Код
|
платформа повертає PDF або інший доступний формат.; Реальні URI API потрібно брати з актуальної Swagger-документації Укрпошти.; "Authorization": f"Bearer {self.bearer_token}",
|
; Barcode
|
Винести в окремий етап.; # Який формат друку потрібен: A4, термопринтер, PDF?; | style="background:#c8e6c9;" | Зелений
|
| Передано Укрпошті
|
ACCEPTED_BY_UKRPOSHTA
|
Відправлення прийнято оператором.; Критерій
"region": "Львівська",
8.4.; Dashboard керівника
Етап 2.; Базовий Python-сервіс
13. Ukrposhta Client
24.; Dashboard менеджера і керівника
async def request(
POST /api/v1/ukrposhta/shipments
|
|
|
|
|
|
|
|
|