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

Для розробників: довідник 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). Перевірені зразки для словацьких ситуацій (неплатник ПДВ, валюта, зворотне оподаткування, кредит-нота, аванси, вбудований PDF): /uk/vzory.

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.

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

Який інтерфейс підходить вам

SAPI-SK 1.0 (/sapi)

Бухгалтерська або рахункова програма, ERP, платформи для багатьох компаній: національний інтерфейс для відправлення, отримання, статусів, квитанцій і звітів FS. Рекомендовано для кожної інтеграції, що надсилає або читає документи.

OAuth2 client credentials: client_id = UUID API-ключа, client_secret = ключ vpt_, access token на 15 хвилин.

Portal API (/api/v1)

Компанії, вебхуки, сповіщення, експорти та завантаження; партнерська консоль (/resellers/me). Доповнює SAPI, не замінює його.

Authorization: Bearer vpt_… (API-ключ облікового запису).

MCP-сервер (/api/mcp)

ШІ-асистент (Claude Code, Cursor, Claude Desktop) має читати документи, перевіряти одержувачів і надсилати після явного підтвердження.

Bearer vpt_… через MCP-клієнт.

E-mail у скриньку компанії

Без програмування: XML-рахунок як вкладення на секретну адресу компанії; перевіряється і надсилається як із порталу.

Адреса відправника в списку дозволених + SPF/DKIM.

Обліковий запис і 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();
  4. 4

    Вибір постачальника на порталі Фінансової адміністрації

    У продуктивному середовищі вибір Verteco на порталі FS (vpds.financnasprava.sk) потрібен навіть для суто відправлення: він розблоковує відправлення (верифікаційний токен) і активує компанію. Отримання при цьому може лишитися в постачальника вашої бухгалтерської програми: у мережі компанія має рівно одного отримувача, але може мати кілька відправників.

Швидкий старт із curl (спочатку в тестовому середовищі)

Шість викликів від облікового запису до першого доставленого рахунку, усі до test.peppol.verteco.digital, де компанія активна одразу після створення, а документи йдуть у тестову мережу Peppol. Очікувані відповіді скорочено.

shell
export BASE=https://test.peppol.verteco.digital   # production: https://peppol.verteco.digital
export KEY=vpt_…        # step 1
  1. 1

    Обліковий запис і API-ключ

    Зареєструйтеся на test.peppol.verteco.digital/register (у тестовому середовищі без листа підтвердження) і створіть ключ на сторінці API-ключі. Він показується один раз; нижче $KEY.

  2. 2

    Перевірте ключ

    shell
    curl -s $BASE/api/v1/auth/me -H "Authorization: Bearer $KEY"
    json
    { "id": "7f1d…", "email": "dev@firma.sk", "emailVerified": true, "persona": "developer" }
  3. 3

    Створіть компанію

    shell
    curl -s -X POST $BASE/api/v1/companies -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"ico":"12345678","dic":"SK2120000001","legalName":"Test s. r. o.","street":"Hlavná 1","city":"Žilina","postalCode":"01001"}'
    json
    { "id": "5c0e…", "legalName": "Test s. r. o.", "dic": "SK2120000001", "status": "active",
      "peppolParticipantId": "0245:2120000001", "verified": true }
  4. 4

    Access token SAPI

    shell
    curl -s -X POST $BASE/sapi/auth/token -H "Content-Type: application/json" -d '{"grant_type":"client_credentials","client_id":"<UUID ключа зі сторінки API-ключі>","client_secret":"'$KEY'"}'
    json
    { "access_token": "eyJhbGciOiJIUzI1NiJ9…", "token_type": "Bearer", "expires_in": 900,
      "refresh_token": "eyJhbGciOiJIUzI1NiJ9…" }
  5. 5

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

    shell
    curl -s -X POST $BASE/sapi/document/validate -H "Authorization: Bearer $ACCESS" -H "Content-Type: application/json" -d '{"payload":"<Invoice …>","payloadFormat":"XML"}'
    json
    { "valid": true, "errors": [], "warnings": [] }
  6. 6

    Надішліть і стежте за статусом

    shell
    curl -s -X POST $BASE/sapi/document/send -H "Authorization: Bearer $ACCESS" -H "X-Peppol-Participant-Id: 0245:2120000001" -H "Idempotency-Key: FA-2026-0001" -H "Content-Type: application/json" -d @send.json, потім curl -s "$BASE/sapi/document/sent?since=2026-10-01T00:00:00Z" -H "Authorization: Bearer $ACCESS" -H "X-Peppol-Participant-Id: 0245:2120000001"
    json
    HTTP/2 202
    { "providerDocumentId": "6a3f…", "status": "ACCEPTED", "peppolMessageId": "f1c7…", "receivedAt": "2026-10-03T12:00:01Z" }
    
    { "documents": [ { "documentId": "6a3f…", "status": "delivered", "sentAt": "2026-10-03T12:00:01Z",
      "deliveredAt": "2026-10-03T12:00:14Z", "hasMls": true, "fsReport": { "state": "reported" } } ] }
Перехід у продакшн: замініть $BASE на peppol.verteco.digital, створіть робочий обліковий запис і ключ, і нехай клієнт обере провайдера на порталі Фінансової адміністрації (компанія активується сама, відправлення розблоковує верифікаційний токен).

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

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

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

Реєстрація
без листа з підтвердженням; обліковий запис можна використовувати одразу
Схвалення компанії
автоматичне, безпосередньо в інтерфейсі або через API; немає вибору постачальника на порталі Фінансової адміністрації Словаччини (Finančná správa, FS) і немає входу на портал ФА; одразу після створення компанії з номером платника ПДВ (IČ DPH) Ви можете як відправляти, так і отримувати
Реєстрація в мережі
автоматична, до тестової мережі Peppol. Зверніть увагу на два рівні ідентифікатора: API і портал використовують той самий формат, що й продуктивне середовище (peppolParticipantId = 0245:<цифри DIČ>, де DIČ це словацький податковий ідентифікаційний номер; Ваш інтеграційний код не змінюється); у тестових SMP/SML компанія технічно реєструється як 9950:SK<DIČ>, оскільки схема 0245 вимагає верифікаційного коду Фінансової адміністрації, якого в тестовому середовищі не існує. У продуктивному середовищі 0245:<цифри DIČ> реєструється в робочій мережі Peppol лише після вибору постачальника на порталі ФА (вхід через eID або за обліковими даними)
Валідація
реальна: правила EN 16931 + Peppol BIS 3.0, ті самі, що й у продуктивному середовищі
Доставка
реальна, через тестову мережу Peppol (AS4, тестовий сертифікат, тестові SML/SMP): отримувач, зареєстрований у тестовій мережі, отримує рахунок як отриманий (включно з електронним листом, PDF і вебхуком); у робочу мережу нічого не потрапляє
Підтвердження доставки (MLS)
реальне підтвердження MLS з тестової мережі
Електронні листи
справді надсилаються (на адреси, які Ви вводите), з префіксом [TEST]
Симуляція помилок
заголовок X-Sandbox-Simulate: 503 (або 502, 500, 429) на будь-якому виклику /sapi/document/* з дійсним токеном повертає відповідну помилку; нічого не обробляється й не зберігається. Для 500 (SAPI-PROC-500) і 429 (SAPI-SYS-003 з Retry-After) ви отримаєте конверт помилки SAPI; 503 і 502 проходять через мережевий периметр (DigitalOcean, Cloudflare) як HTTP 504 з HTML-тілом без конверта, саме так виглядає справжній збій ззовні, тож ви перевірите й обробку відповіді, що не є JSON. Помилки валідації викликає недійсний XML, 429 також перевищення 300 викликів за хвилину. У продуктивному середовищі заголовок ігнорується
Ціна
безкоштовно, без обмежень для тестування

Усе, що працює тут, працює і там: портал, REST API, SAPI-SK 1.0, плагіни для інтернет-магазинів і вебхуки. Достатньо змінити домен у Вашій інтеграції на test.peppol.verteco.digital і використовувати токени, створені в тестовому середовищі. Ідеально для розробки інтеграції, CI-тестів і навчання бухгалтерів перед продуктивним запуском. Тестові документи належать лише туди: у продуктивному середовищі кожен внутрішній документ між платниками ПДВ звітується Фінансовій адміністрації, і звіт не можна відкликати. У продуктивному порталі пробуйте лише кнопкою „Poslať skúšobnú faktúru“ (надіслати тестовий рахунок, 0,00 €); з 1. 1. 2027 продуктивне середовище відхиляє номери TEST-/VITAJTE- (test_document_in_production).

Примітка: захист периметра (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 працює лише в продуктивному середовищі та перевіряється входом на портал ФА (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; для програмного відправлення використовуйте саме його.

Версіонування та зворотна сумісність

  • Контракт лише зростає: нові поля (пропущені, коли null), нові необов’язкові параметри, нові кінцеві точки та події. Наявні назви полів, значення enum і коди статусів не змінюються.
  • Нове значення enum або подія вебхука можуть з’явитися будь-коли; ігноруйте невідоме і відповідайте на невідому подію 2xx.
  • Часові мітки у форматі ISO 8601 UTC зі змінною кількістю дробових цифр; розбирайте їх, ніколи не порівнюйте як текст. Суми надходять рядками з двома десятковими знаками.
  • Якщо зміна не може бути адитивною, ми оголошуємо її в changelog (є підписка e-mail) щонайменше за 90 днів і зберігаємо стару форму на перехідний період.
  • Модель безпеки API-ключа (з 3 жовтня 2026): ключ читає і надсилає документи, керує компаніями, сповіщеннями та вебхуками. Керування обліковим записом і ключами (створення, обмеження або відкликання ключа, MFA, пароль, сесії, запрошення, передача компанії, підписання договорів) виконує лише авторизована особа; ключ отримує там 403 token_not_allowed. GET /api/v1/tokens лишається доступним для ключа.
  • Версія контракту — info.version в openapi.json, і кожна зміна має рядок у changelog з тегом API або Webhooks.

/changelog · /changelog/odber · openapi.json

Помилки

Словник помилок для завантаження: той самий словник, яким портал перекладає деталі відхилення (ідентифікатори правил EN 16931 та Peppol BIS, шаблони мережевих помилок, коди statusReason з GET /sapi/document/sent), доступний у форматі JSON за адресою /docs/peppol-errors.json (sk, en, de, hu). Підходить для таблиці поширених помилок у бухгалтерській програмі: шукайте ідентифікатор правила будь-де в деталях, невідоме правило показуйте разом з його ідентифікатором. З 7.10.2026 кожна JSON-відповідь має заголовок Content-Type: application/json;charset=UTF-8.

Помилки мають єдину структуру з машинозчитуваним кодом 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надто багато запитів

Збій точки доступу та повторні спроби

  • Якщо API відповідає 502, 503 або 504, або не відповідає взагалі, документ ми не прийняли: повторіть виклик пізніше з тим самим Idempotency-Key, нічого не буде надіслано двічі.
  • Документ, який API прийняв (202 ACCEPTED, також із retrying: true), після відновлення вийде сам: точка доступу повторює доставку, стан видно через GET /sapi/document/sent або вебхук; якщо вона зрештою відмовиться, документ завершиться як невдалий, і той самий ключ надішле його знову.
  • Отримання на рівні мережі не залежить від порталу: доставку, яка не пройшла під час збою порталу, відправна точка доступу повторює за правилами Peppol, і документ з'явиться в порталі після відновлення. Звіти Фінансовій адміністрації, що не вийшли через збій, доповнює автоматичний відновлювальний запуск (транспортний збій повторюється, змістовна відмова ні).
  • Стан та історія доступності на /status; у тестовому середовищі збій можна зімітувати заголовком X-Sandbox-Simulate (розділ Тестове середовище).

Коди SAPI-SK (поле error.code)

КодЗначення
SAPI-AUTH-001недійсні client_id/client_secret або заблокований обліковий запис (401)
SAPI-AUTH-002відсутній або некоректний заголовок Authorization: Bearer (401)
SAPI-AUTH-003ключ не має прав на учасника, відправлення не розблоковано або призупинено (403)
SAPI-AUTH-004IP-адреса не в списку дозволених для ключа (403)
SAPI-VAL-001некоректне тіло запиту (400)
SAPI-VAL-002відсутній X-Peppol-Participant-Id (400)
SAPI-PROC-001тимчасово: відправлення з цим ключем триває, повторіть трохи згодом (502, retryable)
SAPI-PROC-002документ відхилено до відправлення (422 з Prefer: handling=strict)
SAPI-PROC-003без Idempotency-Key: під цим номером уже передано інший документ (409, details: documentId, status)
SAPI-RES-001документ не існує або належить іншому учаснику (404)
SAPI-RES-002вміст документа більше не зберігається (ретенція компанії) або не архівувався (404; код залишено для сумісності)
SAPI-RES-003 / 004вкладення або квитанція MLS ще не існує (404)
SAPI-SYS-001 / 002тимчасова помилка інфраструктури або валідатора (503/502, retryable)
SAPI-SYS-003перевищено ліміт запитів (429, Retry-After)
SAPI-PROC-500неочікувана помилка, надішліть correlation_id у підтримку (500)

Повний каталог помилок портального API (326)

Усі коди, які бекенд повертає в полі error, із текстом, що показує портал. Генерується з того самого словника, що й інтерфейс, тому не застаріває. Тексти англійською.

Повний каталог помилок портального API
account_existsAn account already exists for this e-mail. Sign in and accept the invitation in the portal.
account_inactiveYour account is not active. Please contact us.
account_under_reviewYour account is being reviewed. Call us or write to [email protected].
acknowledge_requiredConfirm that you understand the risks of downloads without login.
acknowledgement_requiredConfirm that you understand the consequences of terminating the contract.
address_book_fullThe address book is full. Remove unused clients and try again.
admin_email_unverifiedAdministration access requires a verified e-mail address. Click the link in the message we sent you at sign-up.
admin_mfa_requiredAdministration access requires two-factor authentication. Turn it on in Settings.
ai_budgetThe AI draft budget is used up or you reached the daily limit. Write the reply manually.
ai_failedThe reply draft could not be generated. Please try again.
ai_unavailableAI reply drafts are not available right now.
already_completedThe company transfer has already been completed.
already_memberThis user already has access (member of the company or your team).
attachment_externalThis attachment is stored at the sender as a link, not inside the invoice itself.
attachment_invalidAn attachment could not be sent (type not allowed, corrupted content or size exceeded). Check the attachments and try again.
attachment_not_foundThe attachment was not found.
attachment_not_readableThe attachment could not be read.
billing_unconfiguredSubscription payments are not available yet.
blockedThe test webhook cannot be sent to this address (local or internal addresses are not allowed).
body_requiredPlease write the text of your message.
body_too_longThe message can have at most 4000 characters.
cannot_change_selfYou cannot change your own role. Ask the other company administrator.
cannot_invite_selfYou cannot invite yourself or accept your own invitation.
cannot_release_to_selfThe company is already under this account.
cannot_remove_ownerThe company owner cannot be removed. Ownership changes through a company transfer.
cannot_restrict_adminA portal administrator account cannot be restricted this way.
cannot_transfer_selfThe company already belongs to this e-mail.
captcha_failedThe bot check failed. Please try again.
captcha_requiredThe bot check failed; reload the page and try again.
channel_unknownAn old record without a known channel cannot be replayed. Re-POST it manually to the right endpoint.
chat_not_foundThe conversation was not found or is empty.
client_not_foundThe company does not belong to this partner account.
client_not_removableThe company cannot be removed: it is verified by the Financial Administration, active, registered in the SMP or has documents. Use release instead.
company_activeAn active company cannot be deleted.
company_address_requiredBefore sending an invoice, add the company address (street, city, postal code) in the company details.
company_already_activeThe company is already active; activation instructions are not needed.
company_dic_missingAdd the company DIČ (tax ID) first, then try the verification again.
company_incompleteBefore signing, complete the company details: legal name, IČO, Peppol identifier and full address.
company_limitYou reached the maximum number of companies per account. Contact support and we will raise the limit.
company_name_mismatchThe legal name does not match the official register (ŽR/OR SR) for this IČO.
company_not_activeA migration code can only be issued for an active company registered in the Peppol network.
company_not_foundThe company was not found.
company_not_registeredThe company is not activated yet: complete the Verteco selection on the Financial Administration portal, then you can send.
company_not_verifiedMigration is possible only after selecting Verteco on the Financial Administration portal (the company must be active and verified).
company_verified_lockedThe legal name of a verified company can only be changed to the official register entry. Add the IČO first or write to us.
confirm_name_mismatchThe entered name does not match the registered reseller name.
confirmation_requiredSigning requires confirming your authority and your agreement with the wording.
conflictThis record already exists.
content_unavailableThe content of this document is no longer stored or cannot be read as an invoice.
contract_pendingThe contractual relationship arises on the first entry into the portal (Art. 4 of the Terms); none has been recorded for this company yet, so the contract cannot be issued.
country_invalidCountry must be a two-letter ISO code (SK, CZ, AT, DE…), not a name.
country_outside_euThe online application is open to entities established in an EU member state. Entities outside the EU: write to [email protected].
current_ip_missingThe list must include your current IP address, otherwise you would lock yourself out after signing out.
daily_limitYou reached the daily message limit. Try again tomorrow or write to [email protected].
delivery_failedThe test webhook could not be delivered; your endpoint did not respond.
delivery_not_foundThe webhook delivery record was not found.
deregister_cooldownOnly one company per IP address can be removed every 60 seconds. Try again in a moment.
dic_immutableThe Peppol identifier cannot be changed: it is the identity of the company in the Peppol network.
dic_requiredEnter the company DIČ (tax ID: SK + 10 digits).
dic_takenA company with this DIČ already exists in the portal.
directory_unavailableThe central SMP is not responding or refused the change. Please try again in a moment.
document_no_xmlThe stored original XML is gone; the report cannot be rebuilt.
document_not_foundThe document was not found.
document_too_largeThe document is too large (limit 3 MB).
domestic_subjectA Slovak entity submits the application after signing in at /sprostredkovatel/ziadost.
duplicate_invoice_numberA document with this number was already sent. A new document needs a new number; the same document is never sent twice.
email_change_cooldownWe already sent the confirmation e-mail. You can request another one in 10 minutes.
email_invalidEnter a valid e-mail address.
email_not_verifiedConfirm your e-mail first. We sent you the link.
email_send_company_not_activeSending by e-mail can be switched on only for an active company with a Peppol identifier.
email_send_unavailableSending by e-mail is not available in this environment.
email_takenThis e-mail address is already used by another account.
email_unchangedThis is your current e-mail address.
empty_documentPaste the invoice XML.
empty_ideaPlease tell us what we should improve.
empty_messageThe message is empty.
empty_replyThe reply is empty.
entry_not_foundThe address book client was not found.
export_format_unknownUnknown export format.
forbiddenYou are not allowed to do this.
forwarder_unreachableThe document processing service is not responding. Try again in a moment.
fs_change_already_sentThe request has already gone to the Financial Administration and cannot be cancelled. File a new one if needed.
fs_change_confirm_requiredConfirm that you request all the changes at once.
fs_change_cooldownThe next change request can be filed 48 hours after the previous one.
fs_change_field_readonlyThe company ID and tax ID cannot change; a new identity means a new registration.
fs_change_no_changesYou have not entered any change against the data at the Financial Administration.
fs_change_not_foundThe change request was not found.
fs_change_not_openThe request is already closed.
fs_change_not_queuedOnly a request waiting to be sent can be sent now.
fs_change_pendingOne change request is already waiting or with the Financial Administration. File the next one once it is closed.
fs_secret_invalidThe key has 32 characters (digits and the letters a to f). Copy the whole content of the .txt file from the zip sent by the Financial Administration.
fs_secret_mismatchThe key does not match the signature of calls the Financial Administration has already sent to your endpoint. Check the zip and the copied key; if your proxy alters the call body, write to us.
has_documentsThe company has documents in the archive; deletion is blocked (statutory archiving).
holding_unavailableReleasing the client is not possible right now. Contact support.
ico_immutableThe IČO cannot be changed.
ico_requiredThe IČO is required (8 digits).
ico_takenA company with this IČO already exists under another account. Sign in with it or write to us.
instructions_cooldownWe already sent the instructions for this company. They can be sent again after 24 hours.
integration_not_foundUnknown integration.
internalAn unexpected error occurred. Please try again.
internal_errorAn unexpected server error occurred. Please try again; the error has been logged.
invalid_actionUnknown action.
invalid_afterThe after parameter must be an ISO 8601 date and time (e.g. 2026-09-05T10:00:00Z).
invalid_amountThe amount must be a number.
invalid_billing_modelUnknown billing model. Choose one of the offered models.
invalid_countrySelect the country of the registered office.
invalid_credentialsIncorrect e-mail or password.
invalid_current_passwordThe current password is not correct.
invalid_dateThe date must be in the format YYYY-MM-DD.
invalid_default_companyThe default company must be one of your companies.
invalid_dicEnter a valid DIČ (10 digits, optionally with the SK prefix) or VAT ID.
invalid_directionThe document direction must be sent or received.
invalid_due_daysThe due period must be 0 to 365 days.
invalid_emailEnter a valid e-mail address.
invalid_feed_urlThe feed URL must start with https://.
invalid_icoEnter a valid IČO (8 digits) or company registration number.
invalid_idEnter a Slovak VAT ID or DIČ (e.g. SK2121358349) or a Peppol ID (e.g. 0245:2121358349).
invalid_idsThe list of documents is not valid.
invalid_inviteThe invitation is invalid or has already been used.
invalid_ip_entryThe list contains an invalid entry. Allowed are IP addresses (e.g. 185.76.8.211) and CIDR ranges (e.g. 185.76.8.0/24).
invalid_keyThe reseller key must have 3 to 40 characters: lowercase letters, digits and hyphens.
invalid_limitThe limit must be at least 1, or empty (default value).
invalid_linkThe sign-in link is invalid or has expired. Request a new one.
invalid_localeUnsupported language.
invalid_monthThe month must be in the format YYYY-MM.
invalid_notification_emailOne of the addresses is not a valid e-mail:
invalid_notify_eventUnknown notification event.
invalid_notify_localeThe e-mail language must be Slovak, English, German or Hungarian.
invalid_notify_modeUnknown notification mode. Choose: every event, daily digest, weekly digest or none.
invalid_passwordIncorrect password.
invalid_patternThe numbering format must have at most 64 characters and contain the sequence {N}, {NNN} or {NNNN} exactly once.
invalid_payloadThe invoice (XML) is missing or too large.
invalid_personaUnknown account role.
invalid_phoneEnter the phone number as +421 9xx xxx xxx (digits, spaces, optionally hyphens).
invalid_prefsThe display settings contain an invalid value and could not be saved.
invalid_receiverThe recipient must have a Peppol identifier in the form scheme:value (e.g. 0245:2121358349).
invalid_requestRequired data is missing (e.g. company name, 10-digit DIČ, valid e-mail or endpoint URL).
invalid_roleThe role must be administrator, member or read-only.
invalid_seqThe next sequence number must be at least 1.
invalid_sessionInvalid conversation. Reload the page and try again.
invalid_signatureThe payment notification could not be verified.
invalid_signupThe sign-up is no longer valid or has expired. Start the registration again.
invalid_sortUnknown sort order.
invalid_stateUnknown state.
invalid_statusUnknown status.
invalid_tagThe tag cannot be empty.
invalid_tokenThe link is invalid or has already been used.
invalid_vpds_urlThe selection link must start with https://vpds.financnasprava.sk/.
invalid_webThe website must be a valid address (https://...).
invalid_webhook_urlThe webhook URL must be a valid https:// address (at most 512 characters).
invalid_windowThe time window is not valid: from must be before to and the window at most 31 days.
invalid_xmlThe document XML cannot be read (corrupted file or a DOCTYPE declaration, which is not allowed).
invite_email_mismatchThis invitation is for a different e-mail address. Sign in with the account it was sent to.
invite_expiredThe invitation has expired. Ask for a new one.
ip_not_allowedSigning in from this IP address is not allowed for this account.
lead_no_emailThe lead has no e-mail address and cannot be contacted.
lead_not_contactableOnly a lead in the state new can be contacted.
lead_not_foundThe lead was not found.
link_goneThis link is no longer valid (expired, revoked, or the document content is no longer stored).
lookup_unavailableThe register or verification service is currently unavailable. Try again in a moment.
malformed_requestThe request is not in a valid format. Reload the page and try again.
manager_requiredOnly the company owner or an administrator can make this change.
member_is_ownerThis user is the company owner. Ownership changes through a company transfer.
member_not_foundThe member was not found.
members_fullThe company reached the maximum number of members.
method_not_allowedThis operation is not supported for this address.
mfa_already_enabledTwo-factor authentication is already turned on.
mfa_code_invalidThe code does not match. Try the current code from your app or a backup code.
mfa_not_enabledBackup codes belong to two-factor authentication. Turn it on first.
mfa_not_startedStart the two-factor authentication setup first.
mfa_requiredEnter the code from your authenticator app.
migration_code_liveThe previous migration code is still valid. Cancel it first.
migration_code_noneThere is no active migration code request.
migration_code_pendingA migration code request is already in progress.
migration_code_rejectedThe SMP rejected the migration code. Check it with the previous provider; codes are single-use and time-limited.
migration_code_requiredEnter the migration code from the previous provider.
migration_rejectedThe central SMP rejected the takeover request. Try again or write to us.
missing_fieldsThe name and the owner e-mail are required.
missing_parameterA required parameter is missing from the request.
mls_not_availableNo delivery receipt (MLS) is available for this document yet.
name_requiredEnter the name (client name or legal name).
no_billing_accountYou do not have a billing account yet. Set up a subscription first.
no_bodyThe record has no stored request body and cannot be replayed.
no_contentThe document content is no longer available; the link cannot be issued.
no_dicThe company has no DIČ (tax ID).
no_documentsThere are no documents (with stored XML) for the selected period.
no_evidenceNeither the original XML nor a delivery receipt is stored for this document.
no_idsSelect at least one document.
no_ownerThe company has no owner. Use direct reassignment instead.
no_secretThe signing key does not exist yet. Set the notification webhook URL first.
no_verification_tokenThe company has no stored verification token from the Financial Administration; SMP registration requires it.
not_a_resellerThis account is not the owner of a reseller registration.
not_acceptableThe server answers in JSON format only.
not_available_for_white_labelNot available for companies under a reseller brand.
not_failedOnly failed webhooks can be retried.
not_foundRecord not found.
not_resellerThis account is not the owner of a reseller registration.
not_sandbox_rowThis reseller registration is managed by an administrator and cannot be switched off from the account.
note_too_longThe note can have at most 200 characters.
notification_emails_too_longThe addresses are too long together (256 characters at most).
owner_not_foundNo owner account exists for this e-mail. Create it first.
owner_of_companiesTo delete the account, first request a migration code or deregister the company from the Peppol network. After that you can delete the account permanently.
owner_requiredOnly the owner of the company account can do this.
participant_not_registeredThe company has no record in the central SMP under Verteco yet; set the listing after registration.
partner_managedThis company is managed by its intermediary; the contract confirmation is issued by them.
party_missing_in_textThe text being signed does not contain the company identification. Reload the page and try again.
password_already_setYou already have a password. Use the change password option.
password_not_setThe account has no password. Set one in Settings and try again.
password_requiredSet a password first (Security); then you can confirm this change.
payment_mismatchThe payment could not be matched to the application. Please contact us.
payment_unconfiguredPayment is not available right now. Try later or contact us.
pdf_unavailablePDF generation is temporarily unavailable. Try again in a moment or use Print / PDF.
profile_too_longOne of the profile fields is too long. Shorten the text.
public_link_existsThe document already has an active link. Choose to replace it if you want a new one.
public_links_disabledThe company has not enabled invoice downloads without login. The owner can turn it on in the company details (Data archive).
public_links_unavailablePublic document links are currently switched off.
rate_limitedToo many requests. Try again in a moment.
read_only_memberThe read-only role cannot change document states or tags.
received_onlyA public link is issued only for received documents.
receiving_toggle_cooldownReceiving can be switched at most three times per hour. The next change is possible once an hour has passed since the oldest of the last three changes.
registered_elsewhereThe participant is still registered with another provider; the code did not trigger the takeover.
renderer_unavailableThe preview cannot be rendered right now (the rendering service is restarting). Try again in a moment; sending the invoice is not blocked.
reply_already_cancelledThis reply was cancelled by a colleague in the meantime.
reply_already_sentThis reply has already been sent; it cannot be cancelled or sent again.
reply_not_foundThe scheduled reply was not found.
reply_to_invalidThe results address is not a valid e-mail address.
representative_incompleteEnter both the name and the position of the authorised person, or leave both fields empty.
request_rejectedThe request contains a character that is not allowed in a header or the URL. If you sent an API key, use the full client_secret shown when the key was created (the key list shows only its beginning with …) and plain quotes.
reseller_not_foundThe reseller was not found.
reseller_ownerYour account owns a reseller registration. Arrange its hand-over with support; then you can delete the account.
reseller_requiredThis part is only for the account of a registered intermediary.
sbd_not_availableThis document has no stored transport envelope (SBDH). Download the document XML instead.
schedule_not_foundThis scheduled export no longer exists.
sender_email_invalidThe sender address is not a valid e-mail address.
sender_email_systemAutomated mailboxes (noreply, postmaster, mailer-daemon…) cannot be added; use a person's or the invoicing system's mailbox.
sender_existsThis address is already on the allow-list.
sender_limitAt most 20 allowed senders are possible.
sending_not_verifiedSending is not allowed: the company does not have a verified provider selection on the Financial Administration portal yet.
sending_pausedSending is paused for this company by its managing account. Receiving invoices continues.
service_unavailableThe service is temporarily unavailable. Please try again in a moment.
session_fullThis conversation is too long. Reload the page and start a new one.
session_not_foundThe device was not found.
shoptet_feed_blockedThe address points to a private network. Paste the public address of your shop.
shoptet_feed_httpShoptet refused the address. Check the hash in the address and that the export is not limited to one IP address.
shoptet_feed_invalid_xmlThe export response is not valid XML. Check the address in Shoptet.
shoptet_feed_not_configuredThe Shoptet connection is not set up yet.
shoptet_feed_not_orders_xmlThis is not a Shoptet order export: the address must end with /export/orders.xml.
shoptet_feed_not_system_xmlPaste the address of the “System Shoptet XML” export (its address contains patternId=-11). Custom templates, CSV and XLS are not supported.
shoptet_feed_too_largeThe export response is too large (over 10 MB). We ask for orders week by week, so such a response is usually a product export, not an order export. Check the export type.
shoptet_feed_unreachableThe Shoptet export did not respond. Try again in a moment; Shoptet allows only one export at a time.
sidlo_incompleteThe address must contain street, postal code and city, e.g. "Ulica 1, 010 01 Mesto".
smp_cancel_failedCancelling the code at the central SMP failed. Try again in a moment or write to [email protected].
smp_deregister_failedDeregistration from the Peppol network failed. Try again in a moment.
smp_held_elsewhereThis company's registration is held by another provider. No migration code from us is needed.
smp_not_testThe test environment is not connected to the test SMP correctly. Please write to us.
smp_unavailableThe central SMP is not responding right now; try again in a moment.
smtp_fromAddress_requiredEnter the sender address.
smtp_fromAddress_too_longThe sender address is too long.
smtp_from_forbiddenThe sender address cannot be on a Verteco domain.
smtp_from_invalidThe sender address is not a valid e-mail.
smtp_from_not_yoursThe sender address must be on your company's domain (like the owner, member or company notification e-mail).
smtp_from_takenThis sender address is already used by another company.
smtp_host_blockedThe server cannot be found in DNS or is not publicly reachable (internal addresses are not allowed).
smtp_host_invalidEnter the server's domain name (e.g. smtp.company.com), not an IP address.
smtp_host_requiredEnter the SMTP server address.
smtp_host_too_longThe SMTP server address is too long.
smtp_incompleteFill in the server, port, username, password and sender address.
smtp_password_invalidThe password must not contain spaces or line breaks.
smtp_password_requiredEnter the SMTP account password (it must be re-entered when the server changes).
smtp_port_not_allowedAllowed ports are 465, 587 and 2525.
smtp_security_invalidSecurity must be STARTTLS or SSL.
smtp_test_cooldownA test e-mail can be sent once per minute. Try again in a moment.
smtp_test_failedThe test e-mail could not be sent. Check the SMTP server settings.
smtp_username_invalidThe username must not contain spaces or line breaks.
smtp_username_requiredEnter the SMTP account username.
smtp_username_too_longThe username is too long.
state_not_for_directionThis state is not possible for the document direction (received or sent).
stripe_errorThe payment gateway could not be opened or the payment could not be verified. Please try again.
support_not_on_sandboxSupport runs on the production portal peppol.verteco.digital, not in the test environment.
tag_too_longThe tag is too long.
target_blockedThe target account is blocked; the transfer is not possible.
team_fullYou reached the maximum number of team members.
termination_confirmedA confirmed termination notice cannot be cancelled from the app. Write to [email protected].
termination_pendingA termination request is already in progress. Confirm it via the e-mail link or cancel it.
terms_not_acceptedYou need to accept the terms and conditions to create an account.
test_document_in_productionTest documents (number TEST-… or VITAJTE-…) are not sent through the live network from 1 January 2027. Use the test environment test.peppol.verteco.digital for trials.
ticket_link_expiredThe request has been closed for more than 90 days; the link is no longer valid. Write to us again at [email protected].
ticket_not_foundThe request was not found or the link is not valid.
token_companies_requiredSelect at least one company the key may access.
token_company_not_allowedThis API key has no access to this company (it was created for selected companies only).
token_company_not_memberA key can only cover companies your account is a member of.
token_expiredThe link has expired. Request a new one.
token_invalidThe link or verification token is invalid or no longer valid.
token_limitYou have too many active API keys (max 50). Revoke unused ones and try again.
token_not_allowedThis setting can only be changed after signing in to the portal, not with an API key.
token_not_foundThe API key was not found.
token_not_revokedThis API key is active; there is nothing to restore.
token_restore_expiredThe key was revoked more than 7 days ago and can no longer be restored. Create a new key.
token_scope_invalidThe key scope must be "all" or "selected".
too_many_idsAt most 500 documents can be processed at once.
too_many_notification_emailsEnter at most 5 e-mail addresses.
too_many_schedulesA company can have at most five scheduled exports. Delete one before adding another.
too_many_tagsThe document has too many tags.
too_many_ticketsYou have too many open requests. Please wait for a reply.
transfer_canceledThe company transfer was cancelled.
transfer_expiredThe transfer link has expired. Request a new transfer.
transfer_staleThe company ownership changed in the meantime; the transfer was cancelled.
unauthorizedPlease sign in again.
unknown_documentOnly the DPA, SLA and NDA documents can be signed.
unsupported_documentThe preview can render only an invoice or a credit note (UBL Invoice or CreditNote).
unsupported_media_typeThis content type is not accepted. Send the data as JSON.
user_not_foundNo account with this e-mail was found. The user needs to register first.
validation_failedSome fields are not filled in correctly.
validator_unavailableValidation is currently unavailable. Try again in a moment.
verification_code_rejectedThe SMP rejected the verification token from the FS selection; repeat the selection.
verification_token_missingThe verification token from the FS selection is missing; repeat the selection and try again.
verified_company_requiredOnly an account with at least one verified company can submit the application.
version_staleThe document wording changed in the meantime. Reload the page and sign the current version.
webhook_not_configuredSet and save the webhook URL first.
webhook_url_https_requiredIn production the webhook URL must start with https:// (a delivery carries customer identifiers and a signature).
webhook_url_unreachableThe webhook URL must be publicly reachable. Localhost and internal networks cannot be reached from our servers.
white_label_owner_fixedA company run through a partner is managed by the partner account. Another owner is added by the partner releasing the company, or by selecting Verteco on the Financial Administration portal.
wrong_endpointThis is not the token endpoint. Use POST /sapi/auth/token with client_id and client_secret.
xml_not_availableThe original XML is not stored for this document; its content is no longer available.
xml_requiredThe document XML is missing, the preview cannot be rendered.
xml_too_largeThe document is too large for a preview (at most 8 MB including attachments).

Ліміти запитів (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." }
Практичні відповіді для інтеграторів:
  • Знижки та округлення: правила R040 (сума знижки = база × % / 100) і R120 (сума рядка = кількість × ціна − знижки рядка) мають допуск 0,02 €; точним є лише R046 для знижки на рівні ціни (PriceAmount = BaseAmount − Amount). Ціна за одиницю (BT-146), а також базова ціна та знижка з ціни (BT-147, BT-148) не мають обмеження кількості десяткових знаків, усі інші суми мають 2. Якщо ваша система застосовує знижку до ціни за одиницю й округлює її, запишіть її на рівні ціни: PriceAmount = округлена ціна після знижки, BaseAmount = прайсова ціна, Amount = точна різниця, сума рядка = round(кількість × PriceAmount, 2); відсоток там вказати не можна (він належить до примітки рядка). Другий варіант: знижка рядка лише сумою з кодом причини 95; відсоток і базу в знижці рядка вказуйте лише тоді, коли база = round(кількість × експортованої PriceAmount, 2) і Amount = round(база × % / 100, 2). Від’ємна кількість із додатною ціною (повернення товару, вирахування оподаткованого авансу) дозволена і в кредит-ноті, і в рахунку. Зразки 11, 15 і 16 на /uk/vzory.
  • Ліміти прив’язані до облікових даних, а не до IP: 300 викликів за хвилину на API-токен (SAPI: на access token), auth-ендпоінти 20 за хвилину на IP та захисний поріг 600 за хвилину на IP для /api/v1. Серверну інтеграцію за однією IP це не зачіпає; вищі ліміти встановлюємо на запит, напишіть очікуваний пік.
  • Місткість: обсяг не обмежений прайс-листом, відправлення асинхронне (виклик передає документ, доставка триває у фоні), а пакетний виклик приймає до 100 документів за раз; для запланованого піку напишіть нам заздалегідь очікуваний обсяг, і ми підвищимо ліміт ключа.
  • Polling є повноцінним шляхом: GET /sapi/document/sent і /receive з ?since та ?until кожні 1–5 хвилин; вебхуки є доповненням, а не умовою.
  • Часові позначки (§ 76a абз. 2 літ. d): sentAt = передача службі доставки (чим виконано обов'язок виставника за § 85o абз. 11), deliveredAt = підтвердження Access Point отримувача через MLS, fsReportedAt = звіт до фінансового управління; для отриманих документів creationDateTime = отримання. Усі три є в кожному рядку /sapi/document/sent, у /sapi/document/sent/{id} та у webhook-ах (плюс occurredAt).
  • PDF: GET /sapi/document/receive/{id}/pdf і GET /sapi/document/sent/{id}/pdf (посилання також у links.pdf) повертають PDF постачальника, якщо документ його містить, інакше PDF, згенерований з XML; HTML для друку є на …/html (портал ?format=html).
  • C#/.NET та інші мови: згенеруйте клієнт з OpenAPI (NSwag, Kiota, openapi-generator); власного пакета NuGet ми не постачаємо.
  • Обсяг ключа: під час створення API-ключа (сторінка API-ключі) ви обираєте, чи охоплює він усі компанії облікового запису (зокрема додані пізніше), чи лише вибрані. Виклик із ключем для іншої компанії повертає 403 token_company_not_allowed (SAPI-SK: SAPI-AUTH-003); ротація ключа зберігає обсяг. Ключа лише для читання поки що немає.
  • Базовий шлях: усі виклики SAPI-SK, зокрема наші розширення (GET /sapi/document/sent, GET /sapi/document/receive/{id}/pdf, GET /sapi/discovery), ідуть під /sapi з тим самим access token і заголовком X-Peppol-Participant-Id. Відповідь 401 “Authentication required” без коду SAPI-… означає, що шлях поза /sapi (наприклад /api/v1/document/sent); /api/v1 є API порталу й очікує як Bearer ключ vpt_, а не SAPI access token.
  • Дату виставлення (BT-2) ми не звіряємо з днем передачі на доставку: документ потрапляє в мережу в момент отримання, тому надсилайте його в день виставлення і не ставте в чергу через північ. Документ в іноземній валюті ми звітуємо фінансовому управлінню із сумою податку в EUR з BT-110 і BT-111 (TaxCurrencyCode EUR), як показує зразок 03.
  • Дата постачання: в XML її несе BT-72 (cac:Delivery/cbc:ActualDeliveryDate); податковий документ на отриману оплату несе в BT-72 дату отримання оплати (зразок 12). Наші власні рахунки за послугу та документи з порталу вказують її завжди, навіть коли вона збігається з датою виставлення (§ 74 абз. 1 літ. d закону про ПДВ вимагає її лише при розбіжності). Під час читання беріть BT-72, якщо немає, то BT-7 (cbc:TaxPointDate), інакше дату виставлення.

Бюджети лімітів запитів (поточні значення)

Вікно 60 секунд. Кожна відповідь містить RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset і RateLimit-Policy (limit;w=вікно в секундах), 429 також Retry-After. Значення можуть зростати без попередження; читайте заголовки, а не цю таблицю.

ВикликиКлюч бюджетуЛіміт
/sapi/* і /api/mcp з токеномclient_id за токеном (ротація access token не скидає)300 / хв
/api/v1/* з API-ключем або сесієюключ (хеш) або сесія300 / хв
POST /sapi/auth/token, renew, revokeIP60 / хв
/api/v1/auth/* (вхід, скидання)IP20 / хв
Публічні інструменти (/api/v1/public/peppol-check, валідатор)IP15 / хв
Масова перевірка (/public/peppol-check/batch)IP6 / хв
Реєстрація, забутий пароль, контактна формаIP15 / год
Захисна стеля для всього з неперевіреним bearerIP600 / хв
http
HTTP/2 200
RateLimit-Limit: 300
RateLimit-Remaining: 287
RateLimit-Reset: 41
RateLimit-Policy: 300;w=60
Відповідь 429 на /sapi, крім error і message, містить code SAPI-SYS-003, retryable true і correlation_id. Платформи з багатьма орендарями за однією IP: повідомте очікуваний пік, бюджет налаштуємо індивідуально.

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); неплатник ПДВ надсилає лише 10 цифр DIČ, SK додаємо ми
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). Відповідь може містити додатковий масив warnings[] з тими самими необов'язковими підказками, що й /document/validate (номер TEST-, отримувач із того самого облікового запису, дата виставлення, що не є днем відправлення); підказка ніколи не блокує документ.

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

ЗаголовокОпис
AuthorizationBearer <access_token>
X-Peppol-Participant-Idучасник, від імені якого Ви відправляєте (напр. 0245:2121358349, цифри DIČ (словацького податкового ідентифікаційного номера) без префікса "SK")
Idempotency-Keyодин ключ на один рахунок, похідний від чогось сталого (наприклад, Ваша система + ідентифікатор або номер рахунку); повторний виклик із ним повертає початковий результат і ніколи не доставляє двічі, а новий ключ для того самого рахунку цей захист обходить. Ключ діє в межах компанії (X-Peppol-Participant-Id). Виняток: якщо перша спроба так і не потрапила в мережу (помилка валідації, неповний запит, одержувач не публікує тип документа, точка доступу припинила повторні спроби, помилка передачі зі статусом failed) або завершилася як undeliverable, той самий ключ виконає відправлення знову, тож «виправити й надіслати повторно» працює під тим самим номером рахунку; порядок дій у примітці Виправлення й повторне надсилання нижче. Ключ ніколи не закінчується: він зберігається в записі документа, який ми зберігаємо постійно (ретенція видаляє лише вміст), тож повтор із тим самим ключем повертає початковий результат навіть через місяці.
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 завжди є джерелом істини для відображення в порталі та для вебхуків. documentTypeId: повний ідентифікатор busdox-docid-qns; голий namespace або лише CustomizationID ми нормалізуємо до типу, виведеного з payload, тип, що суперечить payload, відхиляємо помилкою SAPI-VAL-001; схема учасника має бути зі списку EAS.

Помилки: 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)

HTTP-код і вердикт. За національним контрактом SAPI-SK відправлення завжди відповідає 202, а вердикт міститься в тілі (status ACCEPTED або REJECTED). Якщо Ви хочете, щоб HTTP-код також ніс вердикт, надішліть заголовок Prefer: handling=strict (RFC 7240): синхронна відмова тоді повертається як 422 з конвертом помилки SAPI (SAPI-VAL-002 при помилці валідації, SAPI-RES-003, коли одержувачу неможливо доставити; details[] містять providerDocumentId і detail), а відповідь має заголовок Preference-Applied: handling=strict. ACCEPTED не змінюється. Перед передачею точці доступу ми виконуємо той самий пошук SML, що й вона. Документ спочатку проходить валідацію: ми приймаємо та повідомляємо лише валідний документ, невалідний отримує REJECTED з validation_failed навіть тоді, коли одержувача немає в мережі. Одержувач, якого взагалі немає в мережі Peppol, означає ACCEPTED з undeliverable: true: ми прийняли документ і повідомляємо його Фінансовій адміністрації незалежно від доставки (§ 85o ч. 11, FS FAQ 9/DPH/2025/IM, частина II, приклад 9), але нікому він не доставляється; у GET /sapi/document/sent він має статус undeliverable, вебхук отримує invoice.undeliverable, e-mail нікому не надсилається, а той самий Idempotency-Key надсилає знову після виправлення ідентифікатора одержувача або після його реєстрації (порядок дій у примітці Виправлення й повторне надсилання нижче). Одержувач, який є в мережі, але не публікує тип документа, одразу отримує REJECTED без спроби доставки. retrying: true при ACCEPTED означає, що перша спроба доставки не вдалася (наприклад, тимчасово недоступний SMP) і точка доступу повторює її сама, зазвичай протягом 20 хвилин; detail містить причину, а остаточний вердикт надходить через GET /sapi/document/sent або вебхук.
Виправлення й повторне надсилання. Кожна спроба, яку API приймає до обробки (відповідь 202, при handling=strict також 422), отримує власний providerDocumentId, також відхилена.
  • REJECTED під час нашої перевірки перед відправленням (помилка валідації, неповний запит, одержувач не публікує тип документа, у його записі SMP для цього типу немає кінцевої точки, точка доступу припинила повторні спроби): у мережу нічого не потрапило, нічого не доставлено і Фінансовій адміністрації нічого не повідомляється. Виправте дані й надішліть документ знову з тим самим Idempotency-Key. Нова спроба отримає новий providerDocumentId; перший запис залишається у списку відправлених як rejected із причиною, лише як слід невдалої спроби, і видалити його не можна. У своїй системі завжди прив’язуйте рахунок до останнього providerDocumentId. Номер рахунку може залишитися тим самим, адже в розумінні закону рахунок ще не виставлено. Дата виставлення (BT-2) однак має бути днем, коли рахунок фактично відправлено: електронний рахунок вважається виставленим у день його передачі службі доставки, і надіслати його треба не пізніше ніж через 15 днів від постачання або отримання оплати (FS FAQ 9/DPH/2025/IM, частина I, приклад 74). Якщо виправлений рахунок відправляєте пізнішого дня, змініть дату виставлення на цей день.
  • Передано в мережу (ACCEPTED без undeliverable: submitted, delivered або повтор у фоні; сюди належить і документ, який після передачі відхилило підтвердження MLS одержувача і який повторний виклик повертає як REJECTED із причиною): той самий ключ повертає результат цього відправлення, і нічого не надсилається двічі. Доставлений рахунок ніколи не надсилайте повторно; його виправляють кредит-нотою (381) або дебет-нотою (383).
  • undeliverable (одержувач не має адреси в мережі Peppol): рахунок передано, про нього повідомляється Фінансовій адміністрації незалежно від доставки, і обов’язок виставника виконано (FS FAQ 9/DPH/2025/IM, частина I, приклади 42 і 75). Ключ звільняється. Якщо ідентифікатор одержувача був хибний (наприклад, IČO або DIČ з помилкою замість 0245:<10 цифр DIČ>, або одержувач є в мережі під іншим ідентифікатором), виправте ідентифікатор і надішліть знову з тим самим ключем; рахунок залиште незмінним (той самий номер і дата), бо його вже передано. 8-значне число є IČO, і в мережі його ніколи не знайдено. Якщо ідентифікатор правильний, а одержувач просто не зареєстрований, надішліть йому той самий рахунок іншим шляхом, найкраще його XML електронною поштою (PDF лише як попередній перегляд). Згідно з FS FAQ, частина I, приклад 75, це повторне надсилання того самого рахунку, а не виставлення нового, тому не виставляйте новий рахунок з іншим номером. Щойно одержувач зареєструється, той самий рахунок можна надіслати через Peppol знову, повторивши виклик з тим самим Idempotency-Key.
  • Неправильний ідентифікатор одержувача або порожній власний: заголовок X-Peppol-Participant-Id лише зі схемою (наприклад 0245:, коли в налаштуваннях програми немає DIČ компанії) при відправленні відхиляється з 403 SAPI-AUTH-003 і поясненням, а /document/validate з таким заголовком додає попередження у warnings ще до відправлення. Одержувач, заданий як 0088 (GLN) або як 0245 з 8 цифрами (IČO замість DIČ), у словацькій мережі не знаходиться: документ завершується як undeliverable, а його statusReason (detail у відповіді на send) містить підказку, який ідентифікатор використати: 0245 і 10 цифр DIČ.
  • Запобігайте помилкам: перед відправленням викличте POST /sapi/document/validate (ті самі правила, що й при відправленні, нічого не зберігає і не надсилає) та GET /sapi/discovery?receiverId=… (чи є одержувач у мережі і які типи документів він приймає). Остаточний стан дають GET /sapi/document/sent?invoiceNumber=…, GET /sapi/document/sent/{id}, POST /sapi/document/sent/status або вебхуки invoice.delivered, invoice.rejected і invoice.undeliverable.
POST/sapi/document/validateBearer (access)

Перевіряє документ без відправлення: ті самі правила EN 16931 + Peppol BIS 3.0, які точка доступу застосовує перед відправленням. Нічого не зберігається і не відправляється; працює й із sandbox-токеном. Тіло = JSON-пара { payload, payloadFormat } як у /document/send або безпосередньо XML (Content-Type: application/xml). Ліміт 10 МБ. Відповідь також містить масив warnings[] з необов'язковими підказками (наприклад номер TEST-, отримувач, який є іншою компанією того самого облікового запису, або дата виставлення BT-2, що не є днем відправлення); підказка ніколи не блокує документ.

curl
curl -X POST https://peppol.verteco.digital/sapi/document/validate \
-H 'Authorization: Bearer eyJ…' \
-H 'Content-Type: application/xml' \
--data-binary @rakhunok.xml
# 200 OK
{ "valid": false,
  "errors": [ "BR-CO-15: Invoice total amount with VAT (BT-112) = … " ],
  "warnings": [],
  "checkedAt": "2026-09-10T12:00:00Z" }

Помилки: SAPI-AUTH-002 (401) · SAPI-VAL-001 (400: порожнє тіло, недійсний JSON, payloadFormat не XML, > 10 МБ) · SAPI-SYS-002 (502: валідатор тимчасово недоступний, повторіть)

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

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/document/receive/{documentId}/xmlBearer (access)

Архівне посилання (metadata.links.xml): сам діловий документ як XML-файл, той самий вміст, що й payload у деталях.

GET/sapi/document/receive/{documentId}/htmlBearer (access)

Архівне посилання (metadata.links.html): загальне придатне для друку відображення рахунку (HTML).

GET/sapi/document/receive/{documentId}/pdfBearer (access)

Архівне посилання (metadata.links.pdf): PDF документа. Якщо постачальник вклав у XML власний PDF рахунку (BT-125), ви отримаєте цей оригінал; інакше PDF, згенерований на вимогу зі збереженого XML (PDF не зберігається). Заголовок X-Verteco-Pdf-Source: supplier | generated. 404 SAPI-RES-002 після видалення вмісту, 503 коли рендерер недоступний (повторіть пізніше або використайте /html).

GET/sapi/document/receive/{documentId}/attachments/{index}Bearer (access)

Архівне посилання (metadata.links.attachments[].url): байти одного вкладення, вбудованого в документ, напр. PDF-оригінал постачальника. Примусове завантаження.

POST/sapi/document/receive/{documentId}/public-linkBearer (access)

Посилання без входу (необов’язково): видає НОВИЙ випадковий ключ для документа ({"rotate":true} замінює наявний). Повертає url (сторінка), xmlUrl, htmlUrl, pdfUrl та expiresAt; ключ показується лише раз. У компанії має бути увімкнено «завантаження без входу» (інакше 403 SAPI-AUTH-004). DELETE відкликає його.

Архів замість копії: кожен отриманий документ несе в метаданих поля links (xml, html, pdf, вкладення) та retention. Інтегратор може зберігати поряд із проведеним документом лише посилання і завантажувати документ під час перегляду; посилання вимагають того самого Bearer-токена та заголовка X-Peppol-Participant-Id. retention.mode = storage означає, що компанія архівує отримані документи в нас і ми зберігаємо оригінал протягом усього договірного відношення (Умови 11a.1). retention.mode = secure означає, що компанія не архівує отримані документи в нас: вміст безповоротно видаляється в момент retention.contentAvailableUntil, тобто запланованої дати видалення, збереженої для кожного документа (за замовчуванням 14 днів від отримання; строк задається окремо для отриманих і відправлених документів, і кожна зміна налаштування для наявних документів відлічується від дня зміни, ніколи не раніше), після чого посилання повертають SAPI-RES-002; null у contentAvailableUntil при режимі secure означає, що ми ще утримуємо вміст через незавершене податкове звітування і дати не обіцяємо. Архів власник компанії налаштовує в деталях компанії окремо для отриманих та виставлених документів. Посилання без авторизації: якщо власник у деталях компанії увімкне «Завантаження рахунків без авторизації», POST /sapi/document/receive/{id}/public-link поверне посилання з власним випадковим ключем, яке відкриває документ без токена (url для людини, xmlUrl і htmlUrl для програм). Ключ є в цій відповіді рівно один раз; посилання діє щонайдовше до contentAvailableUntil, його можна відкликати (DELETE), а після закінчення воно повертає 410 із причиною, тоді запитайте нове. Без налаштування в порталі виклик повертає 403 SAPI-AUTH-004.
Посилання без входу: поля links.* завжди вимагають Bearer-токен (архівні посилання). Якщо в компанії увімкнено «завантаження без входу» (деталі компанії → Архів даних або PUT /companies/{id}/public-links), деталь документа містить metadata.publicLink з готовими адресами url, xmlUrl, htmlUrl і pdfUrl – та сама адреса при кожному читанні й та сама, яку користувач бачить у порталі біля рахунку. Збережіть її біля проведеного документа; POST …/public-link потрібен лише, щоб примусово видати новий ключ. Якщо опцію вимкнено, publicLink.issued=false з reason=public_links_disabled. Посилання постійне: воно діє, доки зберігається вміст документа (для компанії без архівування отриманих документів до retention.contentAvailableUntil), тому expiresAt дорівнює null (у відповідях SAPI поле відсутнє) і нічого не потрібно оновлювати. xmlUrl і links.xml повертають сам діловий документ (корінь Invoice/CreditNote) без транспортного конверта SBDH. pdfUrl і links.pdf повертають PDF, який постачальник вклав у XML (BT-125), якщо він є, інакше PDF, згенерований з XML; заголовок X-Verteco-Pdf-Source вказує, який саме (supplier | generated).

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

GET/sapi/discovery?receiverId=0245:2121358349

Попередня перевірка перед відправленням: чи зареєстровано отримувача в мережі Peppol і які типи документів він може отримувати? Той самий SML 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)

Підтвердження MLS і докази доставки

Підтвердження MLS (Peppol Message Level Status) є відповіддю Access Point отримувача на нашу передачу: AP = прийнято й доставлено, AB = доставлено без ділового підтвердження, RE = відхилено з причиною. Портал зберігає його разом із відправленим документом і за ним змінює стан: AP і AB обидва означають delivered (при AB statusDetail починається з «MLS AB: », а mls.responseCode дорівнює AB; за SPOG on MLS це доставка без ділового підтвердження, а не застереження), RE означає rejected. Згідно з § 76a абз. 2 літ. d закону 222/2004 провайдер повинен довести дату й час відправлення, доставки та отримання; кожний рядок GET /sapi/document/sent і кожний webhook несуть ці три часи: sentAt (передача службі доставки, чим за § 85o абз. 11 виконано обов'язок виставника), deliveredAt (підтвердження Access Point отримувача через MLS) і fsReportedAt (звіт до фінансового управління). Іноземний Access Point може ніколи не надіслати MLS: документ тоді залишається delivered з деталлю as4_receipt_only і без підтвердження.

GET/sapi/document/sent/{documentId}Bearer (access)

Деталі одного відправленого документа: той самий рядок, що й у списку (sentAt, deliveredAt, fsReportedAt, hasMls, links) плюс mls.responseCode (AP/AB/RE), mls.receivedAt і mls.url. mls дорівнює null, доки підтвердження не надійде.

json
// 200 OK
{ "document": {
    "documentId": "…", "peppolMessageId": "befc9112-…", "status": "delivered",
    "sentAt": "2026-09-17T08:00:12Z", "deliveredAt": "2026-09-17T08:00:31Z", "fsReportedAt": null,
    "hasMls": true,
    "links": { "detail": "…/sapi/document/sent/…", "mls": "…/sapi/document/sent/…/mls" } },
  "mls": { "responseCode": "AP", "receivedAt": "2026-09-17T08:00:31Z", "url": "…/sapi/document/sent/…/mls" } }

Помилки: SAPI-AUTH-002 (401) · SAPI-AUTH-003 (403) · SAPI-RES-001 (404: чужий або отриманий документ) · SAPI-RES-004 (404: підтвердження ще немає)

GET/sapi/document/sent/{documentId}/mlsBearer (access)

Підтвердження як файл: MLS ApplicationResponse від Access Point отримувача з посиланням на peppolMessageId передачі. Доказ доставки або відхилення; примусове завантаження. SAPI-RES-004, доки підтвердження не надійшло.

GET/sapi/document/sent/{documentId}/xmlBearer (access)

Вміст відправленого документа (SAPI 1.8.15): чистий UBL XML, який ми передали мережі (транспортна обгортка знята), примусове завантаження. Пара до посилань на отримані документи: програма зовнішнього бухгалтера може так завантажити й ВИСТАВЛЕНІ рахунки клієнта. Кожен рядок містить links.xml, links.html і links.pdf. SAPI-RES-002 після видалення вмісту згідно з налаштуванням зберігання компанії.

GET/sapi/document/sent/{documentId}/htmlBearer (access)

Друкований вигляд відправленого документа, згенерований зі збереженого XML (нічого не зберігається).

GET/sapi/document/sent/{documentId}/pdfBearer (access)

PDF відправленого документа: власний PDF виставника, вкладений у XML (BT-125), якщо є, інакше згенерований з XML; заголовок X-Verteco-Pdf-Source: supplier | generated. 503 SAPI-PROC-001, доки генератор недоступний (використайте /html).

Посередники: ті самі виклики із заголовком X-Peppol-Participant-Id клієнта повертають підтвердження всіх керованих компаній одним токеном; у порталі те саме підтвердження є в деталях відправленого рахунку (Завантажити підтвердження), інструмент MCP get_document також його містить.

Докази звіту ФС, цілісність і хронологія (SAPI 1.8.14)

Від версії 1.8.14 кожен рядок GET /sapi/document/sent, деталі відправленого та список і деталі отриманих документів містять об'єкт fsReport: state = reported (звіт передано до пункту збору C5, reportedAt = fsReportedAt), pending (звіт ще належить подати, передача не вдалася і повторюється автоматично, reason = c5_unavailable) або not_required (звіт не виникає; reason пояснює чому: cross_border, self_send_test, issuer_without_vat_id, recipient_without_vat_id, not_billing_document, tdd_disabled, before_2026_09_01, not_recorded). Після передачі з'являється tddMessageId (SBDH InstanceIdentifier звіту), після відповіді C5 c5ResponseCode (AP/AB/RE), c5ResponseAt, c5Detail і підсумок outcome: accepted (AP), accepted_with_reservations (AB), rejected (RE) або null, поки C5 не відповіло. outcome = rejected означає, що звіт передано, але фінансове управління його відхилило (c5Detail містить порушене правило, напр. BR-AE-08); state залишається reported, бо передача відбулася, і портал автоматично надсилає виправлений звіт повторно (після прийняття outcome стає accepted). Відправлені рядки додатково мають statusReason (машинний код за statusDetail: network_retrying, network_retrying_sent, as4_receipt_only, recipient_not_registered, transport_failed, mls_rejected, validation_failed), xmlSha256 (SHA-256 переданого XML, зберігається й після видалення вмісту), retention і receiptRetention = permanent (підтвердження MLS ніколи не видаляється). Підтвердження в деталях має mls.sha256 і mls.messageId. Отримані документи отримали peppolMessageId, status (received/acknowledged), receivedAt, acknowledgedAt і xmlSha256 (SHA-256 байтів бізнес-документа саме таких, як їх видає links.xml, без транспортної обгортки SBDH; обчислюється при отриманні і зберігається після видалення вмісту). Обидва списки фільтруються через ?fsReport=reported|pending|not_required|rejected (rejected = outcome rejected), відправлені також через ?status=undeliverable. Відповідь POST /sapi/document/send містить peppolMessageId уже при прийнятті. Усе додано як нові поля, наявні поля не змінилися.

POST/sapi/document/sent/statusBearer (access)

Стан до 200 відправлених документів одним викликом: ті самі рядки, що й у списку, плюс mls, якщо підтвердження вже надійшло. Id, що не є відправленими документами цієї компанії, повертаються в missing; виклик через них не провалюється. Замінює N викликів GET /sapi/document/sent/{id} під час синхронізації ERP.

json
// POST { "documentIds": ["7c1e…", "9af0…", "невідоме"] }  (max 200)
{ "documents": [ {
    "documentId": "7c1e…", "status": "delivered", "statusReason": null, "peppolMessageId": "befc9112-…",
    "sentAt": "2026-09-21T08:00:12Z", "deliveredAt": "2026-09-21T08:00:31Z", "fsReportedAt": "2026-09-21T08:05:40Z",
    "fsReport": { "state": "reported", "reportedAt": "2026-09-21T08:05:40Z", "reason": null, "outcome": "accepted",
                  "tddMessageId": "3f2a…", "c5ResponseCode": "AP", "c5ResponseAt": "2026-09-21T08:06:02Z", "c5Detail": null },
    "xmlSha256": "9b74…", "retention": { "mode": "storage", "contentAvailableUntil": null }, "receiptRetention": "permanent",
    "hasMls": true, "links": { "detail": "…", "mls": "…" },
    "mls": { "responseCode": "AP", "receivedAt": "2026-09-21T08:00:31Z", "url": "…", "sha256": "e1c0…", "messageId": "mls-…" } } ],
  "missing": ["9af0…", "невідоме"] }

Помилки: SAPI-AUTH-002 (401) · SAPI-AUTH-003 (403) · SAPI-VAL-001 (400: 0 / > 200 id)

GET/sapi/document/sent/{documentId}/eventsBearer (access)

Хронологія документа за часом: submitted, network_retrying, delivered / rejected / undeliverable / failed, mls_received, fs_reported, fs_c5_verdict, content_wiped, webhook_delivered та інші (невідомі типи ігноруйте). Фаза 1 виводиться зі збережених фактів, а не з журналу кожної проміжної зміни стану.

Помилки: SAPI-AUTH-002 (401) · SAPI-AUTH-003 (403) · SAPI-RES-001 (404: чужий або отриманий документ)

GET/sapi/document/receive/{documentId}/eventsBearer (access)

Хронологія отриманого документа: received, acknowledged, fs_reported, fs_c5_verdict, content_wiped, доставки вебхуків.

Вебхуки: кожна подія invoice.* містить той самий об'єкт fsReport; нові події invoice.report_pending (передача звіту не вдалася, він залишається належним і повторюється; один раз на документ) та invoice.report_rejected (C5 відхилив звіт, c5Detail містить причину). Нові події надходять лише інтеграціям, підписаним на всі події; на невідомий тип відповідайте 2xx. Тестове середовище повертає fsReport not_required з reason tdd_disabled для зразкового документа та порожній documents для пакетного виклику. При відхиленні fsReport.outcome має значення rejected, а документ можна знайти через ?fsReport=rejected. Самовиставлення (код документа 389, рахунок виставляє покупець): документ ми доставимо, але звіт до Фінансової адміністрації для нього поки не гарантуємо, бо звіт формується за постачальником, названим у документі, а не за відправником; fsReport може залишитися pending або rejected. Перед запуском самовиставлення напишіть нам.

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

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 для служби підтримки. У разі помилки автентифікації (SAPI-AUTH-001) обгортка додатково містить hint (зрозуміле пояснення, що саме належить до Client Id і Client Secret) та docs (посилання на інструкцію; програми MK-soft спрямовуються одразу на /navody/mksoft#prepojenie). Обидва поля необов'язкові й відсутні в інших випадках (1.8.20).

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 с); у разі збою ми повторюємо до 12 разів з експоненційною затримкою (30 с → макс. 8 год, загалом близько 16 годин), потім dead-letter. HTTP 401/403 означає, що Ваш endpoint вимагає автентифікації, якої ми не надсилаємо; натомість перевіряйте підпис webhook-signature і відповідайте 2xx. Отже, збій Вашого сервера не втрачає сповіщення; ми доставимо його при наступній спробі. Захист від SSRF блокує loopback/локальні адреси; URL вебхука має бути публічною.

GET/companies/{id}/notificationssession / token

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

PUT/companies/{id}/notificationsowner / admin

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

ПолеТипОбовʼязковеОпис
webhookUrlstringніпорожньо або http(s) URL, макс. 512
notificationEmailstringніодна адреса або до 5 через кому, макс. 256; кожна отримує листи про отримані рахунки (400 invalid_notification_email / too_many_notification_emails)
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 (відхилено, або мережею, або під час валідації перед відправленням); invoice.undeliverable повідомляє про одержувача без запису в мережі Peppol (прийнято, повідомлено FS, не доставлено). Вони містять ідентифікацію документа та компанії (documentId, invoiceNumber, receiverId, peppolMessageId, companyDic, peppolParticipantId), а також status, statusDetail із причиною відхилення та statusDateTime. Якщо перша спроба доставки не вдалася і точка доступу сама її повторює (зазвичай протягом години), документ залишається submitted, а statusDetail починається з префікса network_retrying: ; після доставки стан стає delivered, після відмови rejected з префіксом network_gave_up: . Завдяки їм Вам не потрібно опитувати стан відправлених рахунків.

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

json
{
"event": "invoice.received",
"eventId": "7f1c2d9e-4b1a-4e3d-9c1f-0a2b3c4d5e6f",
"occurredAt": "2026-09-03T15:04:05Z",
"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"
"occurredAt": "2026-09-03T15:04:05Z",
"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
"occurredAt": "2026-09-03T15:04:05Z",
"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, invoice.undeliverable, invoice.reported, invoice.report_pending, invoice.report_rejected, company.activated, company.deactivated, company.smp_registered_elsewhere і тестова подія webhook.test. Рекомендуємо відкладати невідомий тип події та логувати його; про новий тип ми завжди повідомляємо заздалегідь. Кожна подія також містить occurredAt (час події, ISO-8601 UTC) для впорядкування, а також eventId (те саме значення, що й у заголовку X-Verteco-Delivery-Id): унікальний для кожної події та незмінний при повторній доставці, тому це правильний ключ дедуплікації (peppolMessageId повторюється в invoice.sent, invoice.delivered та invoice.reported). Події invoice.* містять також часи sentAt, deliveredAt, receivedAt і fsReportedAt (ISO-8601 UTC, null, доки факт не настав). invoice.reported надходить, коли податкове повідомлення до Фінансової адміністрації (TDD) щодо документа передано мережі доставки (§ 85o абз. 11), у разі збою C5 навіть із затримкою в кілька днів. Формальні схеми всіх подій наведено в розділі webhooks специфікації OpenAPI.

Партнерський вебхук сповіщень, керування клієнтами (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));
}

Заголовки кожної доставки: X-Verteco-Event (назва події), X-Verteco-Delivery-Id (= eventId у тілі, однаковий при кожному повторі), X-Verteco-Signature (HMAC вище) і паралельно заголовки за стандартом Standard Webhooks: webhook-id (= eventId), webhook-timestamp (unix-секунди цієї спроби) та webhook-signature = v1,base64(HMAC-SHA256(secret, id + "." + timestamp + "." + body)). Ключ = байти Вашого секрету в UTF-8; бібліотека standardwebhooks очікує його як whsec_ + base64(secret). Рекомендована обробка: перевірте підпис, відхиляйте доставку з webhook-timestamp старшим за 5 хвилин (захист від повторного відтворення), обробляйте ідемпотентно за eventId, відповідайте 2xx протягом 15 секунд, а важку обробку відкладайте у власну чергу. Невдалу доставку ми повторюємо 12 разів з інтервалом від 30 с до 8 год (загалом близько 16 годин); потім вона потрапляє в dead-letter із сповіщенням e-mail і залишається видимою в Realtime-логу. Продуктивна webhook-URL має бути https://; тестове середовище приймає також http://.

Секрет Ви отримуєте через 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 Ви розрізняєте їх за companyId (і receiverId).
  • За сотень компаній дотримуйтеся ліміту запитів на токен (поточне значення повертається в заголовку 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 (після реєстрації)
statusstring–pending_verification | active
rolestring–owner | admin | member | viewer (Ваша роль)
createdAtInstant–час створення

Document

ПолеТипОбовʼязковеОпис
idUUID–ідентифікатор документа
directionstring–sent | received
peppolMessageIdstring|null–ID повідомлення 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 }

Поля завантажуються безпосередньо з опублікованого openapi.json, тож таблиці завжди збігаються з тим, що повертає API. Описи англійською.

Завантаження моделей даних з openapi.json…

Глосарій

DIČ
Словацький податковий ідентифікаційний номер (10 цифр). Словацький Peppol ID = 0245: + цифри DIČ, без SK.
IČ DPH
Ідентифікаційний номер платника ПДВ (SK + DIČ). Є лише в платників ПДВ; неплатник виставляє з категорією O.
IČO
Реєстраційний номер організації (8 цифр). Поле ico в API, BT-30 в UBL.
Верифікаційний токен (VÚ)
Підпис Фінансової адміністрації, що виникає при виборі провайдера на порталі FS; розблоковує відправлення для компанії.
VPDS
Застосунок FS, де платник податків обирає провайдера служби доставки (нас).
TDD
Tax Data Document, звіт про рахунок для Фінансової адміністрації; ми формуємо і надсилаємо його за вас.
C5 / C6
П’ятий і шостий кути моделі Peppol: точка доступу Фінансової адміністрації, що приймає TDD (0242:001180).
MLS
Message Level Status, квитанція від точки доступу одержувача (AP = прийнято, RE = відхилено, AB = підтверджено).
SBDH
Standard Business Document Header, конверт, у якому документ подорожує мережею; його InstanceIdentifier = peppolMessageId.
SML / SMP
Каталог мережі: SML знаходить SMP одержувача, SMP повідомляє точку доступу і типи документів, які одержувач приймає.

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

Поза межами 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 МБ кожне; при надсиланні весь XML разом із base64-вкладеннями має бути до 10 МБ через SAPI-SK і до 2 МБ через вкладку порталу Odoslať súborom. Peppol не визначає єдиного ліміту для всієї мережі; окремі постачальники встановлюють власні (FS FAQ 9/DPH/2025/IM, приклад № 67), тому для дуже великих вкладень також перевірте ліміт постачальника іншої сторони.

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

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

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

Валідація е-рахунка за схемою UBL 2.1, 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 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"
}

MCP-сервер (ШІ-асистенти)

Портал має власний сервер для Model Context Protocol, відкритого стандарту, через який ШІ-асистенти (Claude Code, Claude Desktop, Cursor, VS Code Copilot та інші) підключаються до зовнішніх систем. Асистент входить звичайним API-ключем облікового запису й отримує шість інструментів; він ніколи не бачить більше, ніж цей обліковий запис, і кожен виклик з’являється в журналі API ключа.

Адреса: https://peppol.verteco.digital/api/mcp. Транспорт: Streamable HTTP, JSON-RPC 2.0, без стану (POST /api/mcp, без SSE-потоку, GET повертає 405). Вхід заголовком Authorization: Bearer <API-ключ>. Підтримувані методи: initialize, ping, tools/list, tools/call, resources/list, prompts/list.

Інструменти

  • list_companies: компанії облікового запису з Peppol ID, станом і роллю (початок кожної розмови)
  • list_documents: надіслані/отримані рахунки компанії зі станом доставки та звіту до податкової, посторінково
  • get_document: один рахунок детально, включно з квитанцією MLS і звітом, за бажанням UBL XML (до 1 МБ)
  • check_participant: жива перевірка отримувача в мережі Peppol (SML)
  • validate_document: валідація UBL за EN 16931 + Peppol BIS 3.0
  • send_document: надсилання рахунка від імені компанії, потребує confirm = true, діє перевірка Verifikačný údaj

Підключення в Claude Code

bash
claude mcp add --transport http verteco-peppol https://peppol.verteco.digital/api/mcp \
  --header "Authorization: Bearer vpt_..."

Claude Desktop (через міст mcp-remote, потрібен Node.js)

json
{
  "mcpServers": {
    "verteco-peppol": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://peppol.verteco.digital/api/mcp", "--header", "Authorization: Bearer vpt_..."]
    }
  }
}

Надсилання рахунка є юридично зобов’язальним: інструмент відхиляє виклик без confirm = true, а інструкції сервера зобов’язують асистента отримати явну згоду користувача на конкретний рахунок і отримувача. Готові конфігурації для Cursor і VS Code та кнопка створення ключа є в порталі: API-ключі → вкладка MCP-сервер. API-ключі → MCP-сервер

Надсилання електронною поштою (адреса компанії)

У порталі компанія вмикає власну адресу <24 випадкові символи>@peppol.send.verteco.app. Лист із вкладенням UBL XML, надісланий на цю адресу з дозволеної поштової скриньки, ми відправляємо через мережу Peppol так само, як якби файл завантажили на вкладці Надіслати файлом; відправник отримує одну відповідь з результатом за кожне вкладення, а документ доступний у порталі та API зі статусом доставки, квитанцією MLS і звітом FS. Налаштування: З’єднання та інтеграції → Надсилання електронною поштою (власник або адміністратор компанії, після входу). /dashboard/integrations/email

Правила обробки

  • Приймаємо лише листи з адреси, що є в списку дозволених відправників компанії (не більше 20); усе інше відкидаємо без відповіді.
  • За замовчуванням домен відправника має пройти перевірку SPF або DKIM на сервері доставки (вирівнювання як у DMARC, relaxed). Сервер доставки додатково відхиляє листи, які не пройшли ні SPF, ні DKIM, та листи всупереч політиці DMARC відправника. Перевірку можна вимкнути в налаштуваннях; не рекомендуємо.
  • Вкладення: UBL 2.1 Invoice або CreditNote (Peppol BIS Billing 3.0), розширення .xml, за потреби в конверті SBDH; не більше 10 вкладень у листі, 15 МБ на вкладення, 200 листів на адресу за день. PDF і текст листа не обробляються.
  • IFS Finvoice 2.0: вкладення .xml з SOAP-конвертом IFS (IFSFinvoice) або сам Finvoice ми перетворюємо на UBL і далі обробляємо так само. Правила перетворення: INV02 або від’ємна сума = кредит-нота (381) з додатними сумами та посиланням на первинний рахунок (OriginalInvoiceNumber, в IFS OrderIdentifier); продавець і покупець за словацьким ІПН ПДВ (SellerOrganisationTaxCode, BuyerOrganisationTaxCode → 0245:DIČ), покупець поза Словаччиною не перетворюється; розбивка ПДВ із VatSpecificationDetails, рядки з 0 % як категорія E з підставою з VatFreeText, інакше „Oslobodené od DPH“; рядки округлення IFS (база 0,00, ПДВ 0,01) пропускаються, ціна за одиницю, що не збігається із сумою рядка, перераховується; одиниці за UN/ECE (kg → KGM, pcs → H87, h → HUR, невідомі → C62 з оригінальним текстом у примітці рядка); вбудоване зображення рахунка (InvoiceAttachments, PDF) додається до документа до 5 МБ; лише EUR. Результат перетворення зазначено у відповіді та в журналі компанії.
  • Адреса для результатів: якщо рахунки надсилає системна поштова скринька, у налаштуваннях оберіть іншу адресу для відповіді з результатом (replyTo у PUT /companies/{id}/email-send, порожнє = відповісти відправнику).
  • Продавець у XML (EndpointID постачальника, BT-34) має бути цією компанією, інакше лист відхиляється (переслана рахунок-фактура вашого постачальника ніколи не відправляється як ваша). Покупець повинен мати EndpointID зі схемою (BT-49).
  • Той самий лист (Message-ID) обробляється один раз. Документ має в API та вебхуках origin = email, дійова особа = адреса відправника.
Адреса є повноваженням: хто її знає і є в списку дозволених, надсилає від імені компанії. Тому її можна будь-коли замінити (Згенерувати нову адресу; стара негайно перестає діяти), і кожне надходження є в журналі компанії та в записі безпеки.

Стан (ping)

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

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

Стан backend.

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

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

Що готово і що в роботі

Уже в продакшні (часто помилково вважають відсутнім)

  • POST /companies/{id}/documents/send — стабільний інтерфейс порталу; для ERP-інтеграцій і далі рекомендовано SAPI-SK з Idempotency-Key.
  • Реєстрація в SMP відбувається автоматично після вибору на порталі FS; перехід від іншого провайдера через POST /companies/{id}/smp-migrate з міграційним кодом.
  • Квитанції MLS, докази доставки та звіти FS (fsReport) у кожному рядку /sapi/document/sent; повторне відправлення вебхуків за часове вікно.
  • Ключі, обмежені обраними компаніями; MCP-сервер для ШІ-асистентів; зразки UBL на /vzory; публічний валідатор.

У підготовці (у порядку попиту інтеграторів)

  • Асинхронний batch: POST /sapi/document/batch відповідає 202 з посиланням на job і статусом по кожній позиції.
  • Канал змін GET /sapi/document/changes?since&cursor з курсором замість офсетної пагінації.
  • Термін дії та ротація API-ключів у порталі, ключ лише для читання.
  • Кілька кінцевих точок вебхуків на компанію з фільтром подій.
Бракує чогось конкретного? Напишіть на [email protected], що саме і для скількох документів; це впливає на черговість.