# PRRO.cloud — Документація API > REST API сервісу PRRO.cloud: реєстрація чеків, керування змінами, білінг і вебхуки. Джерело правди — специфікація OpenAPI 3.1; цю сторінку згенеровано з неї під час збірки, тож довідник не розходиться з контрактом. Базова адреса: `https://app.prro.cloud` (OpenAPI v0.2.1). Усі шляхи на цій сторінці — відносні до базової адреси. Тіла запитів і відповідей — JSON (`application/json`), кодування UTF-8. ## Автентифікація Машинні запити автентифікуються довгоживучим Bearer-токеном (JWT). Випустіть його в кабінеті PRRO.cloud у розділі токенів — значення показується **рівно один раз**, збережіть його одразу. Токен передається в заголовку `Authorization: Bearer `; відкликання в кабінеті набирає чинності на всіх репліках протягом ~2 секунд. Перевірити токен можна запитом: ```sh curl -H "Authorization: Bearer $PRRO_TOKEN" \ "$BASE_URL/api/v1/whoami" ``` ## Швидкий старт Разовий виклик, щоб узяти id каси, і три запити фіскального циклу — перший чек зареєстровано. На касі в режимі `TEST` цей цикл безкоштовний і не потребує реєстрації в податковій. 1. **Візьміть id каси.** Токен показує ті каси, на які він діє. `id` з відповіді — те саме значення, що далі йде у `cash_register_id` чека і в шляхи `/cash-registers/{id}`; фіскальний номер для цього не годиться. Виклик разовий — збережіть id у налаштуваннях інтеграції. ```sh curl -H "Authorization: Bearer $PRRO_TOKEN" \ "$BASE_URL/api/v1/cash-registers" ``` 2. **Відкрийте зміну.** Якщо каса не в режимі `shift_mode: manual`, цей крок можна пропустити — перший чек відкриє зміну сам. ```sh curl -X POST "$BASE_URL/api/v1/cash-registers/$REGISTER_ID/shifts" \ -H "Authorization: Bearer $PRRO_TOKEN" \ -H "Idempotency-Key: shift-2026-07-14" \ -H "Content-Type: application/json" \ -d '{"cashier": "Каса самообслуговування"}' ``` 3. **Зареєструйте чек.** Суми — десяткові рядки, а не числа. У синхронному режимі (за замовчуванням) фіскальний номер — одразу у відповіді, а поруч із ним — посилання на чек для покупця. ```sh curl -X POST "$BASE_URL/api/v1/receipts" \ -H "Authorization: Bearer $PRRO_TOKEN" \ -H "Idempotency-Key: order-10412" \ -H "Content-Type: application/json" \ -d '{ "cash_register_id": "'$REGISTER_ID'", "type": "sale", "items": [ { "name": "Кава американо", "quantity": "1", "price": "65.00", "tax_letters": "А" } ], "payments": [ { "type": "card", "sum": "65.00" } ] }' ``` 4. **Закрийте день.** Z-звіт і закриття зміни — одна операція (або налаштуйте `shift_close_times` на касі, і день закриватиметься сам). ```sh curl -X DELETE "$BASE_URL/api/v1/cash-registers/$REGISTER_ID/shifts/current" \ -H "Authorization: Bearer $PRRO_TOKEN" \ -H "Idempotency-Key: close-2026-07-14" ``` ## Ключові механіки - **Ідемпотентність.** Заголовок `Idempotency-Key` обовʼязковий для всіх фіскальних операцій. Повтор запиту з тим самим ключем повертає оригінальну задачу, а не другий чек — мережеві збої та ретраї безпечні. Той самий ключ з іншою операцією — `409`. - **Sync та async.** За замовчуванням запит тримає зʼєднання до відповіді ДПС (до 30 с); якщо не встигли — `202` із задачею для опитування. `mode=async` повертає `202` одразу, а результат приходить через `GET /api/v1/tasks/{id}` та/або вебхук. - **Гроші — рядки.** Усі суми — десяткові рядки (`"259.90"`), ніколи не float. Кількість — до 3 знаків після коми, ціни — до 2. - **Помилки.** Єдиний конверт `{code, message, details}`: `code` — машинний код для обробки, `message` — людський текст. `422` — помилка валідації або відхилення операції (немає відкритої зміни, відмова ДПС). - **Баланс.** Сервіс передплатний: коли баланс перетинає мʼякий ліміт, нові чеки відповідають `402`, доки баланс не поповнено. Операції зі змінами при цьому доступні. ## Чек для покупця Відповідь на фіскалізацію несе не лише фіскальний номер: у `result.receipt` поруч із ним лежать два посилання — наша копія чека і той самий документ у кабінеті ДПС. Це все, що потрібно надіслати покупцеві листом чи в месенджер або показати QR-кодом на екрані каси — рендерити чек самотужки не треба. ```json { "task_id": "0197a2c1-…", "type": "receipt", "status": "succeeded", "result": { "receipt": { "document_id": "0197a2c3-…", "local_number": 42, "fiscal_number": "7466800082", "receipt_url": "https://r.prro.cloud/aB3xK9pQvT2mNr7c", "tax_url": "https://cabinet.tax.gov.ua/cashregs/check?fn=4001063533&id=7466800082&date=20260803&time=010754&sm=65.00" } } } ``` - **`receipt_url` — копія чека.** Сторінка відкривається **без авторизації**: 16-символьний код і є доступом, як паперовий чек у кишені. Подання обирає параметр `?format=`: `html` (типово), `text` (моноширинний чек) і `qr` (PNG з адресою цієї ж сторінки). Назовні віддається лише людиночитаний чек — ні XML, ні CMS, ні квитанції ДПС. Невідомий код і документ, який не можна показати, відповідають однаково — `404`. - **`tax_url` — незалежна перевірка.** Той самий документ у кабінеті платника податків — підтвердження, яке покупець читає, не довіряючи нам. Доказ фіскалізації — це `fiscal_number` і `tax_url`; `receipt_url` лише показує чек. - **Офлайн-чек.** У документа з `offline: true` фіскальний номер обчислено локально (`..`), тож `tax_url` зʼявиться лише після того, як пакет сесії прийме фіскальний сервер. `receipt_url` є одразу — копія віддається з нашого журналу. - **Тільки розрахункові документи.** Z-звіт, відкриття та закриття зміни друкованої форми не мають, тож посилань у їхніх `DocResult` не буде. - **Посилання не протухають.** Код зберігається разом із документом, а не перераховується, тож ротація ключів сервісу не ламає адрес, які вже в руках у покупців. Сторінку не індексують пошукові системи. ## Вебхуки Замість опитування задач підпишіться на події: зареєструйте endpoint через `POST /api/v1/webhooks` — і сервіс сам постукає у ваш бекенд. Події: `task.completed`, `task.failed`, `shift.opened`, `shift.closed`, `key.expiring`. - **Конверт доставки.** POST на ваш URL з тілом `{delivery_id, event, attempt, occurred_at, data}`; у `data` — корисне навантаження події. - **Підпис.** Заголовок `X-Signature: sha256=` — HMAC-SHA256 від тіла запиту під секретом endpoint'а. Секрет видається один раз при створенні; перевіряйте підпис перед обробкою. - **Гарантії.** Доставка at-least-once — дедуплікуйте за `delivery_id`; події однієї каси приходять по порядку. Невдалі доставки ретраяться, вичерпані потрапляють у DLQ (`status=dead`) і можуть бути повторені вручну через replay. ```http POST https://example.com/prro-hook X-Signature: sha256=2b7e9f… { "delivery_id": "0197a2c4-…", "event": "task.completed", "attempt": 1, "occurred_at": "2026-07-14T10:15:04Z", "data": { "task_id": "0197a2c1-…", "status": "succeeded" } } ``` ## Довідник ендпоінтів Згенеровано зі специфікації OpenAPI. Кабінетні ендпоінти (cookie-сесія панелі) сюди не входять — інтеграції працюють лише з машинним API. ### Сервісні #### GET /api/v1/version Версія збірки сервісу Відповіді: - `200` — Версія, зашита у збірку. Тіло: див. нижче. Тіло відповіді `200`: | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `version` | string | так | | #### GET /api/v1/whoami Дізнатися, що стоїть за наданим машинним токеном _(Bearer-токен обовʼязковий)_ Відповіді: - `200` — Клієнт, дозволи (scopes) та обмеження за касами. Тіло: див. нижче. - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). Тіло відповіді `200`: | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `client_id` | string (uuid) | так | | | `scopes` | array | так | | | `all_cash_registers` | boolean | так | true — токен діє на всі каси клієнта (поточні й майбутні); false — лише на перелічені у cash_registers. | | `cash_registers` | array | — | Присутнє лише для обмеженого токена — перелік uuid кас, до яких він прив'язаний. Відсутнє, коли all_cash_registers. | | `jti` | string (uuid) | так | | | `expires_at` | string (date-time) | — | | #### GET /system/dps Поточний режим роботи з ДПС (онлайн/офлайн) _(Bearer-токен обовʼязковий)_ Той самий знімок доступності, доступний будь-якій автентифікованій інтеграції: клієнт може показувати «ДПС офлайн» власним операторам. Відповіді: - `200` — Знімок стану доступності. Тіло: `DPSStatus` (див. «Схеми даних»). - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). ### Фіскальні операції #### POST /api/v1/receipts Зареєструвати чек (реалізація/повернення/сторно або рух готівки) _(Bearer-токен обовʼязковий)_ Реєструє або розрахунок за товари (sale/return/storno), або рух готівки повз продаж (service_in/service_out — службове внесення та службова видача, тобто інкасація). І те, й інше — документи DOCTYPE 0, які проходять однаковий шлях. Виконується повний фіскальний цикл: локальний номер, XML за check01, підпис КЕП (CAdES-T), надсилання на фіскальний сервер ДПС, квитанція. У синхронному режимі (типовому) відповідь чекає на результат до 30 секунд; якщо не вклалися — 202 і номер завдання, за яким статус опитують через GET /tasks/{id}. Режим mode=async (у query або в тілі) віддає 202 одразу, а результат приходить опитуванням та/або вебхуком. Заголовок Idempotency-Key обов'язковий: повтор із тим самим ключем поверне те саме завдання, а не зареєструє другий чек. Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `Idempotency-Key` | header | string | так | Ключ операції, який обирає клієнт. Повтор запиту з тим самим ключем поверне початкове завдання, а не виконає фіскальну операцію вдруге. | | `mode` | query | string | — | Режим доставки результату; має перевагу над однойменним полем у тілі. sync (типовий) чекає на результат у межах синхронного очікування; async одразу відповідає 202 і номером завдання, а результат приходить через GET /tasks/{id} та/або вебхуком. | Тіло запиту (application/json): `ReceiptInput` (див. «Схеми даних») Відповіді: - `200` — Повтор за тим самим Idempotency-Key; завдання вже завершене. Тіло: `Task` (див. «Схеми даних»). - `201` — Зареєстровано в межах синхронного очікування. Тіло: `Task` (див. «Схеми даних»). - `202` — Ще виконується; статус — через GET /tasks/{id}. Тіло: `Task` (див. «Схеми даних»). - `400` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `402` — Передплачений баланс опустився нижче порога: нові чеки заблоковано до поповнення. Операції зі змінами лишаються доступними — закрити зміну можна завжди. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `409` — Цей Idempotency-Key уже використано для іншої операції. Тіло: `Error` (див. «Схеми даних»). - `422` — Не пройшла валідація або завдання завершилося помилкою (немає відкритої зміни, відмова ДПС тощо). Тіло: `Error` (див. «Схеми даних»). #### GET /api/v1/tasks/{id} Статус і результат операції (опитування) _(Bearer-токен обовʼязковий)_ Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `id` | path | string (uuid) | так | | Відповіді: - `200` — Завдання в поточному стані. Тіло: `Task` (див. «Схеми даних»). - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). #### GET /api/v1/cash-registers Каси, доступні цьому токену (звідки інтегратор бере cash_register_id) _(Bearer-токен обовʼязковий)_ Перелік реєстраторів, на які діє наданий токен: повний токен бачить усі каси клієнта, обмежений — лише свої. Це разовий виклик під час налаштування інтеграції: усі інші маршрути адресують касу за її uuid, і взяти цей uuid більше ніде — фіскальний номер сторонній сервіс показує людині, а працює за id. Віддає лише те, чим касу впізнають і адресують. Поточний стан (зміна, лічильники, офлайн-бюджет) — за GET /cash-registers/{id}. Відповіді: - `200` — Каси в межах токена, від найстаріших. Тіло: див. нижче. - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). Тіло відповіді `200`: | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `cash_registers` | array | так | | #### GET /api/v1/cash-registers/{id} Стан реєстратора (зміна, режим, лічильники) _(Bearer-токен обовʼязковий)_ Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `id` | path | string (uuid) | так | | Відповіді: - `200` — Поточний стан реєстратора. Тіло: `CashRegisterState` (див. «Схеми даних»). - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). #### POST /api/v1/cash-registers/{id}/shifts Відкрити зміну (DOCTYPE 100; семантика завдання така сама, як у чеків) _(Bearer-токен обовʼязковий)_ Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `id` | path | string (uuid) | так | | | `Idempotency-Key` | header | string | так | Ключ операції, який обирає клієнт. Повтор запиту з тим самим ключем поверне початкове завдання, а не виконає фіскальну операцію вдруге. | | `mode` | query | string | — | Режим доставки результату; має перевагу над однойменним полем у тілі. sync (типовий) чекає на результат у межах синхронного очікування; async одразу відповідає 202 і номером завдання, а результат приходить через GET /tasks/{id} та/або вебхуком. | Тіло запиту (application/json, необовʼязкове): | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `cashier` | string | — | | | `mode` | string | — | Значення: sync, async. | Відповіді: - `201` — Зміну відкрито. Тіло: `Task` (див. «Схеми даних»). - `202` — Ще виконується; статус — через GET /tasks/{id}. Тіло: `Task` (див. «Схеми даних»). - `400` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `422` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). #### DELETE /api/v1/cash-registers/{id}/shifts/current Закрити поточну зміну (Z-звіт і повідомлення про закриття однією операцією) _(Bearer-токен обовʼязковий)_ Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `id` | path | string (uuid) | так | | | `Idempotency-Key` | header | string | так | Ключ операції, який обирає клієнт. Повтор запиту з тим самим ключем поверне початкове завдання, а не виконає фіскальну операцію вдруге. | | `mode` | query | string | — | Режим доставки результату; має перевагу над однойменним полем у тілі. sync (типовий) чекає на результат у межах синхронного очікування; async одразу відповідає 202 і номером завдання, а результат приходить через GET /tasks/{id} та/або вебхуком. | Відповіді: - `201` — Зміну закрито; у результаті — і Z-звіт, і документ закриття. Тіло: `Task` (див. «Схеми даних»). - `202` — Ще виконується; статус — через GET /tasks/{id}. Тіло: `Task` (див. «Схеми даних»). - `400` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `422` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). #### POST /api/v1/cash-registers/{id}/offline-session/close Примусово закрити активну офлайн-сесію (документ завершення сесії потрапляє до журналу одразу, а пакети досилаються у фоні) _(Bearer-токен обовʼязковий)_ Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `id` | path | string (uuid) | так | | | `Idempotency-Key` | header | string | так | Ключ операції, який обирає клієнт. Повтор запиту з тим самим ключем поверне початкове завдання, а не виконає фіскальну операцію вдруге. | | `mode` | query | string | — | Режим доставки результату; має перевагу над однойменним полем у тілі. sync (типовий) чекає на результат у межах синхронного очікування; async одразу відповідає 202 і номером завдання, а результат приходить через GET /tasks/{id} та/або вебхуком. | Тіло запиту (application/json, необовʼязкове): | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `cashier` | string | — | | | `mode` | string | — | Значення: sync, async. | Відповіді: - `201` — Сесію закрито; у результаті — документ завершення. Тіло: `Task` (див. «Схеми даних»). - `202` — Ще виконується; статус — через GET /tasks/{id}. Тіло: `Task` (див. «Схеми даних»). - `400` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `422` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). #### POST /api/v1/cash-registers/{id}/offline-session/retry Відновити зупинене надсилання офлайн-пакетів (сервіс зупинив сесію після повторюваних непоправних відмов — спершу усуньте причину) _(Bearer-токен обовʼязковий)_ Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `id` | path | string (uuid) | так | | Відповіді: - `200` — Скільки сесій повернуто до надсилання. Тіло: див. нижче. - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). Тіло відповіді `200`: | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `resumed_sessions` | integer | так | | #### DELETE /api/v1/cash-registers/{id}/attention Зняти позначку «потребує уваги» з реєстратора _(Bearer-токен обовʼязковий)_ Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `id` | path | string (uuid) | так | | Відповіді: - `200` — Чи справді було знято позначку. Тіло: див. нижче. - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). Тіло відповіді `200`: | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `cleared` | boolean | так | | #### PUT /api/v1/cash-registers/{id}/cash-balance Заявити, скільки готівки насправді в касі _(Bearer-токен обовʼязковий)_ Переставляє лічильник готівки на перераховану суму. Це те, що потрібно реєстратору, який приєднується до сервісу з непорожньою касою: лічильник стартує з нуля і не має звідки дізнатися початкову суму. Так само виправляють лічильник, який розійшовся з касою. Нічого фіскального не відбувається: заявлений залишок не потрапляє в жоден документ і не змінює підсумків зміни. Щоб зареєструвати готівку, яка справді рухається, надсилайте чек service_in або service_out. Заявлений залишок не може бути від'ємним — на відміну від самого лічильника, який чесно йде в мінус, коли зустрічає гроші, приходу яких не бачив. Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `id` | path | string (uuid) | так | | Тіло запиту (application/json): | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `amount` | CashAmount | так | Перерахований залишок; не може бути від'ємним. | Відповіді: - `200` — Лічильник після заяви. Тіло: `CashBalanceDeclaration` (див. «Схеми даних»). - `400` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `422` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). ### Білінг #### GET /api/v1/billing/usage Передплачений баланс і підсумок тарифікації за період _(Bearer-токен обовʼязковий)_ Суми — копійки десятковим рядком, ніколи не числа з рухомою комою. Типовий період — поточний календарний місяць за UTC; межа `to` не включається. Чеки тарифікуються асинхронно після реєстрації, тож підсумок може відставати від останнього чека на кілька секунд. Період не може перевищувати 366 днів — ширший діапазон дає 422. Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `from` | query | string (date) | — | | | `to` | query | string (date) | — | | Відповіді: - `200` — Баланс і використання за період. Тіло: `BillingUsage` (див. «Схеми даних»). - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `422` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). #### GET /api/v1/invoices Рахунки клієнта, від найновішого періоду _(Bearer-токен обовʼязковий)_ Рахунок — це підсумок одного розрахункового періоду, а не окремий платіж: на клієнта припадає один рядок за період, тож типова сторінка у 50 рахунків покриває роки щомісячної тарифікації. Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `limit` | query | integer | — | | | `offset` | query | integer | — | | Відповіді: - `200` — Рахунки клієнта. Тіло: див. нижче. - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `422` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). Тіло відповіді `200`: | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `invoices` | array | так | | ### Вебхуки #### GET /api/v1/webhooks Перелік вебхуків клієнта (без секретів) _(Bearer-токен обовʼязковий)_ Відповіді: - `200` — Точки доставки клієнта. Тіло: див. нижче. - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). Тіло відповіді `200`: | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `webhooks` | array | так | | #### POST /api/v1/webhooks Зареєструвати вебхук (секрет HMAC показують рівно один раз) _(Bearer-токен обовʼязковий)_ Доставка — це POST з тілом {delivery_id, event, attempt, occurred_at, data} і заголовком X-Signature вигляду "sha256=", порахованим на секреті цієї точки доставки. Гарантія — «щонайменше один раз»: приймач має відкидати повтори за delivery_id. Події одного реєстратора приходять по порядку. Якщо secret не вказати, його згенерує сервер і поверне лише у цій відповіді. Тіло запиту (application/json): | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `url` | string | так | Абсолютний http(s)-URL приймача. | | `events` | array | — | Події, на які підписані; порожній список або відсутнє поле означає всі події. Значення: task.completed, task.failed, shift.opened, shift.closed, key.expiring, register.offline, register.online, register.offline_limit, register.remediated, register.needs_attention. | | `secret` | string | — | Секрет HMAC; якщо не вказати, згенерує сервер. | Відповіді: - `201` — Створено; секрет повертається рівно один раз. Тіло: див. нижче. - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `422` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). Тіло відповіді `201`: | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `id` | string (uuid) | так | | | `url` | string | так | | | `events` | array | так | Порожній список означає підписку на всі події. Значення: task.completed, task.failed, shift.opened, shift.closed, key.expiring, register.offline, register.online, register.offline_limit, register.remediated, register.needs_attention. | | `active` | boolean | так | | | `created_at` | string (date-time) | так | | | `updated_at` | string (date-time) | так | | | `secret` | string | так | Отримати повторно неможливо. | #### PATCH /api/v1/webhooks/{id} Змінити URL, підписку або ознаку активності (часткове оновлення) _(Bearer-токен обовʼязковий)_ Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `id` | path | string (uuid) | так | | Тіло запиту (application/json): | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `url` | string | — | | | `events` | array | — | Значення: task.completed, task.failed, shift.opened, shift.closed, key.expiring, register.offline, register.online, register.offline_limit, register.remediated, register.needs_attention. | | `active` | boolean | — | false призупиняє доставку, не втрачаючи черги. | Відповіді: - `200` — Оновлено. Тіло: `WebhookEndpoint` (див. «Схеми даних»). - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `422` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). #### DELETE /api/v1/webhooks/{id} Видалити точку доставки (недоставлену чергу буде відкладено) _(Bearer-токен обовʼязковий)_ Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `id` | path | string (uuid) | так | | Відповіді: - `204` — Видалено. - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). #### GET /api/v1/webhooks/{id}/deliveries Історія доставок, від найновішої (status=dead — черга невдалих) _(Bearer-токен обовʼязковий)_ Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `id` | path | string (uuid) | так | | | `status` | query | string | — | | | `limit` | query | integer | — | | Відповіді: - `200` — Доставки. Тіло: див. нижче. - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `422` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). Тіло відповіді `200`: | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `deliveries` | array | так | | #### POST /api/v1/webhooks/{id}/deliveries/{deliveryId}/replay Повернути доставку в чергу з новим запасом спроб (зазвичай — невдалу) _(Bearer-токен обовʼязковий)_ Параметри: | Параметр | Де | Тип | Обовʼязковий | Опис | |---|---|---|---|---| | `id` | path | string (uuid) | так | | | `deliveryId` | path | string (uuid) | так | | Відповіді: - `200` — Повернуто в чергу; пізніші події того самого реєстратора зачекають на неї — порядок зберігається й після повтору. Тіло: `WebhookDelivery` (див. «Схеми даних»). - `401` — Немає облікових даних, або вони недійсні, протерміновані чи відкликані. Тіло: `Error` (див. «Схеми даних»). - `404` — Конверт помилки. Тіло: `Error` (див. «Схеми даних»). - `409` — Саме зараз триває спроба доставки. Тіло: `Error` (див. «Схеми даних»). ## Схеми даних Обʼєкти, на які посилаються ендпоінти довідника. Обовʼязкові поля позначено «так». ### Error (object) | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `code` | string | так | | | `message` | string | так | | | `details` | any | — | | ### CashRegisterState (object) | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `id` | string (uuid) | так | | | `fiscal_number` | string | так | | | `local_number` | string | так | | | `mode` | string | так | Значення: production, test. | | `state` | string | так | Значення: closed, opened, offline. | | `offline_ready` | boolean | — | Чи має реєстратор видані ДПС офлайн-реквізити (приходять із квитанцією на відкриття зміни). | | `shift_mode` | ShiftMode | — | Як керують змінами реєстратора. `manual` — клієнт відкриває і закриває їх через API, автоматично не відбувається нічого. `round_the_clock` — реєстратор не припиняє продавати: зміна закривається в кожен із shift_close_times, а наступний чек відкриває нову. `working_hours` — денне вікно, задане двома межами у shift_close_times. В обох керованих режимах зміну відкриває перший же чек, тож жоден продаж не втрачається через закритий реєстратор. | | `shift_close_times` | ShiftCloseTimes | — | Час щоденного закриття зміни за київським часом. Порожній рівно тоді, коли shift_mode — `manual`. Часи прив'язані до годинника, тож реєстратор, який відкрився за секунду після закриття, все одно закриється в той самий час, що й щодня, а не поповзе. Потрібно щонайменше два значення з проміжком не більше 18 годин (рахуючи через опівніч): зміна триває стільки, скільки лишилося до наступного закриття, а решта законодавчої доби — це єдиний запас, у якому можна повторити невдале закриття. `working_hours` містить рівно два — початок і кінець дня, саме в цьому порядку, щоб вікно через опівніч ("08:00", потім "02:00") зберігало напрямок. Обидва є точками закриття: денна зміна завершується в кінці вікна, а чек, що прийшов у неробочий час, усе одно відкриє зміну (у продажу ніколи не відмовляють), і вона закриється з початком наступного дня. `round_the_clock` приймає два або більше значень за зростанням. | | `cash_balance` | CashBalance | — | Скільки готівки в касі реєстратора. Це лічильник, а не налаштування і не фіскальна величина: він стартує з нуля при створенні реєстратора і бачить лише ті документи, що пройшли через цей сервіс. Рухають його готівкові рядки оплат — додають на реалізації, віднімають на поверненні та сторно — і службові документи. Картка не рухає нічого: через касу фізично нічого не проходить. Решта вже врахована, бо береться `sum` рядка оплати, а не `provided`. Лічильник живе на реєстраторі, а не на зміні, бо готівка переживає Z-звіт: торговельний автомат закривається двічі на добу і тримає свої монети, доки по них не приїдуть. Значення **може бути від'ємним**, і ніщо цьому не заважає. Гроші лежали в касі ще до того, як сервіс побачив бодай один документ, тож перша інкасація цих грошей — цілком законна операція. Від'ємне значення саме по собі корисний сигнал: у касі було більше, ніж ми знали. Щоб переставити лічильник на справжню суму, скористайтеся PUT .../cash-balance. | | `current_shift` | object | — | | | `current_shift.id` | string (uuid) | — | | | `current_shift.number` | integer (int64) | — | Наскрізний номер зміни в межах каси («Зміна №147»). Присвоюється локально: ДПС номера зміни не видає. | | `current_shift.status` | string | — | Значення: opening, opened, closing, closed. | | `current_shift.testing` | boolean | — | | | `current_shift.opened_at` | string (date-time) | — | | | `current_shift.documents` | integer | — | Скільки документів створила зміна — усіх видів, а не лише розрахункових, які рахують підсумки: сповіщення про відкриття, чеки, рухи готівки. Відсутнє, якщо порахувати не вдалося (нуля, якого в зміні немає, тут не буває). | | `shift_totals` | ShiftTotals | — | Поточні підсумки відкритої зміни — те саме накопичення, з якого потім буде побудований Z-звіт. Сервіс складає його чек за чеком у тій самій транзакції, що реєструє документ, тож розійтися з журналом він не може. Сторно віднімається з боку реалізації, а не додається до повернень. Службові внесення й видачі не належать до жодного боку — ДПС тримає їх в окремих полях, і Z-звіт робить так само. Розклад за податковими літерами тут не віддається навмисно: він найширша частина підсумків і належить Z-звіту, а цей об'єкт їде у відповіді про стан, яку панель опитує кожні кілька секунд. | | `offline_session` | object | — | Присутня, поки реєстратор працює офлайн. | | `offline_session.id` | string (uuid) | — | | | `offline_session.dps_session_id` | integer (int64) | — | | | `offline_session.started_at` | string (date-time) | — | | | `offline_session.documents` | integer (int64) | — | | | `offline_session.last_significant_at` | string (date-time) | — | | | `offline_limits` | object | так | Законодавчі межі офлайн-роботи в секундах: 36 годин на одну сесію і 168 годин на календарний місяць. Скільки лишилося в сесії, рахують від offline_session.started_at, а скільки лишилося на місяць — від offline_month_used_seconds. | | `offline_limits.session_seconds` | integer (int64) | так | | | `offline_limits.month_seconds` | integer (int64) | так | | | `offline_month_used_seconds` | integer (int64) | — | Час, відпрацьований офлайн у цьому календарному місяці (за київським часом). | | `attention` | object | — | Присутня, коли сервіс позначив реєстратор як такий, що потребує уваги (див. CashRegister.attention_reason). Знімається через DELETE .../attention; якщо зупинилося надсилання офлайн-пакетів, його додатково відновлюють через POST .../offline-session/retry. | | `attention.reason` | string | так | Значення: recurring_remediation, offline_submission_paused, auto_close_failing. | | `attention.since` | string (date-time) | — | | ### ShiftMode (string) Як керують змінами реєстратора. `manual` — клієнт відкриває і закриває їх через API, автоматично не відбувається нічого. `round_the_clock` — реєстратор не припиняє продавати: зміна закривається в кожен із shift_close_times, а наступний чек відкриває нову. `working_hours` — денне вікно, задане двома межами у shift_close_times. В обох керованих режимах зміну відкриває перший же чек, тож жоден продаж не втрачається через закритий реєстратор. Значення: `manual`, `round_the_clock`, `working_hours`. ### ShiftCloseTimes (array) Час щоденного закриття зміни за київським часом. Порожній рівно тоді, коли shift_mode — `manual`. Часи прив'язані до годинника, тож реєстратор, який відкрився за секунду після закриття, все одно закриється в той самий час, що й щодня, а не поповзе. Потрібно щонайменше два значення з проміжком не більше 18 годин (рахуючи через опівніч): зміна триває стільки, скільки лишилося до наступного закриття, а решта законодавчої доби — це єдиний запас, у якому можна повторити невдале закриття. `working_hours` містить рівно два — початок і кінець дня, саме в цьому порядку, щоб вікно через опівніч ("08:00", потім "02:00") зберігало напрямок. Обидва є точками закриття: денна зміна завершується в кінці вікна, а чек, що прийшов у неробочий час, усе одно відкриє зміну (у продажу ніколи не відмовляють), і вона закриється з початком наступного дня. `round_the_clock` приймає два або більше значень за зростанням. ### CashRegisterListItem (object) Каса так, як її показує перелік токена: чим її впізнає людина (фіскальний і локальний номер, точка) і чим її адресує машина (id). | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `id` | string (uuid) | так | Ідентифікатор каси в цьому API — те саме значення, що йде в cash_register_id чека і в {id} решти маршрутів. | | `fiscal_number` | string | так | | | `local_number` | string | так | CASHDESKNUM: власний номер каси у клієнта. | | `org_name` | string | — | | | `point_name` | string | — | | | `point_address` | string | — | | | `mode` | string | так | Значення: production, test. | | `state` | string | так | Значення: closed, opened, offline. | ### Task (object) | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `task_id` | string (uuid) | так | | | `type` | string | так | Значення: receipt, open_shift, close_shift, close_offline_session, verify_key, sync_register, dps_objects. | | `status` | string | так | Значення: pending, processing, succeeded, failed. | | `created_at` | string (date-time) | так | | | `finished_at` | string (date-time) | — | | | `error` | string | — | | | `fault` | Fault | — | Структурований опис збою завдання: стабільний код із простором імен (dps.* — відмовив фіскальний сервер; fiscal.* — валідація документа; signer.* — рівень КЕП; state.* — стан реєстратора), клас реакції, параметри для підстановки, повідомлення мовою з Accept-Language (типово українською), дослівний текст ДПС і автоматичні виправлення, застосовані до завершення завдання. | | `result` | TaskResult | — | Результати фіскальних операцій (prro_id/shift_id/testing/*) стосуються завдань на чек, зміну та офлайн-сесію; key_verification — єдиний результат завдання verify_key, решти полів у ньому немає. | ### Fault (object) Структурований опис збою завдання: стабільний код із простором імен (dps.* — відмовив фіскальний сервер; fiscal.* — валідація документа; signer.* — рівень КЕП; state.* — стан реєстратора), клас реакції, параметри для підстановки, повідомлення мовою з Accept-Language (типово українською), дослівний текст ДПС і автоматичні виправлення, застосовані до завершення завдання. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `code` | string | так | Стабільний ідентифікатор, напр. dps.check_local_number_invalid. | | `class` | string | так | Значення: resync, config, precursor, user_action, transient, request, internal. | | `params` | object | — | | | `message` | string | — | Текст для людини, локалізований із каталогу помилок. | | `upstream_message` | string | — | Дослівне повідомлення фіскального сервера. | | `remediation` | array | — | Автоматичні виправлення, застосовані під час обробки завдання. Значення: local_number_synced, shift_adopted, shift_abandoned, zreport_recovered, register_config_filled. | ### TaskResult (object) Результати фіскальних операцій (prro_id/shift_id/testing/*) стосуються завдань на чек, зміну та офлайн-сесію; key_verification — єдиний результат завдання verify_key, решти полів у ньому немає. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `prro_id` | string (uuid) | — | | | `shift_id` | string (uuid) | — | | | `shift_number` | integer (int64) | — | Наскрізний номер зміни в межах каси. Присвоюється локально: ДПС номера зміни не видає (у квитанції такого поля немає). | | `testing` | boolean | — | | | `receipt` | DocResult | — | | | `shift_open` | DocResult | — | | | `zreport` | DocResult | — | | | `shift_close` | DocResult | — | | | `offline_end` | DocResult | — | | | `key_verification` | KeyVerificationResult | — | | | `key_password_check` | KeyPasswordCheckResult | — | Наслідок швидкої локальної перевірки пароля контейнера (TaskVerifyPassword), яку кабінет проганяє синхронно під час завантаження ключа: контейнер лише розшифровується, без CMP і без мережі, щоб хибний пароль повертався формі за мілісекунди, а не аж після повної асинхронної перевірки. Завдання ВВАЖАЄТЬСЯ УСПІШНИМ у тому числі при ok=false — воно дійшло до вердикту. Інфраструктурні збої (БД, KEK, слот підпису) вердиктом не є: там завдання повторюється. | | `reconcile` | ReconcileReport | — | Підсумок звіряння реєстратора з ДПС (sync_register): який стан побачили на боці сервера і що виправили в себе. | | `dps_objects` | array | — | | ### ReconcileReport (object) Підсумок звіряння реєстратора з ДПС (sync_register): який стан побачили на боці сервера і що виправили в себе. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `fiscal_number` | string | так | | | `dps_shift_opened` | boolean | так | | | `dps_next_local_number` | integer (int64) | так | | | `dps_testing` | boolean | — | | | `counter_old` | integer (int64) | — | | | `counter_new` | integer (int64) | — | | | `shift_adopted` | boolean | — | | | `shift_abandoned` | boolean | — | | | `cash` | object | — | Звіряння каси. Присутнє лише тоді, коли на сервері справді триває зміна: скільки готівки ця зміна зрушила за нашим підрахунком — поруч із тією самою величиною, виведеною з підсумків зміни на боці ДПС. Це довідка, за нею нічого не виправляється автоматично. Показник ДПС охоплює одну зміну, а cash_balance — усе життя реєстратора, і розбіжність не каже, чия сторона помиляється: документ, який на цьому ПРРО зареєструвало інше програмне забезпечення, тут невидимий, а там порахований. Вирішує людина. | | `cash.ours` | CashAmount | так | Гривні з копійками десятковим рядком — у тій самій формі, що й суми в чеках. На відміну від Money, який рахує копійки і належить тарифікації. | | `cash.dps` | CashAmount | так | Гривні з копійками десятковим рядком — у тій самій формі, що й суми в чеках. На відміну від Money, який рахує копійки і належить тарифікації. | | `cash.match` | boolean | так | | | `skipped` | string | — | Чому нічого не чіпали (офлайн-сесію звіряння не торкається). Значення: offline_session. | ### DPSTaxObject (object) Одна господарська одиниця власника ключа (dps_objects). | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `name` | string | так | | | `address` | string | — | | | `tin` | string | так | | | `ipn` | string | — | | | `org_name` | string | так | | | `registrars` | array | так | | ### DPSRegistrar (object) Один ПРРО, зареєстрований за господарською одиницею. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `fiscal_number` | string | так | | | `local_number` | string | так | | | `name` | string | — | | | `closed` | boolean | — | | ### KeyPasswordCheckResult (object) Наслідок швидкої локальної перевірки пароля контейнера (TaskVerifyPassword), яку кабінет проганяє синхронно під час завантаження ключа: контейнер лише розшифровується, без CMP і без мережі, щоб хибний пароль повертався формі за мілісекунди, а не аж після повної асинхронної перевірки. Завдання ВВАЖАЄТЬСЯ УСПІШНИМ у тому числі при ok=false — воно дійшло до вердикту. Інфраструктурні збої (БД, KEK, слот підпису) вердиктом не є: там завдання повторюється. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `signing_key_id` | string (uuid) | так | | | `ok` | boolean | так | | | `verify_code` | string | — | Присутній завжди при ok=false (напр. wrong_password). | | `verify_error` | string | — | | ### KeyVerificationResult (object) | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `signing_key_id` | string (uuid) | так | Вказує, який ключ перевіряли. Якщо deleted істинне, цей ідентифікатор більше ні на що не вказує — запис видалено. | | `status` | string | так | Значення: active, invalid. | | `verify_code` | string | — | Значення: wrong_password, cert_not_found, cert_expired, not_prro, verify_failed, ca_unreachable. | | `verify_error` | string | — | | | `key_type` | string | — | Значення: individual, legal. | | `prro_capable` | boolean | так | | | `cert_subject` | string | — | | | `org_name` | string | — | Назва організації (або ім'я особи) власника з сертифіката. | | `edrpou` | string | — | ЄДРПОУ юридичної особи з сертифіката, лише цифри. | | `drfo` | string | — | РНОКПП (ДРФО) фізичної особи з сертифіката, лише цифри. | | `deleted` | boolean | — | Запис ключа остаточно видалено (так відбувається при будь-якому відхиленні, крім not_prro): недійсний ключ у базі не лишається. | ### DocResult (object) | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `document_id` | string (uuid) | так | | | `local_number` | integer | так | | | `fiscal_number` | string | так | Присвоєний фіскальним сервером ДПС. | | `offline` | boolean | — | Документ підписано в межах офлайн-сесії. Його фіскальний номер обчислено локально (..), і на фіскальному сервері він з'явиться лише після надсилання пакета сесії. | | `receipt_url` | string (uri) | — | Копія чека для покупця на короткому домені сервісу (https://r.prro.cloud/<код>) — те, що інтеграція пересилає листом або перетворює на QR. Сторінка відкривається без авторизації: код і є доступом, як паперовий чек у кишені. Формат обирає параметр запиту: ?format=html (типово), text або qr (PNG із адресою цієї ж сторінки). Це подання чека, а не доказ фіскалізації: доказ — fiscal_number і посилання tax_url поруч із ним. Присутнє лише в розрахункових документів: тільки вони мають друковану форму. | | `tax_url` | string (uri) | — | Той самий документ у кабінеті платника податків — незалежне підтвердження, яке читач перевіряє, не довіряючи нам. Відсутнє, доки документ не потрапив на фіскальний сервер: у офлайн-чека до надсилання пакета сесії є лише локально обчислений номер, і посилання за ним нічого не знайде. | ### ReceiptInput (oneOf) Чек буває двох форм, які розрізняє поле `type`. Розрахунок за товари несе позиції та оплати; рух готівки — лише суму, і більше нічого. Сам документ саме такий тонкий: заголовок і CHECKTOTAL/SUM. Поля чужої форми не ігноруються, а відхиляються з 422. Службовий документ, зібраний із позиціями, був би цілком дійсним чеком, який мовчки викинув ці позиції, — тому сервіс радше відмовить, ніж зареєструє не те, що ви мали на увазі. Одна з форм: `SettlementReceiptInput`, `ServiceReceiptInput` (розрізняє поле `type`). ### SettlementReceiptInput (object) Розрахунок за товари — реалізація, повернення або сторно. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `cash_register_id` | string (uuid) | — | Реєстратор. Обов'язковий для POST /api/v1/receipts, де тіло — вся адреса запиту. Кабінетний маршрут бере реєстратор з URL: там поле або відсутнє, або збігається з ним, інакше 422. | | `type` | string | так | Значення: sale, return, storno. | | `cashier` | string | — | | | `comment` | string | — | Вільна примітка, яку друкують на самому документі (CHECKHEAD/COMMENT) — наприклад номер замовлення. | | `mode` | string | — | Режим доставки результату; параметр запиту ?mode= має перевагу над цим полем. Значення: sync, async. | | `original` | object | — | Зв'язок із початковим чеком; обов'язковий для повернення та сторно. | | `original.fiscal_number` | string | так | | | `original.register_fiscal_number` | string | — | Для повернень, оформлених на іншому реєстраторі. | | `original.date` | string (date) | — | У форматі РРРР-ММ-ДД. | | `items` | array | так | | | `payments` | array | так | | | `rounding_step` | string | — | Крок заокруглення готівки десятковим рядком ("0.10" за правилами НБУ); без цього поля заокруглення не застосовується. | ### ServiceReceiptInput (object) Готівка, що проходить через касу повз продаж: `service_in` — службове внесення (DOCSUBTYPE 2), `service_out` — службова видача, тобто інкасація (DOCSUBTYPE 4). Це так само розрахунковий документ, тож він тягне за собою весь звичайний шлях чека: автоматичне відкриття зміни в керованих режимах, офлайн-сесію з ланцюжком хешів, журнал і тарифікацію як за чек. У підсумках зміни він не чіпає ні реалізації, ні повернення: сума накопичується окремо в service_input/service_output і потрапляє до ZREPBODY Z-звіту — так само, як веде свої підсумки ДПС. Залишок готівки реєстратора (cash_balance) він зсуває на всю свою суму. Підтип 3 (отримання підкріплення) не підтримується: це валютний документ (DOCTYPE 2) обмінних пунктів і ПТКС. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `cash_register_id` | string (uuid) | — | Реєстратор. Обов'язковий для POST /api/v1/receipts, де тіло — вся адреса запиту. Кабінетний маршрут бере реєстратор з URL: там поле або відсутнє, або збігається з ним, інакше 422. | | `type` | string | так | Значення: service_in, service_out. | | `cashier` | string | — | | | `comment` | string | — | Вільна примітка, яку друкують на самому документі (CHECKHEAD/COMMENT). Для руху готівки це єдине місце, де сказано, за що гроші — «Інкасація», «Розмінна монета». | | `mode` | string | — | Режим доставки результату; параметр запиту ?mode= має перевагу над цим полем. Значення: sync, async. | | `sum` | string | так | Сума руху — додатний десятковий рядок, до 2 знаків після коми. Це весь документ: підсумовувати тут нічого, позицій немає. | ### ReceiptItem (object) Грошові величини — десяткові рядки ("259.90"); кількість допускає до 3 знаків після коми, ціни — до 2. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `code` | string | — | | | `barcode` | string | — | | | `uktzed` | string | — | | | `dkpp` | string | — | Взаємовиключний з uktzed. | | `name` | string | так | | | `unit_code` | integer | — | | | `unit_name` | string | — | | | `quantity` | string | так | | | `price` | string | так | | | `tax_letters` | string | — | Податкові літери з tax_rates реєстратора, напр. "А" або "АГ". Порожнє значення застосовує default_tax_letter реєстратора (а якщо типової літери немає — позиція лишається без податку); "-" примусово робить позицію неоподаткованою попри типову літеру. | | `discount` | object | — | | | `discount.percent` | string | — | Позначає відсоткову знижку; суму все одно вказують у sum. | | `discount.sum` | string | так | | | `excise_labels` | array | — | | | `comment` | string | — | | ### PaymentType (string) Форма оплати. Фіскальний код і назву, які потраплять у чек, визначає сервіс: `cash` — 0 ГОТІВКА, `card` — 301 КАРТКА, `certificate` — 305 СЕРТИФІКАТ, `bank_transfer` — 306 ПЕРЕКАЗ З ПОТОЧНОГО РАХУНКУ, `direct_debit` — 100000 ПРЯМИЙ ДЕБЕТ. Через касу фізично проходить лише `cash` — саме вона рухає залишок готівки реєстратора. Решта форм на лічильник готівки не впливає. Значення: `cash`, `card`, `certificate`, `bank_transfer`, `direct_debit`. ### ReceiptPayment (object) | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `type` | PaymentType | так | Форма оплати. Фіскальний код і назву, які потраплять у чек, визначає сервіс: `cash` — 0 ГОТІВКА, `card` — 301 КАРТКА, `certificate` — 305 СЕРТИФІКАТ, `bank_transfer` — 306 ПЕРЕКАЗ З ПОТОЧНОГО РАХУНКУ, `direct_debit` — 100000 ПРЯМИЙ ДЕБЕТ. Через касу фізично проходить лише `cash` — саме вона рухає залишок готівки реєстратора. Решта форм на лічильник готівки не впливає. | | `sum` | string | так | | | `provided` | string | — | Отримано готівкою; решта = provided − sum. | | `card` | object | — | | | `card.system_name` | string | — | | | `card.acquirer_name` | string | — | | | `card.transaction_date` | string (date-time) | — | | | `card.transaction_number` | string | — | | | `card.device_id` | string | — | | | `card.epz_details` | string | — | Замаскований номер картки. | | `card.auth_code` | string | — | | ### WebhookEvent (string) task.completed і task.failed повідомляють про кожне завершене завдання; shift.opened і shift.closed — похідні події життєвого циклу зміни; key.expiring попереджає про сертифікати ключів, що спливають протягом 30 днів, раз на добу для кожного ключа; register.offline/register.online/register.offline_limit стежать за офлайн-сесіями та законними межами їх тривалості (36 та 168 годин); register.remediated повідомляє про кожне автоматичне усунення розбіжності між реєстратором і ДПС; register.needs_attention спрацьовує, коли виправлення не тримаються (повторювані усунення, зупинене надсилання офлайн-пакетів) і на реєстратор має поглянути людина. Значення: `task.completed`, `task.failed`, `shift.opened`, `shift.closed`, `key.expiring`, `register.offline`, `register.online`, `register.offline_limit`, `register.remediated`, `register.needs_attention`. ### WebhookEndpoint (object) | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `id` | string (uuid) | так | | | `url` | string | так | | | `events` | array | так | Порожній список означає підписку на всі події. Значення: task.completed, task.failed, shift.opened, shift.closed, key.expiring, register.offline, register.online, register.offline_limit, register.remediated, register.needs_attention. | | `active` | boolean | так | | | `created_at` | string (date-time) | так | | | `updated_at` | string (date-time) | так | | ### WebhookDelivery (object) | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `id` | string (uuid) | так | | | `event` | string | так | Тип події доставки. Крім значень WebhookEvent, доставка може нести зарезервовані типи, на які не можна підписатися: webhook.ping (тестова відправка) та system.dps_* (події доступності ДПС). | | `status` | string | так | Значення: pending, delivering, delivered, failed, dead. | | `attempts` | integer | так | | | `cash_register_id` | string (uuid) | — | | | `data` | any | так | Корисне навантаження події (поле data конверта). | | `last_error` | string | — | | | `next_attempt_at` | string (date-time) | — | | | `created_at` | string (date-time) | так | | | `delivered_at` | string (date-time) | — | | ### Money (string) Копійки десятковим рядком (numeric(14,4)); ніколи не число з рухомою комою. ### CashAmount (string) Гривні з копійками десятковим рядком — у тій самій формі, що й суми в чеках. На відміну від Money, який рахує копійки і належить тарифікації. ### CashBalance (object) Скільки готівки в касі реєстратора. Це лічильник, а не налаштування і не фіскальна величина: він стартує з нуля при створенні реєстратора і бачить лише ті документи, що пройшли через цей сервіс. Рухають його готівкові рядки оплат — додають на реалізації, віднімають на поверненні та сторно — і службові документи. Картка не рухає нічого: через касу фізично нічого не проходить. Решта вже врахована, бо береться `sum` рядка оплати, а не `provided`. Лічильник живе на реєстраторі, а не на зміні, бо готівка переживає Z-звіт: торговельний автомат закривається двічі на добу і тримає свої монети, доки по них не приїдуть. Значення **може бути від'ємним**, і ніщо цьому не заважає. Гроші лежали в касі ще до того, як сервіс побачив бодай один документ, тож перша інкасація цих грошей — цілком законна операція. Від'ємне значення саме по собі корисний сигнал: у касі було більше, ніж ми знали. Щоб переставити лічильник на справжню суму, скористайтеся PUT .../cash-balance. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `amount` | CashAmount | так | Гривні з копійками десятковим рядком — у тій самій формі, що й суми в чеках. На відміну від Money, який рахує копійки і належить тарифікації. | | `as_of` | string (date-time) | — | Коли залишок рухався востаннє. Null означає, що його ще ніщо не рухало, — тоді нуль читається як «ми ще нічого не бачили», а не «каса порожня». | ### ShiftTotalsSide (object) Один бік підсумків зміни — реалізація або повернення: скільки розрахунків прийнято і на яку суму, з розкладом за засобами оплати. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `count` | integer | так | Кількість розрахункових документів цього боку. | | `sum` | CashAmount | так | Гривні з копійками десятковим рядком — у тій самій формі, що й суми в чеках. На відміну від Money, який рахує копійки і належить тарифікації. | | `pay_forms` | array | — | Накопичено за засобами оплати. code/name — це пара PAYFORMCD / PAYFORMNM, яка піде в Z-звіт; масиву немає, поки бік порожній. | | `pay_forms.code` | integer | так | | | `pay_forms.name` | string | так | | | `pay_forms.sum` | CashAmount | так | Гривні з копійками десятковим рядком — у тій самій формі, що й суми в чеках. На відміну від Money, який рахує копійки і належить тарифікації. | ### ShiftTotals (object) Поточні підсумки відкритої зміни — те саме накопичення, з якого потім буде побудований Z-звіт. Сервіс складає його чек за чеком у тій самій транзакції, що реєструє документ, тож розійтися з журналом він не може. Сторно віднімається з боку реалізації, а не додається до повернень. Службові внесення й видачі не належать до жодного боку — ДПС тримає їх в окремих полях, і Z-звіт робить так само. Розклад за податковими літерами тут не віддається навмисно: він найширша частина підсумків і належить Z-звіту, а цей об'єкт їде у відповіді про стан, яку панель опитує кожні кілька секунд. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `realiz` | ShiftTotalsSide | так | Один бік підсумків зміни — реалізація або повернення: скільки розрахунків прийнято і на яку суму, з розкладом за засобами оплати. | | `return` | ShiftTotalsSide | так | Один бік підсумків зміни — реалізація або повернення: скільки розрахунків прийнято і на яку суму, з розкладом за засобами оплати. | | `service_in` | CashAmount | так | Гривні з копійками десятковим рядком — у тій самій формі, що й суми в чеках. На відміну від Money, який рахує копійки і належить тарифікації. | | `service_out` | CashAmount | так | Гривні з копійками десятковим рядком — у тій самій формі, що й суми в чеках. На відміну від Money, який рахує копійки і належить тарифікації. | ### CashBalanceDeclaration (object) Підсумок заяви про залишок: скільки лічильник показував, скільки показує тепер і поправка між ними. Дивитися варто саме на поправку — це те, наскільки наш підрахунок розійшовся з касою. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `amount` | CashAmount | так | Гривні з копійками десятковим рядком — у тій самій формі, що й суми в чеках. На відміну від Money, який рахує копійки і належить тарифікації. | | `previous` | CashAmount | так | Гривні з копійками десятковим рядком — у тій самій формі, що й суми в чеках. На відміну від Money, який рахує копійки і належить тарифікації. | | `adjustment` | CashAmount | так | Гривні з копійками десятковим рядком — у тій самій формі, що й суми в чеках. На відміну від Money, який рахує копійки і належить тарифікації. | ### BillingUsage (object) | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `balance` | Money | так | Копійки десятковим рядком (numeric(14,4)); ніколи не число з рухомою комою. | | `soft_limit` | Money | так | Нижня межа балансу: поки balance < soft_limit, чеки заблоковані. | | `blocked` | boolean | так | | | `period` | object | так | | | `period.from` | string (date) | так | | | `period.to` | string (date) | так | Не включно. | | `receipts` | integer (int64) | так | Кількість тарифікованих чеків за період. | | `charged` | Money | так | Копійки десятковим рядком (numeric(14,4)); ніколи не число з рухомою комою. | | `tariff` | object | так | | | `tariff.plan_id` | string (uuid) | так | | | `tariff.price_per_receipt` | Money | так | Копійки десятковим рядком (numeric(14,4)); ніколи не число з рухомою комою. | ### Invoice (object) | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `id` | string (uuid) | так | | | `period_start` | string (date) | так | | | `period_end` | string (date) | так | Включно. | | `amount` | Money | так | Копійки десятковим рядком (numeric(14,4)); ніколи не число з рухомою комою. | | `currency` | string | так | | | `status` | string | так | Значення: draft, issued, paid, overdue. | | `created_at` | string (date-time) | так | | ### DPSStatus (object) Знімок супервізора доступності ДПС плюс агрегати парку. Ефективний режим (effective) — це відповідь, на яку реагує конвеєр. | Поле | Тип | Обовʼязкове | Опис | |---|---|---|---| | `verdict` | string | так | Думка детектора незалежно від override. Значення: online, degraded, offline. | | `override` | string | так | Ручний режим оператора. Значення: none, forced_offline, forced_online. | | `effective` | string | так | Підсумковий операційний режим (override переважає вердикт). Значення: online, offline. | | `manual` | boolean | так | Чи діє зараз ручний override. | | `since` | string (date-time) | так | | | `override_reason` | string | — | | | `override_by` | string | — | | | `override_expires` | string (date-time) | — | Коли TTL override повертає режим у auto (якщо заданий). | | `last_probe_at` | string (date-time) | — | | | `last_ok_at` | string (date-time) | — | | | `last_error` | string | — | | | `flap_count` | integer | так | Переходи у поточному вікні flap-damping. | | `probe_latency_ms` | integer (int64) | — | | | `clock_drift_ms` | integer (int64) | — | | | `tunables` | object | — | Пороги, за якими судять числа вище (те саме, що у DPSPulse): ширина вікна, поріг degraded і крок перевірок. | | `tunables.window_seconds` | integer (int64) | — | | | `tunables.degraded_latency_ms` | integer (int64) | — | | | `tunables.probe_interval_seconds` | integer (int64) | — | | | `window` | object | так | Вікно детектора цієї репліки (по реальних викликах ДПС). | | `window.samples` | integer | так | | | `window.failures` | integer | так | | | `window.degraded` | boolean | так | | | `window.latency_ms` | integer (int64) | так | | | `window.by_class` | object | — | | | `offline_registers` | integer | так | Кас, що зараз в офлайн-сесії. | | `oldest_offline_age_seconds` | integer (int64) | так | |