prro

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 10, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

README

prro-go

Go Reference CI

Go-клієнт для API PRRO.cloud: фіскалізація чеків програмного РРО, зміни, офлайн-сесії, білінг і вебхуки.

  • Без залежностей — лише стандартна бібліотека Go.
  • Безпечні повтори: ключ ідемпотентності генерується автоматично, мережеві збої та 5xx повторюються з експоненційною затримкою.
  • Типізовані помилки для errors.Is і структурований опис збою ДПС.
  • Підпакет webhook: перевірка підпису, типізовані події, готовий http.Handler.
  • Звірено з контрактом OpenAPI сервісу тестами.

Встановлення

go get github.com/prro-cloud/prro-go

Потрібен Go 1.27 або новіший.

Швидкий старт

Токен випускають у кабінеті у розділі токенів. На касі в режимі test чеки безкоштовні й не потребують реєстрації в податковій.

c := prro.NewClient(os.Getenv("PRRO_TOKEN"))

task, err := c.Receipts.Create(ctx, &prro.SettlementReceipt{
	CashRegisterID: registerID, // з c.CashRegisters.List
	Type:           prro.ReceiptSale,
	Items: []prro.ReceiptItem{
		{Name: "Кава американо", Quantity: "1", Price: "65.00", TaxLetters: "А"},
	},
	Payments: []prro.Payment{{Type: prro.PaymentCard, Sum: "65.00"}},
}, prro.WithIdempotencyKey("order-10412"))
if err != nil {
	return err
}
if !task.Done() { // ДПС не відповіла за 30 секунд
	if task, err = c.Tasks.Wait(ctx, task.ID); err != nil {
		return err
	}
}

r := task.Result.Receipt
fmt.Println(r.FiscalNumber) // фіскальний номер від ДПС
fmt.Println(r.ReceiptURL)   // чек для покупця: https://r.prro.cloud/…
fmt.Println(r.TaxURL)       // той самий чек у кабінеті ДПС

Повний цикл — каса, зміна, чек — у examples/quickstart.

Ключові механіки

Ідемпотентність

Кожна фіскальна операція (чек, зміна, офлайн-сесія) несе ключ ідемпотентності: повтор із тим самим ключем повертає початкове завдання, а не реєструє другий документ. Передавайте ключ, похідний від замовлення, — тоді повтор безпечний і після перезапуску застосунку:

c.Receipts.Create(ctx, receipt, prro.WithIdempotencyKey("order-10412"))

Без WithIdempotencyKey клієнт генерує UUIDv7 сам — його вистачає для повторів у межах одного виклику. Той самий ключ з іншою операцією — prro.ErrIdempotencyKeyReused.

Синхронний і асинхронний режим

Типово виклик чекає на відповідь ДПС до 30 секунд. Не дочекався — повертає незавершене завдання (task.Done() == false), яке дочікуються через c.Tasks.Wait. З prro.WithAsync() завдання повертається одразу, а результат приходить опитуванням або вебхуком.

Гроші

Суми — десяткові рядки, ніколи не float64. Два типи, щоб їх не сплутати:

Тип Одиниця Де Приклад
prro.Amount гривні чеки, готівка, підсумки зміни "259.90"
prro.Kopecks копійки, до 4 знаків білінг: баланс, ціна чека, рахунки "50.0000"

Рядковий літерал присвоюється напряму (Price: "65.00"), обчислені суми перетворює prro.AmountFromKop(6500), назад — amount.Kop().

Помилки

Відповідь API з помилкою — *prro.Error зі статусом, машинним кодом і текстом. Типові випадки перевіряють через errors.Is:

Помилка Статус Що означає
ErrUnauthorized 401 токен недійсний, протермінований чи відкликаний
ErrForbidden 403 обмежений токен звернувся до білінгу чи вебхуків
ErrNotFound 404 ресурсу немає або токен не має до нього доступу
ErrPaymentRequired 402 баланс вичерпано — нові чеки заблоковано
ErrIdempotencyKeyReused 409 ключ уже використано для іншої операції
ErrWebhookLimitReached 409 вебхуків уже стільки, скільки кас, плюс один
ErrValidation 422 запит не пройшов валідацію, подробиці в Details
ErrTaskFailed 422 ДПС відхилила документ або немає відкритої зміни
switch {
case errors.Is(err, prro.ErrPaymentRequired):
	// поповнити баланс
case errors.Is(err, prro.ErrTaskFailed):
	if e, ok := errors.AsType[*prro.Error](err); ok && e.Fault != nil {
		log.Println(e.Fault.Code, e.Fault.Class) // напр. dps.check_local_number_invalid, resync
	}
}

Fault.Class підказує, що робити далі: transient — повторити, request — виправити запит, user_action — потрібне рішення людини тощо.

Чек для покупця

ReceiptURL — копія чека, що відкривається без авторизації: надішліть її листом, у месенджер або покажіть QR-кодом. Параметр ?format=png дає чек завширшки 576 px для термопринтера 80 мм, ?format=qr — QR-код посилання. TaxURL — той самий документ у кабінеті ДПС, незалежне підтвердження фіскалізації.

Вебхуки

Вебхук — адреса на вашому сервері, куди PRRO.cloud сам надсилає події: чек зареєстровано, зміну закрито, каса перейшла в офлайн, баланс добігає кінця. Опитувати завдання тоді не потрібно.

1. Зареєструйте вебхук і збережіть секрет

Секрет — рядок, яким сервіс підписує кожну доставку: HMAC-SHA256 тіла запиту в заголовку X-Signature. Ваш приймач перевіряє підпис тим самим секретом і так відрізняє справжні доставки від підроблених. Секрет видається рівно один раз — під час створення вебхука; отримати його повторно неможливо. Збережіть його одразу у сховищі секретів (змінна оточення, Vault тощо); якщо втратили — створіть вебхук заново.

Створити вебхук можна двома способами:

  • у кабінеті — розділ «Webhooks» → «Додати webhook»: секрет буде показано після створення;
  • з коду:
wh, err := c.Webhooks.Create(ctx, prro.CreateWebhookParams{
	URL:    "https://shop.example.com/prro-hook",
	Events: []prro.WebhookEvent{prro.EventTaskCompleted, prro.EventTaskFailed}, // порожньо — усі події
})
if err != nil {
	return err
}
// wh.Secret — збережіть, наприклад, у змінну оточення PRRO_WEBHOOK_SECRET.

Власний секрет можна задати полем Secret; якщо його не вказати, секрет згенерує сервер.

Вебхуків може бути не більше, ніж кас у клієнта, плюс один; призупинені теж рахуються. Скільки зайнято і скільки дозволено, показує c.Webhooks.List — поля Used і Limit; понад ліміт Create повертає prro.ErrWebhookLimitReached.

Подія receipt.registered несе повний вміст кожного зареєстрованого чека — позиції, оплати, податки, посилання для покупця — і приходить також на чеки, подані з панелі кабінету (Source == webhook.SourceCabinet). Її дані повертає e.Receipt().

2. Приймайте доставки
import "github.com/prro-cloud/prro-go/webhook"

secret := os.Getenv("PRRO_WEBHOOK_SECRET") // секрет із кроку 1

http.Handle("POST /prro-hook", webhook.Handler(secret, func(ctx context.Context, e *webhook.Event) error {
	if e.Type == prro.EventTaskCompleted {
		d, err := e.Task()
		if err != nil {
			return err
		}
		return markOrder(ctx, d.TaskID, d.Status)
	}
	return nil
}))

Handler перевіряє підпис до будь-якої обробки тіла і відповідає 401, якщо підпис не збігся. Помилка вашого обробника — відповідь 500, і сервіс повторить доставку. Доставка гарантована «щонайменше один раз»: відкидайте повтори за e.DeliveryID. Подію, яку приймач не прийняв, сервіс повторить пізніше, і вона може прийти після наступних подій тієї самої каси — упорядковуйте їх за e.Sequence. Перевірити приймач можна кнопкою «Тестова відправка» в кабінеті — прийде подія webhook.ping. Приклад із дедуплікацією — examples/webhook.

Налаштування клієнта

Опція Типово Призначення
WithBaseURL(url) https://api.prro.cloud інша адреса API
WithHTTPClient(hc) тайм-аут 60 с власний транспорт, проксі
WithRetry(n) 2 кількість повторів; 0 вимикає
WithLanguage("en") uk мова повідомлень про помилки
WithUserAgent("shop/1.0") — назва вашого застосунку в User-Agent
WithLogger(slog.Default()) вимкнено журнал запитів на рівні Debug

Повторюються лише запити, які безпечно повторити: GET, PUT і фіскальні операції з ключем ідемпотентності.

Методи

Сервіс Методи
c.Receipts Create
c.Tasks Get, Wait
c.CashRegisters List, Get, ClearAttention, SetCashBalance
c.Shifts Open, Close
c.OfflineSessions Close, Retry, Abandon
c.Billing Usage
c.Invoices List, All
c.Webhooks List, Create, Update, Delete, Deliveries, Replay
c.System Version, WhoAmI, DPS

Опис кожного методу — на pkg.go.dev. Ще приклади: асинхронний режим, повернення.

Документація API

  • prro.cloud/api — документація REST API.
  • llms-full.txt — уся документація одним файлом для ШІ-асистента.
  • openapi.yaml — контракт OpenAPI 3.1.

Бібліотека відповідає контракту версії prro.APIVersion.

Розробка

make test        # тести з -race
make lint        # golangci-lint
make sync-spec   # оновити testdata/openapi.yaml з репозиторію сервісу

Після make sync-spec тести контракту показують, яких методів, полів чи констант бракує клієнту. Зміни — у CHANGELOG.md, вразливості — за SECURITY.md.

Ліцензія

Apache 2.0

Documentation

Overview

Package prro — Go-клієнт для машинного API сервісу PRRO.cloud: реєстрація чеків програмного РРО, керування змінами, білінг і вебхуки.

Бібліотека не має залежностей поза стандартною бібліотекою Go.

Початок роботи

Токен випускають у кабінеті PRRO.cloud у розділі токенів. Клієнт безпечний для одночасного використання з кількох горутин — створюйте один на застосунок:

c := prro.NewClient(os.Getenv("PRRO_TOKEN"))
me, err := c.System.WhoAmI(ctx)

Ідемпотентність

Кожна фіскальна операція несе заголовок Idempotency-Key: повтор запиту з тим самим ключем повертає початкове завдання, а не реєструє другий документ. Якщо ключ не передано через WithIdempotencyKey, клієнт генерує його сам (UUIDv7) — цього досить для безпечних повторів у межах одного виклику. Щоб повтор був безпечним і після перезапуску застосунку, передавайте власний ключ, похідний від замовлення, — наприклад "order-10412".

Повтори

Мережеві збої та відповіді 429, 500, 502, 503 і 504 клієнт повторює з експоненційною затримкою, але лише для запитів, які безпечно повторити: GET, PUT і фіскальних операцій з Idempotency-Key. Кількість повторів задає WithRetry.

Помилки

Відповідь API з помилкою повертається як *Error: HTTP-статус, машинний код і текст для людини. Типові випадки перевіряють через errors.Is:

_, err := c.System.WhoAmI(ctx)
switch {
case errors.Is(err, prro.ErrUnauthorized):
	// токен недійсний або відкликаний
case errors.Is(err, prro.ErrPaymentRequired):
	// баланс вичерпано — нові чеки заблоковано до поповнення
}

Фіскальне завдання, що завершилося помилкою, дає ErrTaskFailed; його структурований опис — у полі Error.Fault.

Index

Examples

Constants

View Source
const APIVersion = "0.6.0"

APIVersion — версія контракту API (info.version в openapi.yaml), з якою зібрано бібліотеку.

View Source
const DefaultBaseURL = "https://api.prro.cloud"

DefaultBaseURL — базова адреса машинного API PRRO.cloud.

View Source
const Version = "0.2.0"

Version — версія бібліотеки; потрапляє в заголовок User-Agent.

Variables

View Source
var (
	// ErrUnauthorized — 401: токена немає, він недійсний, протермінований чи
	// відкликаний.
	ErrUnauthorized = errors.New("prro: unauthorized")
	// ErrForbidden — 403: обмежений токен звернувся до ресурсу рівня
	// клієнта (білінг, вебхуки).
	ErrForbidden = errors.New("prro: forbidden")
	// ErrNotFound — 404: ресурсу немає або токен не має до нього доступу.
	ErrNotFound = errors.New("prro: not found")
	// ErrPaymentRequired — 402: баланс нижче порога, нові чеки заблоковано
	// до поповнення. Операції зі змінами лишаються доступними.
	ErrPaymentRequired = errors.New("prro: payment required")
	// ErrIdempotencyKeyReused — 409: цей Idempotency-Key уже використано
	// для іншої операції.
	ErrIdempotencyKeyReused = errors.New("prro: idempotency key reused")
	// ErrWebhookLimitReached — 409: ліміт вебхуків вичерпано (не більше, ніж
	// кас у клієнта, плюс один); limit і used — у [Error.Details].
	ErrWebhookLimitReached = errors.New("prro: webhook limit reached")
	// ErrValidation — 422: запит не пройшов валідацію; подробиці — у
	// [Error.Details].
	ErrValidation = errors.New("prro: validation failed")
	// ErrTaskFailed — 422: фіскальне завдання завершилося помилкою (немає
	// відкритої зміни, відмова ДПС тощо); опис збою — у [Error.Fault].
	ErrTaskFailed = errors.New("prro: task failed")
)

Помилки для перевірки через errors.Is. Їх обгортає *Error за машинним кодом відповіді, а якщо коду немає — за HTTP-статусом.

Functions

This section is empty.

Types

type AbandonedDocument

type AbandonedDocument struct {
	DocumentID string `json:"document_id"`
	TaskID     string `json:"task_id,omitempty"`
	// Class — вид документа: check, zreport, open_shift, close_shift,
	// offline_begin, offline_end.
	Class string `json:"class"`
	// Kind — що оформив чек; лише для Class = "check".
	Kind ReceiptType `json:"kind,omitempty"`
	// LocalNumber — локальний номер, який мав документ.
	LocalNumber int64 `json:"local_number"`
	// FiscalNumber — офлайн-фіскальний номер, надрукований на документі.
	FiscalNumber string `json:"fiscal_number,omitempty"`
	// Total — сума документа; лише для чеків.
	Total Amount `json:"total,omitempty"`
	// PayForm — форма оплати чека: cash, cashless або mixed.
	PayForm   string    `json:"pay_form,omitempty"`
	CreatedAt time.Time `json:"created_at"`
}

AbandonedDocument — документ відмовленої офлайн-сесії. Його фіскального номера в ДПС не існує.

type Amount

type Amount string

Amount — сума в гривнях десятковим рядком ("259.90"), у тій самій формі, що в чеках: до 2 знаків після коми. Гроші в API ніколи не передаються числом з рухомою комою.

Літерал рядка присвоюється напряму — Price: "65.00"; для сум, обчислених у копійках, є AmountFromKop.

func AmountFromKop

func AmountFromKop(kop int64) Amount

AmountFromKop перетворює суму в копійках на Amount: 6500 → "65.00".

Example
package main

import (
	"fmt"

	"github.com/prro-cloud/prro-go"
)

func main() {
	fmt.Println(prro.AmountFromKop(25990))
	kop, _ := prro.Amount("65.5").Kop()
	fmt.Println(kop)
}
Output:
259.90
6550

func (Amount) Kop

func (a Amount) Kop() (int64, error)

Kop повертає суму в копійках: "65.5" → 6550. Рядок, що не є десятковим числом із щонайбільше 2 знаками після коми, — помилка.

type Attention

type Attention struct {
	Reason AttentionReason `json:"reason"`
	Since  time.Time       `json:"since,omitzero"`
}

Attention — позначка «каса потребує уваги».

type AttentionReason

type AttentionReason string

AttentionReason — чому каса потребує уваги.

const (
	// AttentionRecurringRemediation — розбіжності з ДПС усуваються знову і
	// знову.
	AttentionRecurringRemediation AttentionReason = "recurring_remediation"
	// AttentionOfflineSubmissionPaused — надсилання офлайн-пакетів
	// зупинено; відновлюють через [OfflineSessionsService.Retry].
	AttentionOfflineSubmissionPaused AttentionReason = "offline_submission_paused"
	// AttentionAutoCloseFailing — не вдається автоматичне закриття зміни.
	AttentionAutoCloseFailing AttentionReason = "auto_close_failing"
)

Причини позначки «потребує уваги».

type BillingPeriod

type BillingPeriod struct {
	From Date `json:"from"`
	To   Date `json:"to"`
}

BillingPeriod — період підсумку: From включно, To не включно.

type BillingService

type BillingService service

BillingService — передплачений баланс і тарифікація.

func (*BillingService) Usage

func (s *BillingService) Usage(ctx context.Context, params *UsageParams) (*BillingUsage, error)

Usage повертає передплачений баланс і підсумок тарифікації за період; params може бути nil. Тарифікація асинхронна, тож підсумок може відставати від останнього чека на кілька секунд.

type BillingUsage

type BillingUsage struct {
	Balance Kopecks `json:"balance"`
	// SoftLimit — нижня межа балансу: поки Balance < SoftLimit, нові чеки
	// відхиляються з [ErrPaymentRequired].
	SoftLimit Kopecks `json:"soft_limit"`
	// Blocked — чеки зараз заблоковано: балансом або рішенням оператора.
	Blocked bool          `json:"blocked"`
	Period  BillingPeriod `json:"period"`
	// Receipts — кількість тарифікованих чеків за період.
	Receipts int64   `json:"receipts"`
	Charged  Kopecks `json:"charged"`
	Tariff   Tariff  `json:"tariff"`
}

BillingUsage — баланс і підсумок тарифікації за період. Суми — у копійках (Kopecks).

type CallOption

type CallOption func(*callOptions)

CallOption налаштовує окремий виклик API.

func WithAsync

func WithAsync() CallOption

WithAsync перемикає фіскальну операцію в асинхронний режим: API одразу повертає завдання в стані pending або processing, а результат приходить через опитування завдання або вебхук. Для нефіскальних маршрутів не діє.

func WithIdempotencyKey

func WithIdempotencyKey(key string) CallOption

WithIdempotencyKey задає ключ ідемпотентності фіскальної операції. Ключ обирає інтеграція — найкраще похідний від замовлення ("order-10412"), щоб повтор після збою чи перезапуску не зареєстрував другий документ. Той самий ключ з іншою операцією — ErrIdempotencyKeyReused. Для нефіскальних маршрутів не діє.

type CardDetails

type CardDetails struct {
	SystemName    string `json:"system_name,omitempty"`     // назва платіжної системи
	AcquirerID    string `json:"acquirer_id,omitempty"`     // ідентифікатор еквайра
	AcquirerTaxID string `json:"acquirer_tax_id,omitempty"` // податковий номер еквайра
	AcquirerName  string `json:"acquirer_name,omitempty"`   // найменування еквайра
	// TransactionDate — дата й час транзакції на платіжному пристрої.
	TransactionDate time.Time `json:"transaction_date,omitzero"`
	// TransactionNumber — номер транзакції на платіжному пристрої.
	TransactionNumber string `json:"transaction_number,omitempty"`
	DeviceID          string `json:"device_id,omitempty"`   // ідентифікатор платіжного пристрою
	EPZDetails        string `json:"epz_details,omitempty"` // замаскований номер картки
	AuthCode          string `json:"auth_code,omitempty"`   // код авторизації
	// Commission — комісія еквайра, яку платить платник; у звичайному
	// продажу лишається порожньою.
	Commission Amount `json:"commission,omitempty"`
}

CardDetails — реквізити еквайрингу. Поля Acquirer* описують еквайра торговця, а не самого торговця.

type CashBalance

type CashBalance struct {
	Amount Amount `json:"amount"`
	// AsOf — коли залишок рухався востаннє; нульовий час — рухів ще не
	// було, тож нуль означає «немає даних», а не «каса порожня».
	AsOf time.Time `json:"as_of,omitzero"`
}

CashBalance — лічильник готівки каси. Враховує лише документи, що пройшли через сервіс; від'ємне значення означає, що в касі було більше, ніж побачив сервіс.

type CashBalanceDeclaration

type CashBalanceDeclaration struct {
	Amount     Amount `json:"amount"`
	Previous   Amount `json:"previous"`
	Adjustment Amount `json:"adjustment"`
}

CashBalanceDeclaration — лічильник готівки до заяви, після неї і поправка між ними.

type CashRegister

type CashRegister struct {
	// ID — ідентифікатор каси в API: CashRegisterID чека і параметр решти
	// методів. Фіскальний номер для цього не годиться.
	ID string `json:"id"`
	// FiscalNumber — фіскальний номер ПРРО, присвоєний ДПС.
	FiscalNumber string `json:"fiscal_number"`
	// LocalNumber — власний номер каси у клієнта.
	LocalNumber  string        `json:"local_number"`
	OrgName      string        `json:"org_name,omitempty"`      // назва суб'єкта господарювання
	PointName    string        `json:"point_name,omitempty"`    // назва точки продажу
	PointAddress string        `json:"point_address,omitempty"` // адреса точки продажу
	Mode         RegisterMode  `json:"mode"`
	State        RegisterState `json:"state"`
}

CashRegister — каса в переліку: ідентифікатор для звернень і реквізити, за якими її впізнає людина.

type CashRegisterState

type CashRegisterState struct {
	ID           string        `json:"id"`
	FiscalNumber string        `json:"fiscal_number"`
	LocalNumber  string        `json:"local_number"`
	Mode         RegisterMode  `json:"mode"`
	State        RegisterState `json:"state"`
	// OfflineReady — каса має видані ДПС офлайн-реквізити.
	OfflineReady bool      `json:"offline_ready,omitempty"`
	ShiftMode    ShiftMode `json:"shift_mode,omitempty"`
	// ShiftCloseTimes — час щоденного закриття зміни за київським часом
	// ("21:00"); порожній для [ShiftManual].
	ShiftCloseTimes []string     `json:"shift_close_times,omitempty"`
	CashBalance     *CashBalance `json:"cash_balance,omitempty"`
	// CurrentShift — поточна зміна; nil після закриття.
	CurrentShift *Shift `json:"current_shift,omitempty"`
	// ShiftTotals — підсумки відкритої зміни, з яких буде побудовано Z-звіт.
	ShiftTotals *ShiftTotals `json:"shift_totals,omitempty"`
	// OfflineSession — присутня, поки каса працює офлайн.
	OfflineSession *OfflineSession `json:"offline_session,omitempty"`
	// OfflineLimits — законодавчі межі офлайн-роботи.
	OfflineLimits OfflineLimits `json:"offline_limits"`
	// OfflineMonthUsedSeconds — час офлайн-роботи в цьому календарному
	// місяці (за київським часом), с.
	OfflineMonthUsedSeconds int64 `json:"offline_month_used_seconds,omitempty"`
	// Attention — присутня, коли каса потребує уваги; знімається через
	// [CashRegistersService.ClearAttention].
	Attention *Attention `json:"attention,omitempty"`
}

CashRegisterState — поточний стан каси: режим, зміна, готівка, офлайн-сесія.

type CashRegistersService

type CashRegistersService service

CashRegistersService — каси, доступні токену, і їхній стан.

func (*CashRegistersService) ClearAttention

func (s *CashRegistersService) ClearAttention(ctx context.Context, id string) (bool, error)

ClearAttention знімає з каси позначку «потребує уваги». false — позначки й не було. Зупинене надсилання офлайн-пакетів додатково відновлюють через OfflineSessionsService.Retry.

func (*CashRegistersService) Get

Get повертає поточний стан каси id.

func (*CashRegistersService) List

List повертає каси, доступні токену, від найстаріших. Звідси беруть ідентифікатор каси для решти методів — збережіть його в налаштуваннях інтеграції.

func (*CashRegistersService) SetCashBalance

func (s *CashRegistersService) SetCashBalance(ctx context.Context, id string, amount Amount) (*CashBalanceDeclaration, error)

SetCashBalance заявляє фактичний залишок готівки: переставляє лічильник на перераховану суму — коли касу підключили з непорожнім ящиком або лічильник розійшовся з фактом. Операція не фіскальна; рух готівки реєструють ServiceReceipt. Від'ємна сума — ErrValidation.

type Client

type Client struct {

	// Receipts — реєстрація чеків.
	Receipts *ReceiptsService
	// Tasks — стан і результат фіскальних завдань.
	Tasks *TasksService
	// CashRegisters — каси, доступні токену, і їхній стан.
	CashRegisters *CashRegistersService
	// Shifts — відкриття і закриття змін.
	Shifts *ShiftsService
	// OfflineSessions — керування офлайн-сесією каси.
	OfflineSessions *OfflineSessionsService
	// Billing — баланс і тарифікація.
	Billing *BillingService
	// Invoices — рахунки клієнта.
	Invoices *InvoicesService
	// Webhooks — вебхуки та історія доставок.
	Webhooks *WebhooksService
	// System — службові маршрути: версія сервісу, дозволи токена, режим
	// роботи з ДПС.
	System *SystemService
	// contains filtered or unexported fields
}

Client — клієнт машинного API PRRO.cloud. Створюється через NewClient; безпечний для одночасного використання з кількох горутин.

func NewClient

func NewClient(token string, opts ...Option) *Client

NewClient створює клієнт, що автентифікується машинним токеном token. Без опцій клієнт звертається до DefaultBaseURL, чекає на відповідь до 60 секунд і повторює безпечні запити двічі.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/prro-cloud/prro-go"
)

func main() {
	c := prro.NewClient(os.Getenv("PRRO_TOKEN"),
		prro.WithUserAgent("my-shop/1.0"),
	)

	me, err := c.System.WhoAmI(context.Background())
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("клієнт:", me.ClientID)
}

type CloseOfflineSessionParams

type CloseOfflineSessionParams struct {
	// Cashier — ім'я касира, яке друкують у документі завершення сесії.
	Cashier string `json:"cashier,omitempty"`
}

CloseOfflineSessionParams — необов'язкові параметри завершення офлайн-сесії.

type CreateWebhookParams

type CreateWebhookParams struct {
	// URL — абсолютний http(s)-URL приймача; обов'язковий.
	URL string `json:"url"`
	// Events — події підписки; порожній перелік — усі події.
	Events []WebhookEvent `json:"events,omitempty"`
	// Secret — секрет HMAC; порожній — згенерує сервер.
	Secret string `json:"secret,omitempty"`
}

CreateWebhookParams — параметри нового вебхука.

type CreatedWebhook

type CreatedWebhook struct {
	WebhookEndpoint
	// Secret — секрет HMAC для перевірки підпису доставок. Повертається
	// рівно один раз — збережіть його одразу.
	Secret string `json:"secret"`
}

CreatedWebhook — щойно створена точка доставки разом із секретом.

type DPSMode

type DPSMode string

DPSMode — режим роботи сервісу з ДПС.

const (
	// DPSOnline — ДПС відповідає вчасно.
	DPSOnline DPSMode = "online"
	// DPSDegraded — ДПС відповідає, але повільно; буває лише у
	// [DPSStatus.Verdict].
	DPSDegraded DPSMode = "degraded"
	// DPSOffline — ДПС недоступна, каси працюють в офлайн-сесіях.
	DPSOffline DPSMode = "offline"
)

Режими роботи з ДПС.

type DPSStatus

type DPSStatus struct {
	// Effective — підсумковий режим, якого дотримується сервіс:
	// [DPSOnline] або [DPSOffline].
	Effective DPSMode `json:"effective"`
	// Verdict — вердикт детектора; відрізняє «повільно» ([DPSDegraded]) від
	// «недоступно».
	Verdict DPSMode `json:"verdict"`
	// Since — відколи діє поточний режим Effective.
	Since time.Time `json:"since"`
	// LatencyMS — затримка успішних викликів у вікні детектора, мс.
	LatencyMS int64 `json:"latency_ms"`
	// Samples — скільки викликів у вікні.
	Samples int `json:"samples"`
	// Failures — скільки з них невдалих.
	Failures int `json:"failures"`
	// LastOKAt — остання успішна відповідь ДПС.
	LastOKAt time.Time `json:"last_ok_at,omitzero"`
	// LastProbeAt — остання перевірка доступності ДПС.
	LastProbeAt time.Time `json:"last_probe_at,omitzero"`
	// Tunables — пороги, за якими судять числа вище.
	Tunables DPSTunables `json:"tunables"`
}

DPSStatus — режим роботи з ДПС і телеметрія, що його пояснює.

type DPSTunables

type DPSTunables struct {
	// WindowSeconds — ширина вікна детектора, с.
	WindowSeconds int64 `json:"window_seconds"`
	// DegradedLatencyMS — затримка, від якої відповідь вважають
	// повільною, мс.
	DegradedLatencyMS int64 `json:"degraded_latency_ms"`
	// ProbeIntervalSeconds — крок перевірок, с.
	ProbeIntervalSeconds int64 `json:"probe_interval_seconds"`
}

DPSTunables — пороги детектора доступності ДПС.

type Date

type Date string

Date — календарна дата у форматі РРРР-ММ-ДД ("2026-07-14").

func DateOf

func DateOf(t time.Time) Date

DateOf повертає дату моменту t у його часовому поясі.

func (Date) Time

func (d Date) Time() (time.Time, error)

Time повертає початок дати d за UTC.

type DeliveryStatus

type DeliveryStatus string

DeliveryStatus — стан доставки події.

const (
	DeliveryPending    DeliveryStatus = "pending"    // у черзі
	DeliveryDelivering DeliveryStatus = "delivering" // триває спроба
	DeliveryDelivered  DeliveryStatus = "delivered"  // доставлено
	DeliveryFailed     DeliveryStatus = "failed"     // спроба невдала, буде повтор
	DeliveryDead       DeliveryStatus = "dead"       // спроби вичерпано
)

Стани доставки.

type Discount

type Discount struct {
	// Sum — сума знижки; вказується і для відсоткової знижки.
	Sum Amount `json:"sum"`
	// Percent — позначає знижку як відсоткову: "10".
	Percent string `json:"percent,omitempty"`
}

Discount — знижка на позицію.

type DocResult

type DocResult struct {
	// DocumentID — ідентифікатор документа в сервісі.
	DocumentID string `json:"document_id"`
	// LocalNumber — наскрізний номер документа в межах каси (ORDERNUM).
	LocalNumber int64 `json:"local_number"`
	// FiscalNumber — фіскальний номер документа, присвоєний ДПС; в
	// офлайн-документа обчислений локально (<sid>.<n>.<crc>).
	FiscalNumber string `json:"fiscal_number"`
	// RegisterFiscalNumber — фіскальний номер каси («ФН ПРРО» на чеку);
	// присутній завжди, за ним інтеграція зіставляє записи з касою.
	RegisterFiscalNumber string `json:"register_fiscal_number"`
	// Offline — документ підписано в офлайн-сесії; у ДПС він з'явиться
	// після надсилання пакета сесії.
	Offline bool `json:"offline,omitempty"`
	// ReceiptURL — копія чека для покупця (https://r.prro.cloud/<код>),
	// відкривається без авторизації. Параметр ?format= обирає подання:
	// html (типово), png (576 px для термопринтера 80 мм) або qr. Є лише в
	// розрахункових документів.
	ReceiptURL string `json:"receipt_url,omitempty"`
	// TaxURL — той самий документ у кабінеті платника податків, незалежне
	// підтвердження фіскалізації. Відсутнє, доки документ не потрапив до ДПС.
	TaxURL string `json:"tax_url,omitempty"`
	// Original — початковий чек; лише в документа повернення.
	Original *ReturnOriginal `json:"original,omitempty"`
}

DocResult — документ, який видало завдання: номери в журналі та в ДПС і посилання для покупця.

type Error

type Error struct {
	// StatusCode — HTTP-статус відповіді.
	StatusCode int
	// Code — стабільний машинний код помилки ("validation_failed",
	// "task_failed", …); саме на нього реагує інтеграція. Порожній, якщо
	// відповідь прийшла не від API (наприклад, сторінка помилки проксі).
	Code string
	// Message — пояснення для людини; покладатися на його текст
	// програмно не можна.
	Message string
	// Details — подробиці помилки як є, наприклад перелік полів, які не
	// пройшли валідацію.
	Details json.RawMessage
	// TaskID — завдання, що завершилося помилкою; лише для [ErrTaskFailed].
	TaskID string
	// Fault — структурований опис збою завдання; лише для [ErrTaskFailed].
	Fault *Fault
}

Error — відповідь API з помилкою: конверт {code, message, details}.

Example
package main

import (
	"context"
	"errors"
	"fmt"
	"os"

	"github.com/prro-cloud/prro-go"
)

func main() {
	c := prro.NewClient(os.Getenv("PRRO_TOKEN"))

	_, err := c.System.WhoAmI(context.Background())
	if err == nil {
		fmt.Println("токен дійсний")
		return
	}
	if errors.Is(err, prro.ErrUnauthorized) {
		fmt.Println("токен недійсний або відкликаний")
		return
	}
	if apiErr, ok := errors.AsType[*prro.Error](err); ok {
		fmt.Println("помилка API:", apiErr.Code, apiErr.Message)
		return
	}
	fmt.Println("мережева помилка:", err)
}

func (*Error) Error

func (e *Error) Error() string

Error повертає опис помилки: статус, код і повідомлення.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap повертає відповідну помилку-маркер (ErrNotFound, ErrTaskFailed, …) або nil, якщо такої немає.

type Fault

type Fault struct {
	// Code — стабільний ідентифікатор, напр. "dps.check_local_number_invalid".
	Code string `json:"code"`
	// Class — що може зарадити.
	Class FaultClass `json:"class"`
	// Params — значення для підстановки в Message.
	Params map[string]any `json:"params,omitempty"`
	// Message — текст для людини мовою з [WithLanguage].
	Message string `json:"message,omitempty"`
	// UpstreamMessage — дослівне повідомлення фіскального сервера.
	UpstreamMessage string `json:"upstream_message,omitempty"`
	// Remediation — автоматичні виправлення, застосовані під час обробки
	// завдання: "local_number_synced", "shift_adopted", …
	Remediation []string `json:"remediation,omitempty"`
}

Fault — структурований опис збою завдання. Простори імен коду: dps.* — відмова фіскального сервера, fiscal.* — валідація документа, return.* — звірка повернення з початковим чеком, signer.* — рівень КЕП, state.* — стан реєстратора.

type FaultClass

type FaultClass string

FaultClass — що може зарадити збою завдання.

const (
	// FaultResync — звірити стан із ДПС.
	FaultResync FaultClass = "resync"
	// FaultConfig — виправити налаштування реєстратора.
	FaultConfig FaultClass = "config"
	// FaultPrecursor — виконати пропущений попередній крок.
	FaultPrecursor FaultClass = "precursor"
	// FaultUserAction — потрібне рішення людини.
	FaultUserAction FaultClass = "user_action"
	// FaultTransient — тимчасова недоступність, допоможе повтор.
	FaultTransient FaultClass = "transient"
	// FaultRequest — виправити запит.
	FaultRequest FaultClass = "request"
	// FaultInternal — збій сервісу.
	FaultInternal FaultClass = "internal"
)

Класи збою завдання.

type Identity

type Identity struct {
	// ClientID — клієнт, від імені якого діє токен.
	ClientID string `json:"client_id"`
	// Scopes — дозволи, видані токену.
	Scopes []string `json:"scopes"`
	// AllCashRegisters — токен діє на всі каси клієнта, поточні й
	// майбутні; false — лише на перелічені в CashRegisters.
	AllCashRegisters bool `json:"all_cash_registers"`
	// CashRegisters — ідентифікатори кас обмеженого токена; порожній, коли
	// AllCashRegisters.
	CashRegisters []string `json:"cash_registers,omitempty"`
	// TokenID — ідентифікатор токена (jti); за ним токен відкликають у
	// кабінеті.
	TokenID string `json:"jti"`
	// ExpiresAt — коли токен спливає; нульовий час — токен безстроковий.
	ExpiresAt time.Time `json:"expires_at,omitzero"`
}

Identity — клієнт, від імені якого діє токен, і межі його дозволів.

func (*Identity) UnmarshalJSON

func (id *Identity) UnmarshalJSON(b []byte) error

UnmarshalJSON приймає expires_at і як рядок RFC 3339 (за контрактом), і як число секунд Unix — так його віддають сервери до виправлення формату.

type Invoice

type Invoice struct {
	ID string `json:"id"`
	// PeriodStart і PeriodEnd — межі періоду, обидві включно.
	PeriodStart Date    `json:"period_start"`
	PeriodEnd   Date    `json:"period_end"`
	Amount      Kopecks `json:"amount"`
	// Currency — валюта за ISO 4217: "UAH".
	Currency  string        `json:"currency"`
	Status    InvoiceStatus `json:"status"`
	CreatedAt time.Time     `json:"created_at"`
}

Invoice — рахунок за один розрахунковий період.

type InvoiceStatus

type InvoiceStatus string

InvoiceStatus — стан рахунка.

const (
	InvoiceDraft   InvoiceStatus = "draft"   // чернетка
	InvoiceIssued  InvoiceStatus = "issued"  // виставлено
	InvoicePaid    InvoiceStatus = "paid"    // оплачено
	InvoiceOverdue InvoiceStatus = "overdue" // прострочено
)

Стани рахунка.

type InvoicesService

type InvoicesService service

InvoicesService — рахунки клієнта.

func (*InvoicesService) All

All обходить усі рахунки, від найновішого, підвантажуючи сторінки за потреби. Помилка завершує обхід:

for inv, err := range c.Invoices.All(ctx) {
	if err != nil {
		return err
	}
	fmt.Println(inv.PeriodStart, inv.Amount, inv.Status)
}
Example
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/prro-cloud/prro-go"
)

func main() {
	c := prro.NewClient(os.Getenv("PRRO_TOKEN"))

	for inv, err := range c.Invoices.All(context.Background()) {
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(inv.PeriodStart, inv.Amount, inv.Status)
	}
}

func (*InvoicesService) List

func (s *InvoicesService) List(ctx context.Context, params *ListInvoicesParams) ([]Invoice, error)

List повертає сторінку рахунків, від найновішого періоду; params може бути nil. Усі рахунки поспіль дає InvoicesService.All.

type Kopecks

type Kopecks string

Kopecks — сума тарифікації в копійках десятковим рядком із точністю до 4 знаків ("150.0000" — півтори гривні). Так рахує білінг: ціна чека, баланс, рахунки. Суми в чеках — Amount.

type ListDeliveriesParams

type ListDeliveriesParams struct {
	// Status — лише доставки в цьому стані; порожній — усі.
	Status DeliveryStatus
	// Limit — скільки доставок повернути: 1–200; 0 — типово 50.
	Limit int
}

ListDeliveriesParams — фільтр історії доставок.

type ListInvoicesParams

type ListInvoicesParams struct {
	// Limit — скільки рахунків повернути: 1–200; 0 — типово 50.
	Limit int
	// Offset — скільки рахунків пропустити.
	Offset int
}

ListInvoicesParams — сторінка переліку рахунків.

type OfflineAbandonResult

type OfflineAbandonResult struct {
	// SessionID — сесія, від якої відмовлено.
	SessionID string `json:"session_id"`
	// DPSSessionID — номер сесії, виданий ДПС.
	DPSSessionID int64 `json:"dps_session_id"`
	// HeldDocuments — скільки документів сесії ДПС отримала; вони
	// лишаються зареєстрованими.
	HeldDocuments int64 `json:"held_documents"`
	// Abandoned — документи сесії, яких ДПС не отримала; чи видавати їх
	// знову, вирішує інтеграція.
	Abandoned []AbandonedDocument `json:"abandoned"`
	// ClosureSessionID — сесія, якою відмовлену сесію завершують у ДПС.
	ClosureSessionID string `json:"closure_session_id,omitempty"`
	// Closed — сесію завершено в ДПС, каса знову онлайн; false — завершення
	// ще передається.
	Closed bool `json:"closed"`
}

OfflineAbandonResult — результат відмови від офлайн-сесії.

type OfflineLimits

type OfflineLimits struct {
	SessionSeconds int64 `json:"session_seconds"`
	MonthSeconds   int64 `json:"month_seconds"`
}

OfflineLimits — законодавчі межі офлайн-роботи: 36 годин на сесію і 168 годин на календарний місяць, у секундах.

type OfflineSession

type OfflineSession struct {
	ID string `json:"id"`
	// DPSSessionID — номер сесії, виданий ДПС; входить у фіскальний номер
	// офлайн-документа.
	DPSSessionID int64 `json:"dps_session_id"`
	// StartedAt — початок сесії; від нього рахують 36-годинну межу.
	StartedAt time.Time `json:"started_at"`
	Documents int64     `json:"documents"`
	// LastSignificantAt — останній документ, що продовжує сесію.
	LastSignificantAt time.Time `json:"last_significant_at,omitzero"`
}

OfflineSession — офлайн-сесія каси.

type OfflineSessionsService

type OfflineSessionsService service

OfflineSessionsService — керування офлайн-сесією каси.

func (*OfflineSessionsService) Abandon

func (s *OfflineSessionsService) Abandon(ctx context.Context, registerID string, opts ...CallOption) (*Task, error)

Abandon відмовляється від офлайн-сесії, яку ДПС не приймає. Доступно лише для сесії із зупиненим надсиланням і лише коли ДПС відповідає. Документи, яких ДПС не отримала, стають abandoned: їхніх фіскальних номерів у ДПС не існує. Перелік — у Result.OfflineAbandon; чи видавати ці продажі знову, вирішує інтеграція.

func (*OfflineSessionsService) Close

func (s *OfflineSessionsService) Close(ctx context.Context, registerID string, params *CloseOfflineSessionParams, opts ...CallOption) (*Task, error)

Close передає пакети офлайн-сесії каси registerID до ДПС і завершує сесію, не чекаючи фонової передачі. Якщо ДПС недоступна, завдання завершується збоєм state.offline_close_needs_dps — сесію буде передано й завершено автоматично, щойно зв'язок відновиться. params може бути nil.

func (*OfflineSessionsService) Retry

func (s *OfflineSessionsService) Retry(ctx context.Context, registerID string) (int, error)

Retry відновлює надсилання офлайн-пакетів, зупинене після того, як ДПС відхилила пакет сесії. Спершу усуньте причину. Повертає, скільки сесій повернуто до надсилання; 0 — зупинених не було.

type OpenShiftParams

type OpenShiftParams struct {
	// Cashier — ім'я касира, яке друкують у документі відкриття.
	Cashier string `json:"cashier,omitempty"`
}

OpenShiftParams — необов'язкові параметри відкриття зміни.

type Option

type Option func(*Client)

Option налаштовує Client під час створення в NewClient.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL задає базову адресу API замість DefaultBaseURL — наприклад для власного проксі або локального сервера. Порожній рядок залишає адресу за замовчуванням, тож значення можна брати прямо зі змінної оточення: WithBaseURL(os.Getenv("PRRO_BASE_URL")).

func WithHTTPClient

func WithHTTPClient(hc *http.Client) Option

WithHTTPClient задає HTTP-клієнт для запитів: власний транспорт, проксі, тайм-аути. Тайм-аут має перевищувати 30 секунд синхронного очікування ДПС. nil залишає клієнт за замовчуванням.

func WithLanguage

func WithLanguage(lang string) Option

WithLanguage задає мову повідомлень про помилки (заголовок Accept-Language): "uk" (типово) або "en".

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger вмикає журнал запитів на рівні Debug: метод, шлях, спроба, статус і тривалість. Токен і тіла запитів у журнал не потрапляють.

func WithRetry

func WithRetry(maxRetries int) Option

WithRetry задає, скільки разів повторювати безпечний запит після мережевого збою або відповіді 429/5xx; 0 вимикає повтори. Типово — 2.

func WithUserAgent

func WithUserAgent(ua string) Option

WithUserAgent додає назву вашого застосунку на початок заголовка User-Agent: "my-shop/1.2 prro-go/0.1.0 (…)".

type PayFormTotal

type PayFormTotal struct {
	Code int    `json:"code"` // PAYFORMCD
	Name string `json:"name"` // PAYFORMNM
	Sum  Amount `json:"sum"`
}

PayFormTotal — накопичення за однією формою оплати, як у Z-звіті.

type Payment

type Payment struct {
	// Type — форма оплати.
	Type PaymentType `json:"type"`
	// Sum — сума, віднесена на цю форму оплати.
	Sum Amount `json:"sum"`
	// Provided — отримано готівкою; решта = Provided − Sum.
	Provided Amount `json:"provided,omitempty"`
	// Means — засіб оплати, який друкується замість назви форми:
	// «ПЕРЕКАЗ З КАРТКИ», «ТАЛОН», «Подарунковий сертифікат». Фіскальний
	// код форми лишається за Type. Для готівки не приймається.
	Means string `json:"means,omitempty"`
	// Card — реквізити еквайрингу для оплати карткою.
	Card *CardDetails `json:"card,omitempty"`
}

Payment — одна оплата чека.

type PaymentType

type PaymentType string

PaymentType — форма оплати. Фіскальний код і назву, які потраплять у чек, визначає сервіс; залишок готівки каси рухає лише PaymentCash.

const (
	PaymentCash         PaymentType = "cash"          // 0 ГОТІВКА
	PaymentCard         PaymentType = "card"          // 301 КАРТКА
	PaymentCertificate  PaymentType = "certificate"   // 305 СЕРТИФІКАТ
	PaymentBankTransfer PaymentType = "bank_transfer" // 306 ПЕРЕКАЗ З ПОТОЧНОГО РАХУНКУ
	PaymentDirectDebit  PaymentType = "direct_debit"  // 100000 ПРЯМИЙ ДЕБЕТ
)

Форми оплати.

type ReceiptInput

type ReceiptInput interface {
	// contains filtered or unexported methods
}

ReceiptInput — документ для ReceiptsService.Create: *SettlementReceipt (розрахунок за товари) або *ServiceReceipt (рух готівки). Інших реалізацій немає — поля чужої форми API відхиляє з 422, тож форми розділено на рівні типів.

type ReceiptItem

type ReceiptItem struct {
	// Name — назва позиції, як її друкують у чеку.
	Name string `json:"name"`
	// Quantity — кількість десятковим рядком, до 3 знаків після коми:
	// "1", "0.750".
	Quantity string `json:"quantity"`
	// Price — ціна за одиницю.
	Price Amount `json:"price"`
	// TaxLetters — податкові літери каси, напр. "А" або "АГ". Порожнє
	// значення застосовує типову літеру каси, "-" робить позицію
	// неоподаткованою.
	TaxLetters string `json:"tax_letters,omitempty"`
	// Code — внутрішній код товару.
	Code string `json:"code,omitempty"`
	// Barcode — штрихкод товару.
	Barcode string `json:"barcode,omitempty"`
	// UKTZED — код УКТЗЕД; взаємовиключний з DKPP.
	UKTZED string `json:"uktzed,omitempty"`
	// DKPP — код ДКПП; взаємовиключний з UKTZED.
	DKPP string `json:"dkpp,omitempty"`
	// UnitCode — код одиниці виміру (UNITCD).
	UnitCode int `json:"unit_code,omitempty"`
	// UnitName — назва одиниці виміру: «шт», «кг».
	UnitName string `json:"unit_name,omitempty"`
	// Discount — знижка на позицію.
	Discount *Discount `json:"discount,omitempty"`
	// ExciseLabels — коди марок акцизного податку.
	ExciseLabels []string `json:"excise_labels,omitempty"`
	// Comment — примітка до позиції.
	Comment string `json:"comment,omitempty"`
}

ReceiptItem — позиція чека.

type ReceiptOriginal

type ReceiptOriginal struct {
	// FiscalNumber — фіскальний номер початкового чека.
	FiscalNumber string `json:"fiscal_number"`
	// RegisterFiscalNumber — фіскальний номер каси початкового чека, якщо
	// це інша каса; без нього чек шукають на касі повернення.
	RegisterFiscalNumber string `json:"register_fiscal_number,omitempty"`
	// Date — дата початкового чека.
	Date Date `json:"date,omitempty"`
}

ReceiptOriginal — посилання на початковий чек повернення або сторно.

type ReceiptType

type ReceiptType string

ReceiptType — вид розрахункового документа.

const (
	ReceiptSale       ReceiptType = "sale"        // реалізація
	ReceiptReturn     ReceiptType = "return"      // повернення
	ReceiptStorno     ReceiptType = "storno"      // сторно
	ReceiptServiceIn  ReceiptType = "service_in"  // службове внесення
	ReceiptServiceOut ReceiptType = "service_out" // службова видача (інкасація)
)

Види розрахункових документів.

type ReceiptsService

type ReceiptsService service

ReceiptsService — реєстрація розрахункових документів.

func (*ReceiptsService) Create

func (s *ReceiptsService) Create(ctx context.Context, in ReceiptInput, opts ...CallOption) (*Task, error)

Create реєструє розрахунковий документ: сервіс видає локальний номер, підписує документ КЕП і надсилає до ДПС.

Синхронно (типово) виклик чекає на результат до 30 секунд: успіх — це завдання зі Status == TaskSucceeded, а фіскальний номер і посилання для покупця — у Result.Receipt. Якщо ДПС не встигла, повертається незавершене завдання — дочекайтеся його через TasksService.Wait. З WithAsync незавершене завдання повертається одразу.

Передавайте WithIdempotencyKey з ключем, похідним від замовлення: повтор із тим самим ключем поверне те саме завдання, а не другий чек.

Example
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/prro-cloud/prro-go"
)

func main() {
	c := prro.NewClient(os.Getenv("PRRO_TOKEN"))
	ctx := context.Background()

	task, err := c.Receipts.Create(ctx, &prro.SettlementReceipt{
		CashRegisterID: os.Getenv("PRRO_REGISTER_ID"),
		Type:           prro.ReceiptSale,
		Items: []prro.ReceiptItem{
			{Name: "Кава американо", Quantity: "1", Price: "65.00", TaxLetters: "А"},
		},
		Payments: []prro.Payment{{Type: prro.PaymentCash, Sum: "65.00", Provided: "100.00"}},
	}, prro.WithIdempotencyKey("order-10412"))
	if err != nil {
		log.Fatal(err)
	}
	if !task.Done() {
		if task, err = c.Tasks.Wait(ctx, task.ID); err != nil {
			log.Fatal(err)
		}
	}
	fmt.Println(task.Result.Receipt.FiscalNumber, task.Result.Receipt.ReceiptURL)
}

type ReconcileCash

type ReconcileCash struct {
	Ours  Amount `json:"ours"`
	DPS   Amount `json:"dps"`
	Match bool   `json:"match"`
}

ReconcileCash — готівка зміни за двома підрахунками.

type ReconcileReport

type ReconcileReport struct {
	FiscalNumber       string `json:"fiscal_number"`
	DPSShiftOpened     bool   `json:"dps_shift_opened"`
	DPSNextLocalNumber int64  `json:"dps_next_local_number"`
	DPSTesting         bool   `json:"dps_testing,omitempty"`
	CounterOld         int64  `json:"counter_old,omitempty"`
	CounterNew         int64  `json:"counter_new,omitempty"`
	// ShiftAdopted — сервіс прийняв як свою зміну, відкриту на боці ДПС.
	ShiftAdopted bool `json:"shift_adopted,omitempty"`
	// ShiftAbandoned — сервіс закрив у себе зміну, якої на боці ДПС немає.
	ShiftAbandoned              bool `json:"shift_abandoned,omitempty"`
	OfflineCredentialsRefreshed bool `json:"offline_credentials_refreshed,omitempty"`
	// Cash — рух готівки зміни за обліком сервісу і за ДПС; довідково.
	Cash *ReconcileCash `json:"cash,omitempty"`
	// Totals — підсумки зміни за обліком сервісу і за ДПС.
	Totals *ReconcileTotals `json:"totals,omitempty"`
	// AttentionCleared — знято позначку auto_close_failing.
	AttentionCleared bool `json:"attention_cleared,omitempty"`
	// Skipped — чому звіряння нічого не змінювало ("offline_session").
	Skipped string `json:"skipped,omitempty"`
}

ReconcileReport — підсумок звіряння реєстратора з ДПС: який стан побачили на боці ДПС і що виправили в сервісі.

type ReconcileTotals

type ReconcileTotals struct {
	Ours ShiftTotalsBrief `json:"ours"`
	// DPS — відсутнє, якщо ДПС не повернула підсумки.
	DPS   *ShiftTotalsBrief `json:"dps,omitempty"`
	Match bool              `json:"match"`
	// ZReportSource — з яких підсумків буде подано Z-звіт: local або dps.
	ZReportSource string `json:"z_report_source"`
	// Forced — це звіряння перевело Z-звіт на підсумки ДПС.
	Forced bool `json:"forced,omitempty"`
	// Held — чому розбіжність не виправлено: dps_totals_unavailable,
	// shift_closing або offline_backlog.
	Held string `json:"held,omitempty"`
}

ReconcileTotals — підсумки зміни за двома обліками.

type RegisterMode

type RegisterMode string

RegisterMode — режим каси. Документи зміни мають режим, у якому її відкрито; змінити режим можна лише при закритій зміні.

const (
	RegisterProduction RegisterMode = "production" // бойовий режим
	RegisterTest       RegisterMode = "test"       // документи позначені як тестові
)

Режими каси.

type RegisterState

type RegisterState string

RegisterState — стан каси.

const (
	RegisterClosed  RegisterState = "closed"  // зміна закрита
	RegisterOpened  RegisterState = "opened"  // зміна відкрита
	RegisterOffline RegisterState = "offline" // триває офлайн-сесія
)

Стани каси.

type ReturnOriginal

type ReturnOriginal struct {
	// FiscalNumber — фіскальний номер початкового чека.
	FiscalNumber string `json:"fiscal_number"`
	// DocumentID — початковий чек у журналі сервісу; порожній, якщо чек
	// видано поза сервісом.
	DocumentID string `json:"document_id,omitempty"`
	// Verified — повернення звірено із залишком за початковим чеком; false —
	// чек видано іншим ПРРО, повернення прийнято без звірки.
	Verified bool `json:"verified"`
}

ReturnOriginal — початковий чек повернення.

type ServiceReceipt

type ServiceReceipt struct {
	// CashRegisterID — каса, на якій реєструють документ; обов'язкове.
	CashRegisterID string `json:"cash_register_id"`
	// Type — [ReceiptServiceIn] або [ReceiptServiceOut].
	Type ReceiptType `json:"type"`
	// Sum — сума руху, додатна.
	Sum Amount `json:"sum"`
	// Cashier — ім'я касира, яке друкують у документі.
	Cashier string `json:"cashier,omitempty"`
	// Comment — за що гроші: «Інкасація», «Розмінна монета».
	Comment string `json:"comment,omitempty"`
	// SoldAt — момент фактичної операції, якщо документ дійшов до сервісу
	// пізніше; правила — як у [SettlementReceipt.SoldAt].
	SoldAt time.Time `json:"sold_at,omitzero"`
}

ServiceReceipt — рух готівки повз продаж: службове внесення (ReceiptServiceIn) або інкасація (ReceiptServiceOut). Позицій і оплат не має — лише суму.

type SettlementReceipt

type SettlementReceipt struct {
	// CashRegisterID — каса, на якій реєструють документ; обов'язкове.
	CashRegisterID string `json:"cash_register_id"`
	// Type — [ReceiptSale], [ReceiptReturn] або [ReceiptStorno].
	Type ReceiptType `json:"type"`
	// Cashier — ім'я касира, яке друкують у чеку; без нього рядка не буде.
	Cashier string `json:"cashier,omitempty"`
	// Comment — вільна примітка, яку друкують на чеку, — наприклад номер
	// замовлення.
	Comment string `json:"comment,omitempty"`
	// SoldAt — момент фактичного продажу, якщо документ дійшов до сервісу
	// пізніше за касу. Друкується рядком «Продаж від 03.09.2026 18:11», але
	// фіскальним часом документа не стає. Час у майбутньому або старіший за
	// 31 день — 422.
	SoldAt time.Time `json:"sold_at,omitzero"`
	// Original — початковий чек; обов'язковий для повернення та сторно.
	Original *ReceiptOriginal `json:"original,omitempty"`
	// Items — позиції чека; щонайменше одна.
	Items []ReceiptItem `json:"items"`
	// Payments — оплати чека; щонайменше одна.
	Payments []Payment `json:"payments"`
	// RoundingStep — крок заокруглення готівки ("0.10" за правилами НБУ);
	// порожній — без заокруглення.
	RoundingStep Amount `json:"rounding_step,omitempty"`
}

SettlementReceipt — розрахунок за товари: реалізація, повернення або сторно.

type Shift

type Shift struct {
	ID string `json:"id"`
	// Number — наскрізний номер зміни в межах каси («Зміна №147»).
	Number int64       `json:"number"`
	Status ShiftStatus `json:"status"`
	// Testing — зміну відкрито в режимі test, усі її документи тестові.
	Testing  bool      `json:"testing,omitempty"`
	OpenedAt time.Time `json:"opened_at,omitzero"`
	// Documents — скільки документів створила зміна, усіх видів.
	Documents int `json:"documents,omitempty"`
}

Shift — зміна каси.

type ShiftMode

type ShiftMode string

ShiftMode — як керують змінами каси.

const (
	// ShiftManual — клієнт відкриває і закриває зміни сам.
	ShiftManual ShiftMode = "manual"
	// ShiftRoundTheClock — зміна закривається в кожен із ShiftCloseTimes,
	// наступний чек відкриває нову.
	ShiftRoundTheClock ShiftMode = "round_the_clock"
	// ShiftWorkingHours — денне вікно між двома межами ShiftCloseTimes.
	ShiftWorkingHours ShiftMode = "working_hours"
)

Режими змін.

type ShiftStatus

type ShiftStatus string

ShiftStatus — стан зміни.

const (
	ShiftOpening ShiftStatus = "opening"
	ShiftOpened  ShiftStatus = "opened"
	ShiftClosing ShiftStatus = "closing"
	ShiftClosed  ShiftStatus = "closed"
)

Стани зміни; opening і closing — операція ще в роботі.

type ShiftTotals

type ShiftTotals struct {
	Sales      ShiftTotalsSide `json:"realiz"`
	Returns    ShiftTotalsSide `json:"return"`
	ServiceIn  Amount          `json:"service_in"`
	ServiceOut Amount          `json:"service_out"`
}

ShiftTotals — поточні підсумки відкритої зміни. Сторно віднімається з реалізації; службові внесення й видачі не належать до жодного боку.

type ShiftTotalsBrief

type ShiftTotalsBrief struct {
	Sales         Amount `json:"sales"`
	SalesCount    int    `json:"sales_count"`
	Returns       Amount `json:"returns"`
	ReturnsCount  int    `json:"returns_count"`
	ServiceInput  Amount `json:"service_input"`
	ServiceOutput Amount `json:"service_output"`
}

ShiftTotalsBrief — суми й кількості чеків зміни, за якими ДПС звіряє Z-звіт.

type ShiftTotalsSide

type ShiftTotalsSide struct {
	Count    int            `json:"count"`
	Sum      Amount         `json:"sum"`
	PayForms []PayFormTotal `json:"pay_forms,omitempty"`
}

ShiftTotalsSide — один бік підсумків зміни: кількість документів, сума і розклад за формами оплати.

type ShiftsService

type ShiftsService service

ShiftsService — відкриття і закриття змін.

func (*ShiftsService) Close

func (s *ShiftsService) Close(ctx context.Context, registerID string, opts ...CallOption) (*Task, error)

Close закриває поточну зміну каси registerID: однією операцією формує Z-звіт і документ закриття — обидва в Result.ZReport і Result.ShiftClose.

func (*ShiftsService) Open

func (s *ShiftsService) Open(ctx context.Context, registerID string, params *OpenShiftParams, opts ...CallOption) (*Task, error)

Open відкриває зміну на касі registerID. Якщо каса не в режимі ShiftManual, крок можна пропустити — перший чек відкриє зміну сам. params може бути nil. Завдання, режими і ключ ідемпотентності — як у ReceiptsService.Create.

type SystemService

type SystemService service

SystemService — службові маршрути: версія сервісу, дозволи токена, режим роботи з ДПС.

func (*SystemService) DPS

func (s *SystemService) DPS(ctx context.Context) (*DPSStatus, error)

DPS повертає поточний режим роботи сервісу з ДПС; доступний будь-якому машинному токену.

func (*SystemService) Version

func (s *SystemService) Version(ctx context.Context) (string, error)

Version повертає версію збірки сервісу: "dev" у локальній збірці, інакше тег релізу ("v0.3.0"). Маршрут не потребує токена.

func (*SystemService) WhoAmI

func (s *SystemService) WhoAmI(ctx context.Context) (*Identity, error)

WhoAmI повертає клієнта і дозволи токена — найпростіший спосіб перевірити, що токен дійсний.

type Tariff

type Tariff struct {
	PlanID          string  `json:"plan_id"`
	PricePerReceipt Kopecks `json:"price_per_receipt"`
}

Tariff — тариф, за яким рахували.

type Task

type Task struct {
	// ID — ідентифікатор завдання; за ним опитують [TasksService.Get].
	ID         string     `json:"task_id"`
	Type       TaskType   `json:"type"`
	Status     TaskStatus `json:"status"`
	CreatedAt  time.Time  `json:"created_at"`
	FinishedAt time.Time  `json:"finished_at,omitzero"`
	// Error — текст помилки завдання; структурований опис — у Fault.
	Error  string      `json:"error,omitempty"`
	Fault  *Fault      `json:"fault,omitempty"`
	Result *TaskResult `json:"result,omitempty"`
}

Task — завдання фіскального конвеєра: у нього перетворюється кожна фіскальна операція (чек, зміна, офлайн-сесія).

func (*Task) Done

func (t *Task) Done() bool

Done повідомляє, чи завершилося завдання — успішно або помилкою.

type TaskResult

type TaskResult struct {
	// CashRegisterID — каса, на якій виконано завдання.
	CashRegisterID string `json:"prro_id,omitempty"`
	// ShiftID — зміна, у межах якої видано документи завдання.
	ShiftID string `json:"shift_id,omitempty"`
	// ShiftNumber — наскрізний номер зміни в межах каси.
	ShiftNumber int64 `json:"shift_number,omitempty"`
	// Testing — документи тестові: каса в режимі test.
	Testing bool `json:"testing,omitempty"`

	Receipt        *DocResult            `json:"receipt,omitempty"`
	ShiftOpen      *DocResult            `json:"shift_open,omitempty"`
	ZReport        *DocResult            `json:"zreport,omitempty"`
	ShiftClose     *DocResult            `json:"shift_close,omitempty"`
	OfflineEnd     *DocResult            `json:"offline_end,omitempty"`
	OfflineAbandon *OfflineAbandonResult `json:"offline_abandon,omitempty"`
	Reconcile      *ReconcileReport      `json:"reconcile,omitempty"`
}

TaskResult — результат завдання. Заповнені лише поля, що стосуються його типу: Receipt — для чека, ShiftOpen — для відкриття зміни, ZReport і ShiftClose — для закриття тощо.

type TaskStatus

type TaskStatus string

TaskStatus — стан завдання.

const (
	TaskPending    TaskStatus = "pending"    // у черзі
	TaskProcessing TaskStatus = "processing" // виконується
	TaskSucceeded  TaskStatus = "succeeded"  // завершено успішно, результат у Result
	TaskFailed     TaskStatus = "failed"     // завершено помилкою, опис у Fault
)

Стани завдання.

type TaskType

type TaskType string

TaskType — операція завдання.

const (
	TaskReceipt               TaskType = "receipt"                 // розрахунковий документ
	TaskOpenShift             TaskType = "open_shift"              // відкриття зміни
	TaskCloseShift            TaskType = "close_shift"             // Z-звіт і закриття зміни
	TaskCloseOfflineSession   TaskType = "close_offline_session"   // завершення офлайн-сесії
	TaskAbandonOfflineSession TaskType = "abandon_offline_session" // відмова від офлайн-сесії
	TaskSyncRegister          TaskType = "sync_register"           // звіряння з ДПС
)

Типи завдань.

type TasksService

type TasksService service

TasksService — стан і результат завдань.

func (*TasksService) Get

func (s *TasksService) Get(ctx context.Context, id string) (*Task, error)

Get повертає завдання в поточному стані. Завдання, що завершилося помилкою, — це успішна відповідь зі Status == TaskFailed, а не помилка.

func (*TasksService) Wait

func (s *TasksService) Wait(ctx context.Context, id string) (*Task, error)

Wait опитує завдання, доки воно не завершиться, з паузою, що зростає від 0,5 до 5 секунд. Межу очікування задає ctx.

Завдання, що завершилося помилкою, повертається разом із *Error, як у синхронній відповіді: errors.Is(err, ErrTaskFailed), опис збою — у Error.Fault.

type UpdateWebhookParams

type UpdateWebhookParams struct {
	// URL — новий абсолютний http(s)-URL приймача.
	URL string `json:"url,omitempty"`
	// Events — новий перелік подій. nil — без змін; порожній, але не nil
	// зріз []WebhookEvent{} — підписка на всі події.
	Events []WebhookEvent `json:"events,omitzero"`
	// Active — false призупиняє доставку, не втрачаючи черги; true
	// відновлює. nil — без змін.
	Active *bool `json:"active,omitempty"`
}

UpdateWebhookParams — зміни вебхука; незаповнені поля не змінюються.

type UsageParams

type UsageParams struct {
	// From — початок періоду, включно.
	From Date
	// To — кінець періоду, не включно. Період понад 366 днів — 422.
	To Date
}

UsageParams — період підсумку тарифікації. Порожні межі — поточний календарний місяць за UTC.

type WebhookDelivery

type WebhookDelivery struct {
	// ID — ідентифікатор доставки; його передають у
	// [WebhooksService.Replay].
	ID string `json:"id"`
	// Event — тип події; крім підписних, буває webhook.ping і system.dps_*.
	Event    WebhookEvent   `json:"event"`
	Status   DeliveryStatus `json:"status"`
	Attempts int            `json:"attempts"`
	// CashRegisterID — каса, якої стосується подія; порожній у подій рівня
	// клієнта.
	CashRegisterID string `json:"cash_register_id,omitempty"`
	// Sequence — номер події в межах каси (поле sequence конверта); за ним
	// упорядковують події. 0 у подій рівня клієнта.
	Sequence int64 `json:"sequence,omitempty"`
	// Data — корисне навантаження події.
	Data json.RawMessage `json:"data"`
	// LastError — чим завершилася остання невдала спроба.
	LastError     string    `json:"last_error,omitempty"`
	NextAttemptAt time.Time `json:"next_attempt_at,omitzero"`
	CreatedAt     time.Time `json:"created_at"`
	DeliveredAt   time.Time `json:"delivered_at,omitzero"`
}

WebhookDelivery — одна доставка події та її стан.

type WebhookEndpoint

type WebhookEndpoint struct {
	ID string `json:"id"`
	// URL — абсолютний http(s)-URL приймача.
	URL string `json:"url"`
	// Events — події підписки; порожній перелік — усі події.
	Events []WebhookEvent `json:"events"`
	// Active — доставка ввімкнена; false призупиняє її, не втрачаючи черги.
	Active    bool      `json:"active"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

WebhookEndpoint — точка доставки подій: куди слати й на які саме.

type WebhookEvent

type WebhookEvent string

WebhookEvent — тип події вебхука.

const (
	// EventTaskCompleted — завдання завершилося успішно.
	EventTaskCompleted WebhookEvent = "task.completed"
	// EventTaskFailed — завдання завершилося помилкою.
	EventTaskFailed WebhookEvent = "task.failed"
	// EventShiftOpened — зміну відкрито.
	EventShiftOpened WebhookEvent = "shift.opened"
	// EventShiftClosed — зміну закрито.
	EventShiftClosed WebhookEvent = "shift.closed"
	// EventKeyExpiring — сертифікат ключа КЕП спливає протягом 30 днів;
	// раз на добу.
	EventKeyExpiring WebhookEvent = "key.expiring"
	// EventRegisterOffline — каса перейшла в офлайн-сесію.
	EventRegisterOffline WebhookEvent = "register.offline"
	// EventRegisterOnline — каса повернулася онлайн.
	EventRegisterOnline WebhookEvent = "register.online"
	// EventRegisterOfflineLimit — наближення до законних меж офлайн-сесії
	// (36 і 168 годин).
	EventRegisterOfflineLimit WebhookEvent = "register.offline_limit"
	// EventRegisterOfflineAbandoned — від офлайн-сесії відмовлено; у даних —
	// документи, яких ДПС не отримала.
	EventRegisterOfflineAbandoned WebhookEvent = "register.offline_abandoned"
	// EventRegisterRemediated — сервіс сам усунув розбіжність із ДПС.
	EventRegisterRemediated WebhookEvent = "register.remediated"
	// EventRegisterNeedsAttention — розбіжності не усуваються самі, на касу
	// має поглянути людина.
	EventRegisterNeedsAttention WebhookEvent = "register.needs_attention"
	// EventClientBalanceLow — баланс опустився нижче порога; попередження
	// перед тим, як чеки почнуть відхилятися з 402.
	EventClientBalanceLow WebhookEvent = "client.balance_low"
	// EventReceiptRegistered — зареєстровано чек (продаж, повернення, сторно,
	// службове внесення чи видача) з повним вмістом: позиції, оплати,
	// податки — у тому вигляді, в якому його отримала ДПС.
	EventReceiptRegistered WebhookEvent = "receipt.registered"
)

Події, на які можна підписатися.

const (
	// EventPing — тестова відправка з кабінету.
	EventPing WebhookEvent = "webhook.ping"
	// EventDPSOffline — сервіс перейшов в офлайн-режим роботи з ДПС.
	EventDPSOffline WebhookEvent = "system.dps_offline"
	// EventDPSOnline — сервіс повернувся в онлайн-режим роботи з ДПС.
	EventDPSOnline WebhookEvent = "system.dps_online"
	// EventDPSFlapping — режим роботи з ДПС часто перемикається.
	EventDPSFlapping WebhookEvent = "system.dps_flapping"
	// EventDPSModeChanged — режим роботи з ДПС задано вручну.
	EventDPSModeChanged WebhookEvent = "system.dps_mode_changed"
)

Зарезервовані події: на них не підписуються, але доставка може їх нести.

type WebhookList added in v0.2.0

type WebhookList struct {
	// Webhooks — точки доставки; секрети не повертаються.
	Webhooks []WebhookEndpoint `json:"webhooks"`
	// Limit — скільки вебхуків дозволено: кількість кас клієнта плюс один.
	Limit int `json:"limit"`
	// Used — скільки вебхуків зареєстровано, включно з призупиненими.
	Used int `json:"used"`
}

WebhookList — вебхуки клієнта і ліміт їхньої кількості.

type WebhooksService

type WebhooksService service

WebhooksService — реєстрація вебхуків і історія доставок.

func (*WebhooksService) Create

Create реєструє вебхук. Доставка — POST із конвертом {delivery_id, event, attempt, occurred_at, data} і підписом у заголовку X-Signature; гарантія — «щонайменше один раз», тож приймач відкидає повтори за delivery_id. Секрет у відповіді повертається рівно один раз.

Вебхуків може бути не більше, ніж кас у клієнта, плюс один; призупинені теж рахуються. Понад ліміт — ErrWebhookLimitReached, а поточні limit і used — у Error.Details.

func (*WebhooksService) Delete

func (s *WebhooksService) Delete(ctx context.Context, id string) error

Delete видаляє вебхук id; недоставлені події переходять у dead.

func (*WebhooksService) Deliveries

func (s *WebhooksService) Deliveries(ctx context.Context, id string, params *ListDeliveriesParams) ([]WebhookDelivery, error)

Deliveries повертає історію доставок вебхука id, від найновішої; params може бути nil. Доставлені зберігаються 30 днів, невдалі (dead) — 14 днів від останньої спроби; старіші зникають з історії.

func (*WebhooksService) List

func (s *WebhooksService) List(ctx context.Context) (*WebhookList, error)

List повертає вебхуки клієнта разом із лімітом: поки Used < Limit, можна створити ще один.

func (*WebhooksService) Replay

func (s *WebhooksService) Replay(ctx context.Context, id, deliveryID string) (*WebhookDelivery, error)

Replay повертає доставку deliveryID вебхука id у чергу з новим запасом спроб; спроба — одразу. Доступно, поки доставка є в історії: невдала — 14 днів від останньої спроби, далі — ErrNotFound. Події, доставлені тим часом, не повторюються: ця прийде після них, тож упорядковуйте події за Sequence. Якщо саме зараз триває спроба доставки — 409 (Code == "delivery_in_flight").

func (*WebhooksService) Update

Update змінює URL, підписку або активність вебхука id. На час ремонту свого приймача вимикайте вебхук (Active: new(false)), а не видаляйте: видалення переводить недоставлене в dead.

Directories

Path Synopsis
examples
async command
Асинхронний режим: виклик повертає завдання одразу, не тримаючи з'єднання до відповіді ДПС, а результат забирають опитуванням (або вебхуком — див.
Асинхронний режим: виклик повертає завдання одразу, не тримаючи з'єднання до відповіді ДПС, а результат забирають опитуванням (або вебхуком — див.
quickstart command
Швидкий старт: перший чек на касі в режимі test — безкоштовно і без реєстрації в податковій.
Швидкий старт: перший чек на касі в режимі test — безкоштовно і без реєстрації в податковій.
refund command
Повернення: чек повернення посилається на початковий чек продажу.
Повернення: чек повернення посилається на початковий чек продажу.
smoke command
Димова перевірка: викликає всі маршрути читання API і нічого не створює.
Димова перевірка: викликає всі маршрути читання API і нічого не створює.
webhook command
Приймач вебхуків: перевіряє підпис, відкидає повтори доставок і реагує на події чеків, каси і балансу.
Приймач вебхуків: перевіряє підпис, відкидає повтори доставок і реагує на події чеків, каси і балансу.
Package webhook — приймач вебхуків PRRO.cloud: перевірка підпису, розбір конверта доставки і типізовані дані подій.
Package webhook — приймач вебхуків PRRO.cloud: перевірка підпису, розбір конверта доставки і типізовані дані подій.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL