Коли покупець оплачує замовлення банківською карткою через monobank, LiqPay або WayForPay, закон вимагає видати йому фіскальний чек. Якщо інтернет-магазин приймає десятки замовлень на день, робити це вручну через окремий касовий апарат чи веб-кабінет стає неможливо. Ручна робота забирає години робочого часу, а помилка або забутий Z-звіт тягнуть за собою прямі податкові штрафи. Нижче розібрано, як побудувати надійну автоматичну інтеграцію магазину з програмним РРО Checkbox, яка відкриває зміну, фіскалізує оплату, надсилає чек покупцеві та формує Z-звіт без участі оператора.
Законодавчі вимоги та розміри податкових штрафів
В Україні застосування РРО та програмних РРО (ПРРО) регулює Закон України № 265/95-ВР. З 1 жовтня 2023 року за Законом № 3219-IX держава повністю повернула фінансову відповідальність за порушення порядку проведення розрахункових операцій. Штрафи не є символічними. Вони розраховуються від суми продажу:
- 100% вартості проданих з порушенням товарів або послуг за перше виявлене порушення,
- 150% вартості проданих товарів за кожне наступне порушення.
Податкова служба чітко розмежовує способи розрахунків. Якщо покупець оплачує рахунок за повними реквізитами IBAN безпосередньо зі свого банківського рахунку без застосування платіжних карток, така операція не вважається розрахунковою в розумінні закону і чек видавати не потрібно. Але якщо оплата проходить на сайті через кнопку оплати, віджет еквайрингу, Apple Pay або Google Pay, це є безготівкова розрахункова операція. Фіскальний чек для неї обов'язковий.
Закон зобов'язує надати покупцеві розрахунковий документ у момент отримання оплати або під час передачі товару поштовій службі. Для інтернет-торгівлі електронний чек має таку ж юридичну силу, як і паперовий. Покупець може отримати його на електронну пошту, у месенджер або у вигляді посилання з QR-кодом.
Чому ручна видача чеків створює збитки
Багато власників інтернет-магазинів намагаються зекономити на інтеграції, доручаючи створення чеків менеджеру. Практика показує, що така економія швидко призводить до втрат. Ось головні проблеми ручного підходу:
- Оплати в неробочий час. Покупці часто замовляють товари ввечері, у вихідні або вночі. Менеджера на робочому місці немає, зміна закрита, а чек має бути сформований вчасно.
- Людські помилки при перенесенні даних. Менеджер може випадково пропустити копійки, переплутати кількість або не вказати обов'язковий код УКТ ЗЕД для підакцизного чи технічно складного товару. Некоректний чек податкова вважає невиданим.
- Забуте закриття зміни. За законом фіскальна зміна касира не може тривати довше 24 годин. Зміну треба закривати щодня до 23:59:59 формуванням фіскального звітного чека (Z-звіту). Якщо касир пішов додому і забув натиснути кнопку, каса блокується, а наступного дня магазин не може законно приймати оплати.
- Втрачений час команди. Створення одного чека вручну займає від двох до трьох хвилин. При потоці в 50 замовлень на день менеджер витрачає понад дві години лише на монотонне заповнення форм.
Архітектура автоматичної інтеграції
Правильна схема автоматизації виключає людину з ланцюжка формування фіскальних документів. Робота будується на подіях платіжної системи та асинхронній черзі завдань. Схема процесу складається з чотирьох кроків:
- Отримання вебхука від банку. Покупець сплачує замовлення через monobank або LiqPay. Платіжний шлюз надсилає серверний POST-запит на вебхук вашого інтернет-магазину зі статусом успішної оплати.
- Постановка завдання в чергу. Обробник вебхука перевіряє підпис запиту, оновлює статус замовлення в базі магазину і негайно ставить завдання фіскалізації у фонову чергу (наприклад, Laravel Queue, Celery або чергу воркфлоу n8n). Вебхук одразу повертає статус 200 банку, не чекаючи відповіді фіскального сервера.
- Взаємодія з Checkbox API. Фоновий воркер бере завдання, перевіряє стан зміни касира, формує JSON-структуру чека з точними позиціями і кодами УКТ ЗЕД та відправляє запит на створення чека продажу.
- Доставка чека клієнту. Checkbox автоматично відправляє електронний чек на пошту покупця. Додатково магазин зберігає фіскальний номер і посилання на чек у картці замовлення для відправки в SMS або месенджері.
Асинхронний підхід критично важливий для швидкості сайту. Згідно з дослідженням Baymard Institute, середній показник кинутих кошиків сягає 70,22%, причому 17% покупців кидають замовлення через технічні збої та затримки під час оформлення. Якщо викликати фіскалізацію синхронно прямо у вебхуку чи під час перенаправлення клієнта, будь-яка секундна затримка сервера ДПС призведе до таймауту і збою замовлення.
Робота з Checkbox REST API
Сервіс Checkbox надає повноцінний RESTful API зі специфікацією OpenAPI v2 (офіційна документація Checkbox). Усі запити виконуються у форматі JSON з обов'язковими системними заголовками.
Для авторизації та роботи потрібні ліцензійний ключ каси (License Key), логін і пароль касира або персональний пін-код касира. Авторизація за пін-кодом є найбільш зручною для фонових скриптів. Вона виконується через метод POST /api/v1/cashier/signinPinCode:
curl -X POST "https://api.checkbox.ua/api/v1/cashier/signinPinCode" \
-H "accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Client-Name: MyShop-Integration" \
-H "X-Client-Version: 1.0.0" \
-H "X-License-Key: 1a2b3c4d5e6f" \
-d '{"pin_code": "1234"}'
У відповідь API повертає об'єкт з Bearer-токеном у полі access_token. Цей токен використовується для всіх наступних операцій у заголовку Authorization: Bearer <token>.
Перед створенням чека скрипт завжди перевіряє стан зміни касира через метод GET /api/v1/cashier/shift. Якщо зміна має статус CLOSED, її необхідно відкрити перед фіскалізацією:
curl -X POST "https://api.checkbox.ua/api/v1/shifts" \
-H "Authorization: Bearer <access_token>" \
-H "X-Client-Name: MyShop-Integration" \
-H "X-Client-Version: 1.0.0"
Відкриття зміни відбувається асинхронно через хмарний підпис (HSM). Checkbox підписує відкриття зміни електронним цифровим підписом підприємства і реєструє її на сервері податкової служби.
Створення та відправка фіскального чека
Створення розрахункового документа продажу відбувається через метод POST /api/v1/receipts/sell. Схема ReceiptSellPayload вимагає точного дотримання форматів даних. Зверніть увагу на два правила API:
- Усі грошові суми (ціни товарів, суми оплат, знижки) передаються в копійках цілими числами. Наприклад, ціна 450 грн передається як
45000. Це захищає від помилок округлення дробових чисел. - Кількість товару передається у тисячних частках одиниці. Одна одиниця штучного товару передається як ціле число
1000, а пів кілограма вагової продукції як500.
Ось реальний приклад тіла запиту для онлайн-замовлення з безготівковою оплатою карткою:
{
"id": "b78d21ea-3a1e-450f-9f70-d5a230722101",
"order_id": "ORDER-9182",
"goods": [
{
"good": {
"code": "SKU-9921",
"name": "Бездротові навушники Pro Studio",
"price": 280000,
"uktzed": "8518300090"
},
"quantity": 1000
}
],
"payments": [
{
"type": "CASHLESS",
"value": 280000,
"label": "monobank"
}
],
"delivery": {
"email": "[email protected]"
}
}
Поле order_id містить номер замовлення з вашого магазину, а поле id приймає унікальний UUID запиту. Якщо через мережевий збій воркер повторить той самий запит, Checkbox поверне вже створений чек замість створення дубліката. Це гарантує повну ідемпотентність операції.
Якщо покупець замовив товар з обов'язковим кодом товарної класифікації, поле uktzed містить 10 цифр коду УКТ ЗЕД. У разі його відсутності для підакцизних товарів чек буде відхилено податковим сервером.
Доставка чека покупцеві
Закон вимагає надати чек покупцеві. Checkbox вирішує це питання вбудованими механізмами, які не потребують додаткових витрат на дорогі SMS-повідомлення:
- Автоматична безкоштовна відправка на email. Якщо в об'єкті
deliveryпередано електронну пошту клієнта, сервер Checkbox сам формує красивий лист з деталізацією покупок і прямим посиланням на чек. Також лист можна надіслати окремим запитомPOST /api/v1/receipts/{receipt_id}/email. - Публічне посилання на чек. Кожен фіскалізований чек отримує унікальне посилання вигляду
https://check.gov.uaабо сторінку в системі Checkbox. Це посилання можна безкоштовно надіслати клієнту через Telegram-бота або Viber-бота разом з номером накладної Нової Пошти. - QR-код чека. Метод
GET /api/v1/receipts/{receipt_id}/qrcodeповертає графічний QR-код. Його можна роздрукувати на товарному чеку чи вкласти у відправлення.
Автоматичне закриття зміни та Z-звіт
Щоденне закриття зміни є обов'язковим фіскальним обов'язком. Згідно з вимогами ДПС, тривалість однієї зміни не повинна перевищувати одну календарну добу. Якщо каса відкрита о 09:00 ранку, вона має бути закрита до опівночі.
Закриття зміни виконується методом POST /api/v1/shifts/close. Скрипт надсилає запит, Checkbox підраховує підсумки реалізації за день, формує Z-звіт, підписує його цифровим підписом і відправляє на сервер податкової служби. Одночасно створюються періодичні звіти та оновлюються залишки готівки.
Для повної автономності магазину закриття зміни налаштовується через системний планувальник завдань cron щовечора о 23:50 за київським часом. Якщо протягом дня замовлень не було і зміна не відкривалася, скрипт перевіряє стан і нічого не робить.
Фоновий обробник фіскалізації на Python
Нижче наведено робочий приклад скрипта на Python, який можна запускати у воркері черги. Скрипт отримує дані оплаченого замовлення, виконує авторизацію, відкриває зміну за потреби та створює фіскальний чек:
import json
import uuid
import urllib.request as request
import urllib.error as error
CHECKBOX_BASE_URL = "https://api.checkbox.ua/api/v1"
class CheckboxFiscalizer:
def __init__(self, license_key: str, pin_code: str, client_name: str = "ShopWorker"):
self.license_key = license_key
self.pin_code = pin_code
self.client_name = client_name
self.token = None
def _headers(self, with_auth: bool = True) -> dict:
headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"X-Client-Name": self.client_name,
"X-Client-Version": "1.0.0",
"X-License-Key": self.license_key,
}
if with_auth and self.token:
headers["Authorization"] = f"Bearer {self.token}"
return headers
def authenticate(self) -> bool:
url = f"{CHECKBOX_BASE_URL}/cashier/signinPinCode"
payload = json.dumps({"pin_code": self.pin_code}).encode("utf-8")
req = request.Request(url, data=payload, headers=self._headers(with_auth=False), method="POST")
try:
with request.urlopen(req, timeout=15) as res:
data = json.loads(res.read().decode("utf-8"))
self.token = data.get("access_token")
return bool(self.token)
except error.HTTPError as e:
return False
def ensure_shift_open(self) -> bool:
shift_url = f"{CHECKBOX_BASE_URL}/cashier/shift"
req = request.Request(shift_url, headers=self._headers(), method="GET")
try:
with request.urlopen(req, timeout=15) as res:
shift_data = json.loads(res.read().decode("utf-8"))
if shift_data and shift_data.get("status") == "OPENED":
return True
except error.HTTPError:
pass
open_url = f"{CHECKBOX_BASE_URL}/shifts"
open_req = request.Request(open_url, headers=self._headers(), method="POST")
try:
with request.urlopen(open_req, timeout=15) as res:
return res.status in (200, 202)
except error.HTTPError:
return False
def create_receipt(self, order_id: str, items: list, total_kopecks: int, email: str) -> dict:
if not self.token and not self.authenticate():
raise RuntimeError("Authentication failed")
if not self.ensure_shift_open():
raise RuntimeError("Could not open cashier shift")
goods = []
for it in items:
goods.append({
"good": {
"code": it["sku"],
"name": it["name"],
"price": it["price_kopecks"],
"uktzed": it.get("uktzed", "")
},
"quantity": it["quantity"] * 1000
})
payload = {
"id": str(uuid.uuid4()),
"order_id": order_id,
"goods": goods,
"payments": [{
"type": "CASHLESS",
"value": total_kopecks,
"label": "Online Card"
}],
"delivery": {"email": email}
}
body = json.dumps(payload).encode("utf-8")
req = request.Request(f"{CHECKBOX_BASE_URL}/receipts/sell", data=body, headers=self._headers(), method="POST")
with request.urlopen(req, timeout=20) as res:
return json.loads(res.read().decode("utf-8"))
Цей клас легко підключається як сервіс у Laravel, плагін для WooCommerce чи OpenCart або окремий модуль n8n. Скрипт бере на себе перевірку стану зміни, безпечну повторну спробу авторизації та передачу параметрів.
Якщо у вас кастомний сайт або потрібна інтеграція специфічних бізнес-процесів, ми розробляємо кастомні модулі автоматизації під ключ. Вартість розробки кастомного модуля в нашому прайсі починається від $80, а налаштування автоматизації на базі n8n від $500.
Порівняння ручної та автоматичної фіскалізації
| Параметр | Ручна фіскалізація | Автоматична через API |
|---|---|---|
| Час обробки замовлення | 2-3 хвилини роботи менеджера | Миттєво у фоновому режимі (до 2 секунд) |
| Нічні та святкові замовлення | Очікують робочого дня (ризик прострочення) | Фіскалізуються одразу після оплати |
| Контроль відкриття та закриття зміни | Залежить від уважності співробітника | Автоматичний cron-скрипт о 23:50 щодня |
| Помилки в сумах та кодах УКТ ЗЕД | Висока ймовірність механічної помилки | Помилки виключені, дані йдуть з каталогу |
| Вартість доставки чека клієнту | Витрати на SMS або ручний друк на папері | Безкоштовно на email та в месенджери |
| Ризик податкових штрафів | Високий (100% або 150% від суми продажу) | Зведений до нуля завдяки логуванню |
Обробка повернень коштів
Коли покупець повертає товар або скасовує замовлення до відправки, бухгалтер зобов'язаний сформувати видатковий чек (чек повернення). Залишити кошти повернутими без фіскального відображення не можна. Це порушує звітність за касою.
У Checkbox повернення оформлюється через той самий метод POST /api/v1/receipts/sell, але з додатковими параметрами. У тілі запиту передається параметр related_receipt_id з ідентифікатором оригінального чека продажу і прапорець повернення. Грошова сума повертається покупцеві тим же безготівковим способом через платіжний шлюз, а Checkbox реєструє від'ємний баланс у денному звіті.
Типові помилки при інтеграції ПРРО
- Синхронний виклик API під час оформлення замовлення. Найбільш часта помилка розробників-початківців. Якщо сайт очікує відповіді від податкової під час перенаправлення покупця, швидкість чекауту падає, а клієнт бачить порожній екран. Фіскалізація завжди має йти в черзі.
- Відсутність перевірки стану зміни перед чеком. Якщо спробувати надіслати чек на закриту касу, API поверне помилку. Логіка повинна спочатку перевіряти стан і відкривати зміну.
- Розбіжність копійок через математичне округлення. При застосуванні промокодів або знижок на кошик сума рядків товарів може відрізнятися від суми платежу на одну копійку. Перевіряйте збіг сум перед відправкою, інакше Checkbox відхилить чек.
- Відсутність збереження ідентифікатора чека в базі сайту. Якщо не зберігати фіскальний номер, податковий код і посилання на чек у замовленні, менеджеру доведеться вручну шукати чек у кабінеті при кожному зверненні клієнта.
- Ігнорування повторних вебхуків від платіжних систем. Банки надсилають повторні запити, якщо сервер не відповів статусом 200 за кілька секунд. Без перевірки ідентифікатора замовлення магазин може вибити два чеки на одну оплату. Про надійну обробку повідомлень від платіжних систем читайте в нашій статті про воронку чекауту і втрати платежів, а про платіжні модулі у матеріалі про інтеграцію WooCommerce, LiqPay і monobank.
Часті запитання
Чи потрібен окремий касовий апарат для роботи з Checkbox?
Ні. Checkbox є програмним РРО. Він працює повністю у хмарі на серверах провайдера. Фізичне обладнання не потрібне, а всі підписи накладаються за допомогою хмарного цифрового підпису.
Що робити, якщо податковий сервер не працює або завис?
Checkbox підтримує режим офлайн. Якщо зв'язок з сервером ДПС тимчасово зникає, каса продовжує реєструвати чеки з локальними фіскальними номерами з попередньо завантаженого діапазону. Після відновлення зв'язку всі чеки автоматично передаються в податкову.
Як передавати код УКТ ЗЕД для товарів?
У каталозі магазину створюється окреме поле або атрибут товару, наприклад uktzed. При формуванні запиту на чек значення поля додається в об'єкт товару good.uktzed. Для товарів без обов'язкового коду поле залишається порожнім.
Чи треба видавати чек при оплаті накладеним платежем у Новій Пошті?
При класичному накладеному платежі розрахункову операцію готівкою чи карткою проводить фінансова компанія Нової Пошти (NovaPay). Вона видає покупцеві свій фіскальний чек у відділенні. Магазин у цьому випадку чек видавати не повинен, якщо відправляє товар без передплати.
Налаштуємо автоматичну фіскалізацію для вашого магазину
Ми підключаємо ПРРО Checkbox до інтернет-магазинів на WooCommerce, OpenCart, кастомному Laravel або налаштовуємо готові сценарії автоматизації через n8n. Ваша каса працюватиме автономно 24/7 без ручної праці менеджерів та ризику штрафів. Детальніше про інтеграцію та управління замовленнями дивіться в розділі розробка інтернет-магазинів. Також читайте наш кейс про автоматичну звірку платежів через n8n.
Повний прайс-лист доступний на сторінці цін на послуги. Щоб обговорити інтеграцію вашого сайту, надішліть заявку через форму контактів або напишіть нам напряму в Telegram.