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

Для розробників: довідник API

REST API порталу та національний інтерфейс SAPI-SK 1.0: автентифікація, компанії, документи, вебхуки, помилки та ліміти.

Вступ

API Verteco це REST поверх HTTPS. Запит і відповідь мають формат JSON (UTF-8). Почніть зі створення облікового запису, потім API-токена, і зробіть перший виклик протягом хвилини. Усі шляхи вказано відносно базової URL-адреси нижче.

Повне тестове середовище (sandbox) доступне на test.peppol.verteco.digital. Воно поводиться так само, як продуктивне середовище, і додатково пропонує тестові інструменти (вебхук Фінансової адміністрації Словаччини (Finančná správa, FS), верифікаційний токен (Verifikačný údaj), видалення компанії) та симульований вибір постачальника замість порталу FS (VPDS).

Base URL
https://peppol.verteco.digital/api/v1
Версія
v1 (у шляху). Зворотно несумісні зміни виходитимуть під новою версією.
Протокол
HTTPS only · TLS 1.2+ · TLS A+
Формат
application/json (UTF-8)
Автентифікація
cookie-сесія (портал) або Bearer-токен (server-to-server)
Часові мітки
ISO-8601 (UTC), напр. 2026-06-03T09:40:27Z

Сертифікований AP

Справжній Peppol Access Point (Seat ID PSK001128), а не реселер. Ми пройшли тести відповідності OpenPeppol (19/19) і працюємо в продуктивному режимі.

Валідні документи

Серверна валідація EN 16931 + Peppol BIS 3.0 Schematron кожного отриманого ТА відправленого документа. Документ можна перевірити й заздалегідь: публічний валідатор працює на /validator (і як API на POST /api/v1/public/peppol-validate); помилки повертаються з конкретним правилом (напр. BR-CO-15).

Multi-tenant

Один обліковий запис і один токен для N компаній, ідеально для SaaS, ERP і бухгалтерів.

SK TDD автоматично

Податковий звіт (corner-5 / TDD) до Фінансової адміністрації (FS) ми генеруємо та надсилаємо за Вас.

Машинозчитуваний інтерфейс (OpenAPI 3.1): /api/v1/openapi.json. Імпортуйте його в Postman, відкрийте у Swagger Editor або згенеруйте типізований клієнт будь-якою мовою (TS, Java, PHP, Python…) за допомогою openapi-generator. Він охоплює як API порталу, так і SAPI-SK.

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

Обліковий запис і API-токен Ви створюєте в порталі (через браузер). Далі інтеграція працює виключно через API-токен. Вашому застосунку не потрібно обробляти реєстрацію, вхід чи паролі.

  1. 1

    Створіть обліковий запис у порталі

    Зареєструйтеся за допомогою електронної пошти і підтвердьте її за посиланням з електронного листа.
  2. 2

    Згенеруйте API-токен

    У порталі перейдіть до API tokeny → Vytvoriť (API-токени → Створити). Токен vpt_… показується лише один раз. Зберігайте його надійно.
  3. 3

    Зробіть перший виклик

    Використайте токен у заголовку Authorization:
    javascript
    const res = await fetch('https://peppol.verteco.digital/api/v1/companies', {
    headers: { Authorization: 'Bearer vpt_8f2a…' },
    });
    const companies = await res.json();

Тестове середовище (sandbox)

Тестові документи автоматично видаляються через 60 днів: середовище призначене для випробувань, а не для архівування. На продуктивний портал цей термін зберігання не поширюється.

Окрім SAPI mock sandbox (нижче), ми також підтримуємо повнофункціональне тестове середовище, повну копію цього порталу з окремими даними, де можна випробувати весь процес (реєстрація → компанія → відправлення → отримання → сповіщення) від початку до кінця без жодного впливу на продуктивне середовище.

Реєстрація
без листа з підтвердженням; обліковий запис можна використовувати одразу
Схвалення компанії
автоматичне, безпосередньо в інтерфейсі або через API; немає вибору постачальника на порталі Фінансової адміністрації Словаччини (Finančná správa, FS) і немає eID; одразу після створення компанії з номером платника ПДВ (IČ DPH) Ви можете як відправляти, так і отримувати
Реєстрація в мережі
автоматична, до тестової мережі Peppol. Зверніть увагу на два рівні ідентифікатора: API і портал використовують той самий формат, що й продуктивне середовище (peppolParticipantId = 0245:<цифри DIČ>, де DIČ це словацький податковий ідентифікаційний номер; Ваш інтеграційний код не змінюється); у тестових SMP/SML компанія технічно реєструється як 9950:SK<DIČ>, оскільки схема 0245 вимагає верифікаційного коду Фінансової адміністрації, якого в тестовому середовищі не існує. У продуктивному середовищі 0245:<цифри DIČ> реєструється в робочій мережі Peppol лише після вибору постачальника через eID
Валідація
реальна: правила EN 16931 + Peppol BIS 3.0, ті самі, що й у продуктивному середовищі
Доставка
симульована: документ ніколи не залишає тестовий сервер; якщо отримувач (номер платника ПДВ) існує в тестовому середовищі, рахунок доставляється йому як отриманий (включно з електронним листом, PDF і вебхуком)
Підтвердження доставки (MLS)
симульоване, явно позначене як SANDBOX
Електронні листи
справді надсилаються (на адреси, які Ви вводите), з префіксом [TEST]
Ціна
безкоштовно, без обмежень для тестування

Усе, що працює тут, працює і там: портал, REST API, SAPI-SK 1.0, плагіни для інтернет-магазинів і вебхуки. Достатньо змінити домен у Вашій інтеграції на test.peppol.verteco.digital і використовувати токени, створені в тестовому середовищі. Ідеально для розробки інтеграції, CI-тестів і навчання бухгалтерів перед продуктивним запуском.

Примітка: захист периметра (edge) тестового домену блокує загальні заголовки User-Agent: Python-urllib і User-Agent: Java/1.8.x (стандартний User-Agent HttpsURLConnection у Java 8) відповіддю HTTP 403 "error code: 1010" ще до того, як запит дійде до нашого API; продуктивний домен peppol.verteco.digitalїх пропускає. Встановіть власний User-Agent: у Java або прапорцем JVM -Dhttp.agent=my-app/1.0 (без зміни коду; Java додає "Java/1.8", і результат "my-app/1.0 Java/1.8.0_xxx" проходить, блокується лише заголовок, що починається з "Java/1.8"), або на з'єднанні через conn.setRequestProperty("User-Agent", "my-app/1.0"). Поширені клієнти (requests, httpx, Java 11+, Apache HttpClient, okhttp, axios, Go, PHP, curl) працюють без змін.

Чому компанії схвалюються автоматично

Фінансова адміністрація не має тестового середовища для порталу VPDS: вибір постачальника на vpds.financnasprava.sk працює лише в продуктивному середовищі та перевіряється через slovensko.sk (eID), тому в продуктивному середовищі Ви не можете «обрати» довільну компанію, яка не є Вашою. Щоб Ви все ж могли протестувати свою інтеграцію, у тестовому середовищі ми симулюємо цей крок: кожна створена Вами компанія схвалюється автоматично (без вибору у FS), тож Ви можете налаштувати як відправника, так і отримувача та пройти весь процес.

Для тестування вебхуків FS (вибір постачальника) ми маємо власний аналог інструменту Фінансової адміністрації: test.peppol.verteco.digital/sandbox-nastroje. Там можна згенерувати валідний верифікаційний токен (Verifikačný údaj) у стилі FS і надіслати повний вебхук на Ваш endpoint, точно так, як це робить портал FS під час реального вибору. Компанії, створені для тестування, натомість можна зняти з реєстрації (з порталу та з тестового SMP), саме через відсутність тестового режиму на боці Фінансової адміністрації.

Тестове середовище не є частиною робочої мережі Peppol: компанії реєструються в окремій тестовій мережі (тестові SMP/SML), ніщо не надсилається на реальні endpoint-и, а його дані можуть бути стерті в будь-який момент. Не використовуйте його для реальних рахунків; для них продуктивне середовище працює на peppol.verteco.digital, де реєстрацію в робочій мережі розблоковує вибір постачальника на порталі Фінансової адміністрації, підтверджений через eID.

Автентифікація

Ваша інтеграція автентифікується за допомогою API-токена в заголовку Authorization: Bearer vpt_…. Токен Ви створюєте в порталі (API-токени); він має формат vpt_ + 40 hex-символів, ми зберігаємо лише його SHA-256 хеш, і він має той самий доступ, що і Ваш обліковий запис. Перевірте його через /auth/me:

curl
curl https://peppol.verteco.digital/api/v1/auth/me -H 'Authorization: Bearer vpt_8f2a…'
# 200 → { "id": "…", "email": "vy(at)firma.sk" }   (token works)

Якщо токен відсутній або недійсний, API повертає:

json
// 401 Unauthorized
{ "error": "unauthorized", "message": "Authentication required" }
Портал (браузер) використовує внутрішню cookie-сесію (portal_session, JWT, 7 днів); для інтеграції server-to-server вона Вам не потрібна. Публічними без автентифікації є /ping, /openapi.json та endpoint-и під /public/* (перевірка peppol-check, валідатор peppol-validate, докладніше в розділі Публічні інструменти, і стан сервісу через status); усе інше вимагає сесії або Bearer-токена.

Конвенції та формати

ТипФорматПриклад
idUUID (string)08dd6c1e-…
часові міткиISO-8601 Instant (UTC)2026-06-03T09:40:27Z
issueDateдата (YYYY-MM-DD)2026-06-03
totalAmountдесяткове число120.00
відсутні значенняnull (а не пропущене поле)"dic": null

Пагінація та ідемпотентність

/companies і /companies/{id}/documents підтримують опціональні ?page&limit (відповідь залишається JSON-масивом; загальна кількість міститься в заголовках X-Total-Count / X-Total-Pages). Без параметрів вони повертають увесь масив, документи відсортовані за createdAt за спаданням; /tokens завжди повертає увесь масив. Заголовок Idempotency-Key підтримує національний інтерфейс SAPI-SK на POST /sapi/document/send; для програмного відправлення використовуйте саме його.

Помилки

Помилки мають єдину структуру з машинозчитуваним кодом error. Помилки валідації додають мапу fields (перша помилка для кожного поля).

json
// business error
{ "error": "invalid_credentials", "message": "Invalid email or password" }

// validation error (400); field messages are returned in Slovak ("IČO musí byť 8 číslic" = "IČO must be 8 digits")
{ "error": "validation_failed", "message": "Some fields are invalid",
"fields": { "ico": "IČO musí byť 8 číslic" } }

HTTP-статуси

200 / 201 / 204
успіх (OK / Created / No Content)
400
недійсні вхідні дані (див. error / fields)
401
відсутня або недійсна автентифікація
403
недостатньо прав (роль)
404
ресурс не існує або Ви не маєте до нього доступу
405
HTTP-метод не підтримується для цього шляху
409
конфлікт (IČO / електронна адреса вже існує)
415
непідтримуваний Content-Type (XML endpoint-и очікують application/xml)
429
перевищено ліміт запитів (заголовки RateLimit-* і Retry-After, тіло JSON rate_limited)
Наше API завжди відповідає JSON із полем error. Відповідь без JSON-тіла (HTML або текст, як error code: 1010 зі статусом 403, або 502/504 під час розгортання) надійшла не від API, а від інфраструктури перед ним (захист периметра, шлюз). Типова причина 403/1010: загальний User-Agent бібліотеки (Python-urllib, Java/1.8.x на тестовому домені); рішення описано в розділі Тестове середовище.

Повний каталог помилок

КодHTTPКоли
validation_failed400тіло не пройшло валідацію (див. fields)
unauthorized401відсутній або недійсний API-токен
forbidden403дія вимагає ролі owner/admin
company_not_found404компанія не існує або Ви не є її учасником
ico_taken409компанія з таким IČO (реєстраційним номером компанії) вже існує
ico_immutable400IČO не можна змінити
company_dic_missing400верифікація для відправлення без DIČ компанії (словацького податкового ідентифікаційного номера)
token_invalid400верифікаційний токен (Verifikačný údaj, підпис) не збігається
document_not_found404документ не існує
token_not_found404API-токен не існує / не належить Вам
rate_limited429надто багато запитів

Ліміти запитів (rate limit)

API захищене обмеженням частоти запитів у 60-секундному вікні (на інстанс). Ліміт і залишок квоти повертаються в кожній відповіді через заголовки; при перевищенні API повертає 429 Too Many Requests із Retry-After.

Звичайні виклики
динамічний ліміт із великим запасом, на API-токен (або сесію, інакше IP); поточне значення повертається в заголовку RateLimit-Limit
Auth (/auth/*)
суворіший ліміт на IP (захист від brute-force; крім /auth/me і /auth/logout)
RateLimit-Limit
ліміт у вікні
RateLimit-Remaining
скільки запитів залишилося
RateLimit-Reset
секунд до скидання вікна
Retry-After
секунд до наступної спроби (при 429)
http
HTTP/2 429 Too Many Requests
RateLimit-Limit: <limit in the window>
RateLimit-Remaining: 0
RateLimit-Reset: 37
Retry-After: 37

{ "error": "rate_limited", "message": "Too many requests. Slow down." }

API-токени

Непрозорі (opaque) токени vpt_… для доступу server-to-server. Відкритий текст показується лише один раз при створенні. Збережіть його. Ми зберігаємо лише SHA-256 хеш і 12-символьний префікс для відображення.

GET/tokenssession / token

Список Ваших активних токенів (без секрету), createdAt за спаданням.

POST/tokenssession / token

Створює токен; повертає відкритий текст (лише один раз).

ПолеТипОбовʼязковеОпис
namestringтакназва токена, макс. 128
curl
curl -X POST https://peppol.verteco.digital/api/v1/tokens -b cookies.txt \
-H 'Content-Type: application/json' -d '{"name":"moja-appka"}'
# 201 Created
{ "id":"…","name":"moja-appka","token":"vpt_8f2a…","prefix":"vpt_8f2a3b…","createdAt":"…" }
DELETE/tokens/{id}session / token

Відкликає токен. Повертає 204.

Помилки: token_not_found (404)

Компанії

Компанії, ідентифіковані за реєстраційним номером (IČO) / номером платника ПДВ (IČ DPH), якими Ви керуєте. Доступ залежить від членства: Ви бачите лише компанії, учасником яких є. Творець компанії стає її owner.

GET/companiessession / token

Список компаній, учасником яких Ви є (з Вашою роллю).

POST/companiessession / token

Додає компанію; Ви стаєте її owner, status = pending_verification.

ПолеТипОбовʼязковеОпис
icostringтакрівно 8 цифр
dicstringтакформат SK + 10 цифр (напр. SK2121358349)
legalNamestringтакюридична (комерційна) назва, макс. 500
registeredAddressstringніадреса зареєстрованого офісу, макс. 1000
curl
curl -X POST https://peppol.verteco.digital/api/v1/companies \
-H 'Authorization: Bearer vpt_8f2a…' -H 'Content-Type: application/json' \
-d '{"ico":"53412834","dic":"SK2121358349","legalName":"Verteco digital services, s. r. o."}'

# 201 Created
{ "id":"08dd…","ico":"53412834","dic":"SK2121358349","legalName":"…",
"registeredAddress":null,"peppolParticipantId":null,
"status":"pending_verification","role":"owner","createdAt":"2026-06-03T09:40:27Z" }

Помилки: ico_taken (409) · validation_failed (400)

GET/companies/{id}session / token

Деталі компанії (Ви маєте бути учасником).

PUT/companies/{id}owner / admin

Оновлює компанію. IČO незмінне (має дорівнювати наявному значенню).

Помилки: forbidden (403) · ico_immutable (400) · company_not_found (404)

Поле status

pending_verification
після створення; відправлення ще не розблоковано
active
верифікована, відправлення розблоковано

Роль учасника

owner
творець компанії (повний доступ)
admin
адміністратор (редагування, вебхуки, верифікація)
member
учасник (читання)
viewer
лише читання
Дії, позначені «owner / admin», доступні як ролі owner, так і admin (менеджер компанії).

Верифікація для відправлення (верифікаційний токен, Verifikačný údaj)

Перед відправленням компанію необхідно верифікувати за допомогою верифікаційного токена (Verifikačný údaj, VÚ), підписаного токена, який видає Фінансова адміністрація Словаччини (Finančná správa, FS). Після успішної верифікації status компанії змінюється на active і відправлення розблоковується.

POST/companies/{id}/verificationowner / admin

Самостійна верифікація верифікаційного токена (Verifikačný údaj). У разі успіху встановлює status на active.

ПолеТипОбовʼязковеОпис
tokenstringтакVÚ = hex-підпис (prod/pPFS 1024 hex, test/tPFS 768 hex)
curl
curl -X POST https://peppol.verteco.digital/api/v1/companies/{id}/verification \
-H 'Authorization: Bearer vpt_8f2a…' -H 'Content-Type: application/json' \
-d '{"token":"<1024-hex VÚ>"}'

# 200 OK
{ "companyId":"08dd…","status":"active","sendingVerified":true,
"verificationMethod":"self","verifiedAt":"2026-06-15T…Z" }

Помилки: company_dic_missing (400) · token_invalid (400) · forbidden (403)

Документи

Журнал документів Peppol (отриманих і відправлених) для компанії. Він наповнюється в міру того, як рахунки проходять через Access Point. Залежить від членства в компанії, відсортовано за createdAt за спаданням.

GET/companies/{id}/documentssession / token

Список документів компанії. Опціональний фільтр ?direction=sent|received.

curl
curl 'https://peppol.verteco.digital/api/v1/companies/{id}/documents?direction=received' \
-H 'Authorization: Bearer vpt_8f2a…'
# 200 OK
[ { "id":"…","direction":"received","peppolMessageId":"…","docTypeId":"…",
  "senderId":"0088:7300010000001","receiverId":"0245:2121358349",
  "invoiceNumber":"2026001","issueDate":"2026-06-03",
  "currency":"EUR","totalAmount":120.00,"status":"received","createdAt":"…" } ]
GET/companies/{id}/documents/{docId}session / token

Деталі одного документа.

Помилки: document_not_found (404)

GET/companies/{id}/documents/{docId}/downloadsession / token

Окремий HTML рахунка для друку. ?inline=1 → відображає в браузері, інакше завантажує.

Повертає text/html із Content-Disposition, де файл має назву faktura-<číslo>.html (číslo = номер рахунка).

SAPI-SK 1.0 (національний інтерфейс)

SAPI-SK це стандартизований національний REST-інтерфейс між клієнтською/ERP-системою та Access Point (sapi-sk.sk). Ми реалізуємо його повністю. Це означає, що Ви не залежите від нашої пропрієтарної форми API і пишете інтеграцію один раз для будь-якого SAPI-SK Access Point.

Base URL
https://peppol.verteco.digital/sapi
Автентифікація
OAuth2 client_credentials → короткостроковий access-токен (JWT)
client_id
UUID Вашого API-токена (наведений у розділі API-токени / dashboard)
client_secret
сам токен vpt_… з порталу
Версія
1.3 (10 операцій: 4× auth, 6× документи)
Access-токен SAPI підписаний окремим ключем (це ні портальний токен vpt_, ні сесія). Відкликання API-токена в порталі негайно робить недійсними як /auth/token, так і /auth/renew.

Sandbox (пробне середовище)

Хочете випробувати SAPI-SK без реєстрації і без жодного ризику? Використайте публічні облікові дані sandbox. Sandbox валідує запити точно так, як продуктивне середовище, але ніколи нічого не надсилає в мережу Peppol і не працює з реальними даними; він повертає реалістичні mock-відповіді. Ідеально для розробки, CI та онбордингу інтеграції.

client_id
sandbox
client_secret
sandbox
send
повна валідація контракту + mock 202 (ніщо не доставляється)
receive
1 зразковий документ sandbox-doc-0001 для тестування парсингу та acknowledge
curl
# 1) sandbox token (no registration required)
curl -X POST https://peppol.verteco.digital/sapi/auth/token \
-H 'Content-Type: application/json' \
-d '{ "client_id": "sandbox", "client_secret": "sandbox",
      "grant_type": "client_credentials" }'

# 2) mock send: it is validated, but NOTHING is actually delivered
curl -X POST https://peppol.verteco.digital/sapi/document/send \
-H 'Authorization: Bearer <sandbox access_token>' \
-H 'X-Peppol-Participant-Id: 0245:0000000000' \
-H 'Content-Type: application/json' \
-d '{ "metadata": { "documentId": "TEST-1",
        "documentTypeId": "urn:…::Invoice##…::2.1",
        "senderParticipantId": "0088:sandbox-sender",
        "receiverParticipantId": "0088:sandbox-receiver" },
      "payload": "<Invoice>…</Invoice>", "payloadFormat": "XML" }'
# 202 { "providerDocumentId": "sandbox-…", "status": "ACCEPTED", … }

# 3) sample inbox + detail of the sample document
curl https://peppol.verteco.digital/sapi/document/receive \
-H 'Authorization: Bearer <sandbox access_token>'
curl https://peppol.verteco.digital/sapi/document/receive/sandbox-doc-0001 \
-H 'Authorization: Bearer <sandbox access_token>'
Токени sandbox ізольовані: вони ніколи не доставляють у Peppol і ніколи не бачать реальних документів. Для реального відправлення використовуйте client_id/client_secret з порталу (нижче).

Автентифікація

POST/sapi/auth/tokenclient_credentials

Обмінює client_id + client_secret на access-токен (15 хв) і refresh-токен (30 днів). Збережіть токен і використовуйте його всі 15 хвилин: запит нового токена при кожному виклику є зайвими витратами (ліміт запитів враховує і виклики /auth/token).

curl
curl -X POST https://peppol.verteco.digital/sapi/auth/token \
-H 'Content-Type: application/json' \
-d '{ "client_id": "<token UUID>", "client_secret": "vpt_8f2a…",
      "grant_type": "client_credentials" }'
# 200 OK
{ "access_token": "eyJhbGciOi…", "token_type": "Bearer",
"expires_in": 900, "refresh_token": "eyJhbGciOi…" }

Помилки: SAPI-AUTH-001 (401) · SAPI-AUTH-003 (401: IP поза списком дозволених адрес ключа) · SAPI-VAL-001 (400)

GET/sapi/auth/token/statusBearer (access)

Дійсність і термін дії access-токена; should_refresh = true, коли залишається менше 3 хв.

POST/sapi/auth/renewrefresh token

Видає новий access + refresh-токен. Не вдається, якщо базовий API-токен було відкликано.

json
// body
{ "refresh_token": "eyJhbGciOi…" }
POST/sapi/auth/revoke

Завжди повертає успіх (RFC 7009). Постійний kill switch: відкликання API-токена в порталі.

Відправлення документа

POST/sapi/document/sendBearer (access)

Відправляє бізнес-документ Peppol (UBL / BIS 3.0) отримувачу через наш Access Point. Відправлення працює за принципом fail-closed: компанія має мати верифікований верифікаційний токен (Verifikačný údaj).

Обов'язкові заголовки:

ЗаголовокОпис
AuthorizationBearer <access_token>
X-Peppol-Participant-Idучасник, від імені якого Ви відправляєте (напр. 0245:2121358349, цифри DIČ (словацького податкового ідентифікаційного номера) без префікса "SK")
Idempotency-Keyунікальний ключ; повторний виклик повертає початковий результат
curl
curl -X POST https://peppol.verteco.digital/sapi/document/send \
-H 'Authorization: Bearer eyJ…' \
-H 'X-Peppol-Participant-Id: 0245:2121358349' \
-H 'Idempotency-Key: 7b1f0e2a-…' \
-H 'Content-Type: application/json' \
-d '{ "metadata": {
        "documentId": "INV-2026-001",
        "documentTypeId": "urn:…::Invoice##…::2.1",
        "processId": "urn:…:bis:billing:3.0",
        "senderParticipantId": "0245:2121358349",
        "receiverParticipantId": "0088:7300010000001",
        "creationDateTime": "2026-06-17T10:00:00Z" },
      "payload": "<Invoice …>…</Invoice>",
      "payloadFormat": "XML" }'
# 202 Accepted
{ "providerDocumentId": "…", "status": "ACCEPTED",
"receivedAt": "2026-06-17T10:00:01Z", "timestamp": "…" }
# when status is "REJECTED", the response also carries a "detail" field
# with the rejection reason (validation rules, e.g. BR-CO-15)
metadata vs. UBL: поля в metadata це маршрутизаційні та технічні поля: documentId це Ваш внутрішній ідентифікатор, а не номер рахунка. Бізнес-дані (номер рахунка cbc:ID, дата виставлення, термін оплати, дата постачання, валюта, сума) беруться безпосередньо з UBL payload; нічого з цього Ви не надсилаєте в metadata, і UBL завжди є джерелом істини для відображення в порталі та для вебхуків.

Помилки: SAPI-AUTH-002 (401) · SAPI-AUTH-003 (403) · SAPI-VAL-001 (400) · SAPI-PROC-001 (502) · SAPI-PROC-002 (503) · SAPI-PROC-500 (500: не повторюйте, повідомте correlation_id)

Отримання документів

GET/sapi/document/receiveBearer (access)

Список отриманих документів (найстаріші першими); метадані також містять invoiceNumber, тож документ можна ідентифікувати без завантаження payload. Query: ?pageToken, ?limit (макс. 200), ?status (received / acknowledged; без урахування регістру, будь-яке інше значення повертає помилку SAPI-VAL-001), ?invoiceNumber (точна відповідність cbc:ID), ?since і ?until (ISO-8601 instant; вікно за часом отримання, напр. документи за останні 5 днів, масове завантаження для зовнішнього архівування або відновлення бухгалтерського обліку), ?deliveryDateFrom і ?deliveryDateTo (ISO-8601 date; фільтр за датою постачання, вказаною в документі). Заголовок X-Peppol-Participant-Id обов'язковий.

json
// 200 OK
{ "documents": [ { "documentId":"…","documentTypeId":"…",
  "senderParticipantId":"0088:…","receiverParticipantId":"0245:…",
  "creationDateTime":"2026-06-17T…Z" } ],
"nextPageToken": "50" }
GET/sapi/document/receive/{documentId}Bearer (access)

Деталі включно з payload (сирий XML, точно так, як він надійшов через Peppol).

Помилки: SAPI-RES-001 (404) · SAPI-RES-002 (404: payload не архівовано)

POST/sapi/document/receive/{documentId}/acknowledgeBearer (access)

Підтверджує, що Ваша система прийняла документ. Ідемпотентний.

Стан відправлених документів

GET/sapi/discovery?receiverId=0245:2121358349

Попередня перевірка перед відправленням: чи зареєстровано отримувача в мережі Peppol і які типи документів він може отримувати? Той самий SML/SMP lookup, який виконує Access Point; receiverId приймає Peppol ID, номер платника ПДВ (IČ DPH) або сам DIČ. Відповідь: {registered, participantId, smp, documentTypes, checkedAt}. Заголовок X-Peppol-Participant-Id тут не потрібен.

GET/sapi/document/sentBearer (access)

Стан доставки відправлених документів: pending (передається мережі) → submitted → delivered / rejected (підтверджено підтвердженням доставки (MLS) від AP отримувача); failed = транспортна помилка (повторна спроба з тим самим Idempotency-Key відправляє знову). Query: ?pageToken, ?limit, ?status (pending / submitted / sent / delivered / rejected / failed; без урахування регістру, будь-яке інше значення повертає помилку SAPI-VAL-001), ?invoiceNumber (точна відповідність cbc:ID: стан конкретного рахунка одним викликом), ?since і ?until (ISO-8601 instant; часове вікно), ?deliveryDateFrom і ?deliveryDateTo (ISO-8601 date; фільтр за датою постачання).

json
// 200 OK
{ "documents": [ {
  "documentId": "…",
  "receiverParticipantId": "0245:1084695645",
  "peppolMessageId": "befc9112-…",
  "status": "delivered",
  "statusDateTime": "2026-07-09T14:52:31Z",
  "creationDateTime": "2026-07-09T14:52:12Z" } ],
"nextPageToken": null }

Помилки: SAPI-AUTH-002 (401) · SAPI-AUTH-003 (403) · SAPI-VAL-001 (400: недійсний since)

Пакетне відправлення

POST/sapi/document/batchBearer (access)

До 100 документів в одному виклику. Кожен елемент проходить повну логіку одиночного відправлення (ідемпотентність через itemId + idempotencyKey, резервування, submit, вердикт) і повертає власний результат; збій одного елемента не зупиняє інші. Елементи обробляються послідовно; невдалі елементи повторюйте з тим самим idempotencyKey.

json
// request
{ "documents": [ {
  "itemId": "fa-2026-001",
  "idempotencyKey": "fa-2026-001",
  "metadata": { "documentId": "2026001", "documentTypeId": "…", "processId": "…",
                "senderParticipantId": "0245:2121358349", "receiverParticipantId": "0245:1084695645" },
  "payload": "<Invoice …>", "payloadFormat": "XML" } ] }

// 202 Accepted
{ "total": 2, "accepted": 1, "rejected": 1, "failed": 0,
"results": [
  { "itemId": "fa-2026-001", "ok": true,  "providerDocumentId": "…", "status": "ACCEPTED" },
  { "itemId": "fa-2026-002", "ok": false, "errorCode": "SAPI-AUTH-003", "errorMessage": "…" } ] }

Помилки: SAPI-AUTH-002 (401) · SAPI-AUTH-003 (403) · SAPI-VAL-001 (400: порожній або надто великий список)

Модель помилок

Усі помилки SAPI мають єдину обгортку з категорією, стабільним кодом, прапорцем retryable і correlation_id для служби підтримки.

json
{ "error": {
  "category": "AUTH",
  "code": "SAPI-AUTH-001",
  "message": "Invalid client credentials.",
  "retryable": false,
  "correlation_id": "b4191dfc-…" } }
Примітка: під час відправлення ми доставляємо бізнес-документ; сторона C2 податкового звітування (TDD) для відправлених документів у підготовці. Податкове звітування при отриманні (C3) генерується та подається до Фінансової адміністрації Словаччини (Finančná správa, FS) автоматично.

Сповіщення та вебхуки

Про отриманий рахунок ми можемо повідомити компанію електронною поштою або вебхуком (POST на Вашу URL-адресу). Доставка надійна (durable): сповіщення зберігається у вихідній черзі та доставляється асинхронно (тайм-аут 15 с); у разі збою ми повторюємо до 8 разів з експоненційною затримкою (30 с → макс. 1 год), потім dead-letter. Отже, збій Вашого сервера не втрачає сповіщення; ми доставимо його при наступній спробі. Захист від SSRF блокує loopback/локальні адреси; URL вебхука має бути публічною.

GET/companies/{id}/notificationssession / token

Налаштування сповіщень: { webhookUrl, notificationEmail, hasSecret }.

PUT/companies/{id}/notificationsowner / admin

Встановлює обидва канали (порожній рядок вимикає відповідний канал).

ПолеТипОбовʼязковеОпис
webhookUrlstringніпорожньо або http(s) URL, макс. 512
notificationEmailstringнідійсна електронна адреса, макс. 256
GET/companies/{id}/webhooksession / token

Конфігурація вебхука: { url, hasSecret } (без секрету).

PUT/companies/{id}/webhookowner / admin

Встановлює URL вебхука (автоматично генерує секрет для підпису, якщо його ще немає).

ПолеТипОбовʼязковеОпис
urlstringтакhttp(s) URL, макс. 512
curl
curl -X PUT https://peppol.verteco.digital/api/v1/companies/{id}/webhook \
-H 'Authorization: Bearer vpt_8f2a…' -H 'Content-Type: application/json' \
-d '{"url":"https://vas-system.sk/peppol/webhook"}'
# 200 OK { "url":"https://vas-system.sk/peppol/webhook", "hasSecret": true }
DELETE/companies/{id}/webhookowner / admin

Видаляє як URL вебхука, так і секрет. Повертає 204.

POST/companies/{id}/webhook/secretowner / admin

Генерує новий секрет для підпису та повертає його ОДИН РАЗ; збережіть його для перевірки X-Verteco-Signature.

json
// 200 OK
{ "secret": "vpt_8f2a…" }
POST/companies/{id}/webhook/testowner / admin

Синхронно надсилає тестове сповіщення (подія webhook.test, підписана, із захистом від SSRF) на збережену URL і повертає, ЩО було надіслано і ЩО повернулося. Те саме запускає кнопка „Otestovať webhook“ (Тестувати вебхук) у деталях компанії.

json
// 200 OK
{
"sent":     { "url": "https://vas-system.sk/peppol/webhook", "event": "webhook.test",
              "signed": true, "payload": "{…}" },
"received": { "status": 200, "body": "OK", "durationMs": 142, "error": null }
}
// 400 webhook_not_configured if no webhook URL is stored

Payload вебхука

Як для отриманого (invoice.received), так і для відправленого (invoice.sent) рахунка ми надсилаємо POST із таким тілом; поле event розрізняє тип.

Ще дві події повідомляють про вердикт мережі щодо відправленого Вами рахунка: invoice.delivered (Access Point отримувача підтвердив доставку підтвердженням доставки (MLS)) і invoice.rejected (відхилено, або мережею, або під час валідації перед відправленням). Вони містять ідентифікацію документа та компанії (documentId, invoiceNumber, receiverId, peppolMessageId, companyDic, peppolParticipantId), а також status, statusDetail із причиною відхилення та statusDateTime. Завдяки їм Вам не потрібно опитувати стан відправлених рахунків.

Подія company.activated надходить, коли клієнт завершує вибір постачальника на порталі (VPDS) Фінансової адміністрації Словаччини (Finančná správa, FS); тіло: event, companyId, companyDic, peppolParticipantId, status, verifiedAt. company.deactivated натомість надходить, коли компанію знімають з реєстрації в мережі (те саме тіло без verifiedAt); докладніше в посібнику /saas:

json
{
"event": "invoice.received",
"companyId": "08dd…",
"documentId": "…",
"invoiceNumber": "2026001",
"senderId": "0088:7300010000001",
"supplierName": "Dodávateľ s.r.o.",
"receiverId": "0245:2121358349",
"issueDate": "2026-06-03",
"dueDate": "2026-06-17",
"deliveryDate": "2026-06-03",
"currency": "EUR",
"totalAmount": "120.00",
"peppolMessageId": "…",
"companyDic": "SK2121358349",
"peppolParticipantId": "0245:2121358349"
}

Поля companyDic і peppolParticipantId ідентифікують компанію, якої стосується подія (важливо для партнерів, які використовують одну URL вебхука для всіх своїх клієнтів).

Вердикт мережі щодо відправленого рахунка:

json
{
"event": "invoice.delivered",          // or "invoice.rejected"
"companyId": "08dd…",
"companyDic": "SK2121358349",
"peppolParticipantId": "0245:2121358349",
"documentId": "…",
"invoiceNumber": "2026001",
"receiverId": "0245:2120049096",
"peppolMessageId": "…",
"status": "delivered",                 // or "rejected"
"statusDetail": null,                  // for rejected: the rejection reason
"statusDateTime": "2026-06-03T10:15:42Z"
}

Активація компанії після вибору постачальника на порталі FS (VPDS):

json
{
"event": "company.activated",          // company.deactivated has the same body without verifiedAt
"companyId": "08dd…",
"companyDic": "SK2121358349",
"peppolParticipantId": "0245:2121358349",
"status": "active",
"verifiedAt": "2026-06-03T10:02:11Z"
}

Назва події також передається в заголовку X-Verteco-Event. Повний список подій: invoice.received, invoice.sent, invoice.delivered, invoice.rejected, company.activated, company.deactivated і тестова подія webhook.test. Рекомендуємо відкладати невідомий тип події та логувати його; про новий тип ми завжди повідомляємо заздалегідь.

Партнерський вебхук сповіщень, керування клієнтами (release, pause-sending) та модель розрахунків доступні лише зареєстрованим посередникам і описані в розділі Для посередників.

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

Якщо компанія має секрет, ми надсилаємо заголовок X-Verteco-Signature у формі sha256=HMAC-SHA256(secret, raw body) (hex у нижньому регістрі). Завжди обчислюйте HMAC над точними байтами тіла:

javascript
import crypto from 'node:crypto';

// rawBody = the exact bytes of the request body (not re-serialized JSON)
function verify(rawBody, header, secret) {
const expected = 'sha256=' +
  crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
return crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}
Секрет Ви отримуєте через POST /companies/{id}/webhook/secret; він повертається один раз (ротація генерує новий). Без секрету ми не надсилаємо заголовок X-Verteco-Signature.

Масове налаштування: один токен, кілька компаній

Один API-токен (прив'язаний до Вашого облікового запису / електронної адреси) керує усіма компаніями, якими він володіє: хто створює компанію через POST /companies, стає її owner і може налаштувати її вебхук. Вебхук є окремим для кожної компанії (власна URL і секрет), тож одним і тим самим токеном Ви можете підключити будь-яку кількість компаній:

bash
# 1) list of your companies (paginated, see Companies)
curl 'https://peppol.verteco.digital/api/v1/companies?page=0&limit=100' -H 'Authorization: Bearer vpt_8f2a…'

# 2) for EACH company {id}: set the webhook (and/or e-mail)
curl -X PUT https://peppol.verteco.digital/api/v1/companies/{id}/notifications \
-H 'Authorization: Bearer vpt_8f2a…' -H 'Content-Type: application/json' \
-d '{"webhookUrl":"https://vas-system.sk/peppol/webhook","notificationEmail":"faktury@firma.sk"}'

# 3) fetch the signing secret (returned ONLY ONCE) and store it for signature verification
curl -X POST https://peppol.verteco.digital/api/v1/companies/{id}/webhook/secret -H 'Authorization: Bearer vpt_8f2a…'
# → { "secret": "…" }
  • Токен має бути owner/admin відповідної компанії; для компанії, де він лише member/viewer, повертається 403 forbidden (жодного доступу між клієнтами (cross-tenant)).
  • Кожній компанії можна задати іншу URL або одну й ту саму для всіх; у payload Ви розрізняєте їх за companyIdreceiverId).
  • За сотень компаній дотримуйтеся ліміту запитів на токен (поточне значення повертається в заголовку RateLimit-Limit); групуйте запити з затримкою (backoff) при 429 (заголовок Retry-After).
  • Вебхук фактично спрацьовує лише тоді, коли компанія активна в Peppol (після вибору Verteco як постачальника у Фінансовій адміністрації) і, отже, фактично отримує документи.

Моделі даних

Поля об'єктів, які повертає API.

Company

ПолеТипОбовʼязковеОпис
idUUIDідентифікатор компанії
icostringреєстраційний номер компанії (IČO, 8 цифр)
dicstring|nullномер платника ПДВ (IČ DPH)
legalNamestringюридична назва
registeredAddressstring|nullадреса зареєстрованого офісу
peppolParticipantIdstring|nullучасник Peppol (після реєстрації)
statusstringpending_verification | active
rolestringowner | admin | member | viewer (Ваша роль)
createdAtInstantчас створення

Document

ПолеТипОбовʼязковеОпис
idUUIDідентифікатор документа
directionstringsent | received
peppolMessageIdstring|nullID повідомлення Peppol
docTypeIdstring|nullтип документа (Peppol)
senderIdstring|nullвідправник (scheme:id)
receiverIdstring|nullотримувач (scheme:id)
invoiceNumberstring|nullномер рахунка
issueDatedate|nullдата виставлення
currencystring|nullвалюта (напр. EUR)
totalAmountnumber|nullзагальна сума
statusstringстан обробки
createdAtInstantчас запису

User · Token · Webhook

ПолеТипОбовʼязковеОпис
Userobject{ id: UUID, email: string }
Tokenobject{ id, name, prefix, lastUsedAt|null, createdAt }
Webhookobject{ url: string|null, hasSecret: boolean }

Словацькі конвенції з практики розробників

Поза межами Peppol BIS Billing 3.0 словацькі постачальники ERP і програм для виставлення рахунків поступово сходяться на спільній інтерпретації опціональних полів (обговорення відбувається в Slack-каналі, який веде Фінансова адміністрація Словаччини, Finančná správa, FS). Нижче наведено конвенції, яких наш портал дотримується вже сьогодні: усі вони є валідними конструкціями BIS, проходять через наше API без змін, а отримані документи відображають їх також у зрозумілому для людини попередньому перегляді та PDF.

  • Вирахування оподаткованого авансу в рядку: від'ємний рядок із cac:DocumentReference, де cbc:ID містить номер податкового документа на отриманий платіж, а cbc:DocumentTypeCode дорівнює 130 (BIS: invoice line object identifier, макс. 1 на рядок). Отриманий рахунок із таким рядком відображається в нашому попередньому перегляді з приміткою „odpočet zálohy – daňový doklad č. …" (вирахування авансу, податковий документ №…).
  • Податковий документ на отриманий платіж: згідно з FAQ Фінансової адміністрації використовується код InvoiceTypeCode 388 (Tax invoice). Він проходить як наше API, так і валідацію; вирахування неоплаченого (неоподаткованого) авансу виражається через cbc:PrepaidAmount.
  • Анулювання рахунка: кредит-нота 381 (CreditNote) з cac:BillingReference на початковий рахунок, а не від'ємний рахунок 380. Примітка: мережа відхиляє код 384 для словацьких сторін (правило PEPPOL-EN16931-P0112 дозволяє його лише між німецькими суб'єктами); для коригування в бік збільшення використовуйте дебет-ноту 383.
  • BT-83 PaymentID: словацька практика сходиться на форматі референсу платника /VS…/SS…/KS…; лише змінний символ (variabilný symbol) також поширений. Наша обробка передає значення без змін і відображає його разом із платіжними реквізитами.
  • Додаткові дані позицій (партії, серійні номери, терміни придатності) через cac:AdditionalItemProperty з усталеними назвами, такими як BatchNumber, SerialNumber, ExpirationDate.
Це конвенції спільноти, а не обов'язкові національні правила: система-отримувач має також обробляти документ, який їх не використовує. Коли обговорення у Фінансовій адміністрації завершиться, ми оновлюватимемо цей розділ (слідкуйте за /changelog).

Вкладення документів (BT-125)

Вкладення (PDF, зображення) можна додати до е-рахунка у форматі base64 в елементі cac:AdditionalDocumentReference (BT-125). Наш ліміт: 25 МБ на вкладення. Peppol не визначає єдиного ліміту для всієї мережі; окремі постачальники встановлюють власні (FS FAQ 9/DPH/2025/IM, приклад № 67), тому для дуже великих вкладень також перевірте ліміт постачальника іншої сторони.

Публічні інструменти (валідація, перевірка отримувача)

Два допоміжні endpoint-и без автентифікації: те саме ядро валідації і той самий SML/SMP lookup, які використовує наш Access Point. Вони підходять для CI та перевірок перед відправленням; на них діє суворіший публічний ліміт запитів.

POST/public/peppol-validateпублічний

Валідація е-рахунка за EN 16931 + Peppol BIS Billing 3.0 (включно зі словацькими правилами), те саме, що й UI-валідатор на /validator. Тіло запиту = безпосередньо UBL 2.1 XML (Invoice / CreditNote або весь Peppol SBD), Content-Type application/xml, ліміт 3 МБ.

bash
curl -X POST https://peppol.verteco.digital/api/v1/public/peppol-validate \
-H "Content-Type: application/xml" \
--data-binary @faktura.xml
json
// 200 OK
{
"valid": false,
"errors": [
  "BR-CO-09: [BR-CO-09]-The Seller VAT identifier (BT-31) … shall have a prefix in accordance with ISO code…"
],
"warnings": []
}
// 400 = empty body (empty_document) or document over 3 MB (document_too_large)
GET/public/peppol-check?id=0245:2121358349публічний

Перевірка отримувача в робочій мережі Peppol (SML/SMP lookup): чи він зареєстрований і які типи документів може отримувати? Параметр id приймає Peppol ID (0245:…), номер платника ПДВ (IČ DPH, SK…) або сам DIČ (словацький податковий ідентифікаційний номер). Автентифікований еквівалент для ERP-конвеєрів: GET /sapi/discovery.

json
// 200 OK
{
"registered": true,
"participantId": "0245:2121358349",
"smp": "sml.peppol-smp.sk",
"capabilities": ["Faktúra (BIS Billing)", "Dobropis", "Self-billing", "MLS doručenky"], // Slovak labels: Invoice (BIS Billing), Credit note, Self-billing, MLS delivery receipts
"lastCheckedAt": "2026-08-31T…Z"
}

Стан (ping)

Публічний endpoint перевірки стану (health-check), придатний для моніторингу.

GET/pingпублічний

Стан backend.

json
// 200 OK
{ "service": "peppol-portal-backend", "status": "ok", "timestamp": "2026-06-17T…Z" }

Актуальний огляд усіх компонентів доступний на сторінці стану системи.

Незабаром

Ядро відправлення/отримання (AS4) завершене та протестоване. Наведені нижче endpoint-и для окремих компаній додаються; їхня форма ще може змінитися. Партнери можуть отримати ранній доступ.
  • POST/companies/{id}/peppol/register· Ручна реєстрація в Peppol SMP через API. Сьогодні це відбувається автоматично при виборі постачальника на порталі FS (VPDS) Фінансової адміністрації Словаччини (Finančná správa, FS).
POST /companies/{id}/documents/send уже доступний (beta: форма відповіді ще може змінитися); для стабільного програмного відправлення рекомендуємо SAPI-SK POST /sapi/document/send із Idempotency-Key.

Хочете отримати ранній доступ до інтеграції, sandbox або маєте запитання? Зв'яжіться з нами безпосередньо:

Miriama Mrkávková

Ваш контакт з Peppol

Miriama Mrkávková

+421 944 488 269·peppol​@​verteco.digital