Вступ
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-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
Створіть обліковий запис у порталі
Зареєструйтеся за допомогою електронної пошти і підтвердьте її за посиланням з електронного листа. - 2
Згенеруйте API-токен
У порталі перейдіть до API tokeny → Vytvoriť (API-токени → Створити). Токенvpt_…показується лише один раз. Зберігайте його надійно. - 3
Зробіть перший виклик
Використайте токен у заголовкуAuthorization:javascriptconst res = await fetch('https://peppol.verteco.digital/api/v1/companies', { headers: { Authorization: 'Bearer vpt_8f2a…' }, }); const companies = await res.json(); - 4
Вибір постачальника на порталі Фінансової адміністрації
У продуктивному середовищі вибір Verteco на порталі FS (vpds.financnasprava.sk) потрібен навіть для суто відправлення: він розблоковує відправлення (верифікаційний токен) і активує компанію. Отримання при цьому може лишитися в постачальника вашої бухгалтерської програми: у мережі компанія має рівно одного отримувача, але може мати кілька відправників.
Швидкий старт із curl (спочатку в тестовому середовищі)
Шість викликів від облікового запису до першого доставленого рахунку, усі до test.peppol.verteco.digital, де компанія активна одразу після створення, а документи йдуть у тестову мережу Peppol. Очікувані відповіді скорочено.
export BASE=https://test.peppol.verteco.digital # production: https://peppol.verteco.digital
export KEY=vpt_… # step 1- 1
Обліковий запис і API-ключ
Зареєструйтеся на test.peppol.verteco.digital/register (у тестовому середовищі без листа підтвердження) і створіть ключ на сторінці API-ключі. Він показується один раз; нижче $KEY.
- 2
Перевірте ключ
shellcurl -s $BASE/api/v1/auth/me -H "Authorization: Bearer $KEY"json{ "id": "7f1d…", "email": "dev@firma.sk", "emailVerified": true, "persona": "developer" } - 3
Створіть компанію
shellcurl -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
Access token SAPI
shellcurl -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
Перевірте без відправлення
shellcurl -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
Надішліть і стежте за статусом
shellcurl -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"jsonHTTP/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" } } ] }
Тестове середовище (sandbox)
Окрім 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), саме через відсутність тестового режиму на боці Фінансової адміністрації.
Автентифікація
Ваша інтеграція автентифікується за допомогою API-токена в заголовку Authorization: Bearer vpt_…. Токен Ви створюєте в порталі (API-токени); він має формат vpt_ + 40 hex-символів, ми зберігаємо лише його SHA-256 хеш, і він має той самий доступ, що і Ваш обліковий запис. Перевірте його через /auth/me:
curl https://peppol.verteco.digital/api/v1/auth/me -H 'Authorization: Bearer vpt_8f2a…'
# 200 → { "id": "…", "email": "vy(at)firma.sk" } (token works)Якщо токен відсутній або недійсний, API повертає:
// 401 Unauthorized
{ "error": "unauthorized", "message": "Authentication required" }portal_session, JWT, 7 днів); для інтеграції server-to-server вона Вам не потрібна. Публічними без автентифікації є /ping, /openapi.json та endpoint-и під /public/* (перевірка peppol-check, валідатор peppol-validate, докладніше в розділі Публічні інструменти, і стан сервісу через status); усе інше вимагає сесії або Bearer-токена.Конвенції та формати
| Тип | Формат | Приклад |
|---|---|---|
id | UUID (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.
Помилки
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 (перша помилка для кожного поля).
// 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)
error. Відповідь без JSON-тіла (HTML або текст, як error code: 1010 зі статусом 403, або 502/504 під час розгортання) надійшла не від API, а від інфраструктури перед ним (захист периметра, шлюз). Типова причина 403/1010: загальний User-Agent бібліотеки (Python-urllib, Java/1.8.x на тестовому домені); рішення описано в розділі Тестове середовище.Найчастіші коди помилок
| Код | HTTP | Коли |
|---|---|---|
validation_failed | 400 | тіло не пройшло валідацію (див. fields) |
unauthorized | 401 | відсутній або недійсний API-токен |
forbidden | 403 | дія вимагає ролі owner/admin |
company_not_found | 404 | компанія не існує або Ви не є її учасником |
ico_taken | 409 | компанія з таким IČO (реєстраційним номером компанії) вже існує |
ico_immutable | 400 | IČO не можна змінити |
company_dic_missing | 400 | верифікація для відправлення без DIČ компанії (словацького податкового ідентифікаційного номера) |
token_invalid | 400 | верифікаційний токен (Verifikačný údaj, підпис) не збігається |
document_not_found | 404 | документ не існує |
token_not_found | 404 | API-токен не існує / не належить Вам |
rate_limited | 429 | надто багато запитів |
Збій точки доступу та повторні спроби
- Якщо API відповідає
502,503або504, або не відповідає взагалі, документ ми не прийняли: повторіть виклик пізніше з тим самимIdempotency-Key, нічого не буде надіслано двічі. - Документ, який API прийняв (
202ACCEPTED, також із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-004 | IP-адреса не в списку дозволених для ключа (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_exists | An account already exists for this e-mail. Sign in and accept the invitation in the portal. |
account_inactive | Your account is not active. Please contact us. |
account_under_review | Your account is being reviewed. Call us or write to [email protected]. |
acknowledge_required | Confirm that you understand the risks of downloads without login. |
acknowledgement_required | Confirm that you understand the consequences of terminating the contract. |
address_book_full | The address book is full. Remove unused clients and try again. |
admin_email_unverified | Administration access requires a verified e-mail address. Click the link in the message we sent you at sign-up. |
admin_mfa_required | Administration access requires two-factor authentication. Turn it on in Settings. |
ai_budget | The AI draft budget is used up or you reached the daily limit. Write the reply manually. |
ai_failed | The reply draft could not be generated. Please try again. |
ai_unavailable | AI reply drafts are not available right now. |
already_completed | The company transfer has already been completed. |
already_member | This user already has access (member of the company or your team). |
attachment_external | This attachment is stored at the sender as a link, not inside the invoice itself. |
attachment_invalid | An attachment could not be sent (type not allowed, corrupted content or size exceeded). Check the attachments and try again. |
attachment_not_found | The attachment was not found. |
attachment_not_readable | The attachment could not be read. |
billing_unconfigured | Subscription payments are not available yet. |
blocked | The test webhook cannot be sent to this address (local or internal addresses are not allowed). |
body_required | Please write the text of your message. |
body_too_long | The message can have at most 4000 characters. |
cannot_change_self | You cannot change your own role. Ask the other company administrator. |
cannot_invite_self | You cannot invite yourself or accept your own invitation. |
cannot_release_to_self | The company is already under this account. |
cannot_remove_owner | The company owner cannot be removed. Ownership changes through a company transfer. |
cannot_restrict_admin | A portal administrator account cannot be restricted this way. |
cannot_transfer_self | The company already belongs to this e-mail. |
captcha_failed | The bot check failed. Please try again. |
captcha_required | The bot check failed; reload the page and try again. |
channel_unknown | An old record without a known channel cannot be replayed. Re-POST it manually to the right endpoint. |
chat_not_found | The conversation was not found or is empty. |
client_not_found | The company does not belong to this partner account. |
client_not_removable | The company cannot be removed: it is verified by the Financial Administration, active, registered in the SMP or has documents. Use release instead. |
company_active | An active company cannot be deleted. |
company_address_required | Before sending an invoice, add the company address (street, city, postal code) in the company details. |
company_already_active | The company is already active; activation instructions are not needed. |
company_dic_missing | Add the company DIČ (tax ID) first, then try the verification again. |
company_incomplete | Before signing, complete the company details: legal name, IČO, Peppol identifier and full address. |
company_limit | You reached the maximum number of companies per account. Contact support and we will raise the limit. |
company_name_mismatch | The legal name does not match the official register (ŽR/OR SR) for this IČO. |
company_not_active | A migration code can only be issued for an active company registered in the Peppol network. |
company_not_found | The company was not found. |
company_not_registered | The company is not activated yet: complete the Verteco selection on the Financial Administration portal, then you can send. |
company_not_verified | Migration is possible only after selecting Verteco on the Financial Administration portal (the company must be active and verified). |
company_verified_locked | The 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_mismatch | The entered name does not match the registered reseller name. |
confirmation_required | Signing requires confirming your authority and your agreement with the wording. |
conflict | This record already exists. |
content_unavailable | The content of this document is no longer stored or cannot be read as an invoice. |
contract_pending | The 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_invalid | Country must be a two-letter ISO code (SK, CZ, AT, DE…), not a name. |
country_outside_eu | The online application is open to entities established in an EU member state. Entities outside the EU: write to [email protected]. |
current_ip_missing | The list must include your current IP address, otherwise you would lock yourself out after signing out. |
daily_limit | You reached the daily message limit. Try again tomorrow or write to [email protected]. |
delivery_failed | The test webhook could not be delivered; your endpoint did not respond. |
delivery_not_found | The webhook delivery record was not found. |
deregister_cooldown | Only one company per IP address can be removed every 60 seconds. Try again in a moment. |
dic_immutable | The Peppol identifier cannot be changed: it is the identity of the company in the Peppol network. |
dic_required | Enter the company DIČ (tax ID: SK + 10 digits). |
dic_taken | A company with this DIČ already exists in the portal. |
directory_unavailable | The central SMP is not responding or refused the change. Please try again in a moment. |
document_no_xml | The stored original XML is gone; the report cannot be rebuilt. |
document_not_found | The document was not found. |
document_too_large | The document is too large (limit 3 MB). |
domestic_subject | A Slovak entity submits the application after signing in at /sprostredkovatel/ziadost. |
duplicate_invoice_number | A document with this number was already sent. A new document needs a new number; the same document is never sent twice. |
email_change_cooldown | We already sent the confirmation e-mail. You can request another one in 10 minutes. |
email_invalid | Enter a valid e-mail address. |
email_not_verified | Confirm your e-mail first. We sent you the link. |
email_send_company_not_active | Sending by e-mail can be switched on only for an active company with a Peppol identifier. |
email_send_unavailable | Sending by e-mail is not available in this environment. |
email_taken | This e-mail address is already used by another account. |
email_unchanged | This is your current e-mail address. |
empty_document | Paste the invoice XML. |
empty_idea | Please tell us what we should improve. |
empty_message | The message is empty. |
empty_reply | The reply is empty. |
entry_not_found | The address book client was not found. |
export_format_unknown | Unknown export format. |
forbidden | You are not allowed to do this. |
forwarder_unreachable | The document processing service is not responding. Try again in a moment. |
fs_change_already_sent | The request has already gone to the Financial Administration and cannot be cancelled. File a new one if needed. |
fs_change_confirm_required | Confirm that you request all the changes at once. |
fs_change_cooldown | The next change request can be filed 48 hours after the previous one. |
fs_change_field_readonly | The company ID and tax ID cannot change; a new identity means a new registration. |
fs_change_no_changes | You have not entered any change against the data at the Financial Administration. |
fs_change_not_found | The change request was not found. |
fs_change_not_open | The request is already closed. |
fs_change_not_queued | Only a request waiting to be sent can be sent now. |
fs_change_pending | One change request is already waiting or with the Financial Administration. File the next one once it is closed. |
fs_secret_invalid | The 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_mismatch | The 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_documents | The company has documents in the archive; deletion is blocked (statutory archiving). |
holding_unavailable | Releasing the client is not possible right now. Contact support. |
ico_immutable | The IČO cannot be changed. |
ico_required | The IČO is required (8 digits). |
ico_taken | A company with this IČO already exists under another account. Sign in with it or write to us. |
instructions_cooldown | We already sent the instructions for this company. They can be sent again after 24 hours. |
integration_not_found | Unknown integration. |
internal | An unexpected error occurred. Please try again. |
internal_error | An unexpected server error occurred. Please try again; the error has been logged. |
invalid_action | Unknown action. |
invalid_after | The after parameter must be an ISO 8601 date and time (e.g. 2026-09-05T10:00:00Z). |
invalid_amount | The amount must be a number. |
invalid_billing_model | Unknown billing model. Choose one of the offered models. |
invalid_country | Select the country of the registered office. |
invalid_credentials | Incorrect e-mail or password. |
invalid_current_password | The current password is not correct. |
invalid_date | The date must be in the format YYYY-MM-DD. |
invalid_default_company | The default company must be one of your companies. |
invalid_dic | Enter a valid DIČ (10 digits, optionally with the SK prefix) or VAT ID. |
invalid_direction | The document direction must be sent or received. |
invalid_due_days | The due period must be 0 to 365 days. |
invalid_email | Enter a valid e-mail address. |
invalid_feed_url | The feed URL must start with https://. |
invalid_ico | Enter a valid IČO (8 digits) or company registration number. |
invalid_id | Enter a Slovak VAT ID or DIČ (e.g. SK2121358349) or a Peppol ID (e.g. 0245:2121358349). |
invalid_ids | The list of documents is not valid. |
invalid_invite | The invitation is invalid or has already been used. |
invalid_ip_entry | The 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_key | The reseller key must have 3 to 40 characters: lowercase letters, digits and hyphens. |
invalid_limit | The limit must be at least 1, or empty (default value). |
invalid_link | The sign-in link is invalid or has expired. Request a new one. |
invalid_locale | Unsupported language. |
invalid_month | The month must be in the format YYYY-MM. |
invalid_notification_email | One of the addresses is not a valid e-mail: |
invalid_notify_event | Unknown notification event. |
invalid_notify_locale | The e-mail language must be Slovak, English, German or Hungarian. |
invalid_notify_mode | Unknown notification mode. Choose: every event, daily digest, weekly digest or none. |
invalid_password | Incorrect password. |
invalid_pattern | The numbering format must have at most 64 characters and contain the sequence {N}, {NNN} or {NNNN} exactly once. |
invalid_payload | The invoice (XML) is missing or too large. |
invalid_persona | Unknown account role. |
invalid_phone | Enter the phone number as +421 9xx xxx xxx (digits, spaces, optionally hyphens). |
invalid_prefs | The display settings contain an invalid value and could not be saved. |
invalid_receiver | The recipient must have a Peppol identifier in the form scheme:value (e.g. 0245:2121358349). |
invalid_request | Required data is missing (e.g. company name, 10-digit DIČ, valid e-mail or endpoint URL). |
invalid_role | The role must be administrator, member or read-only. |
invalid_seq | The next sequence number must be at least 1. |
invalid_session | Invalid conversation. Reload the page and try again. |
invalid_signature | The payment notification could not be verified. |
invalid_signup | The sign-up is no longer valid or has expired. Start the registration again. |
invalid_sort | Unknown sort order. |
invalid_state | Unknown state. |
invalid_status | Unknown status. |
invalid_tag | The tag cannot be empty. |
invalid_token | The link is invalid or has already been used. |
invalid_vpds_url | The selection link must start with https://vpds.financnasprava.sk/. |
invalid_web | The website must be a valid address (https://...). |
invalid_webhook_url | The webhook URL must be a valid https:// address (at most 512 characters). |
invalid_window | The time window is not valid: from must be before to and the window at most 31 days. |
invalid_xml | The document XML cannot be read (corrupted file or a DOCTYPE declaration, which is not allowed). |
invite_email_mismatch | This invitation is for a different e-mail address. Sign in with the account it was sent to. |
invite_expired | The invitation has expired. Ask for a new one. |
ip_not_allowed | Signing in from this IP address is not allowed for this account. |
lead_no_email | The lead has no e-mail address and cannot be contacted. |
lead_not_contactable | Only a lead in the state new can be contacted. |
lead_not_found | The lead was not found. |
link_gone | This link is no longer valid (expired, revoked, or the document content is no longer stored). |
lookup_unavailable | The register or verification service is currently unavailable. Try again in a moment. |
malformed_request | The request is not in a valid format. Reload the page and try again. |
manager_required | Only the company owner or an administrator can make this change. |
member_is_owner | This user is the company owner. Ownership changes through a company transfer. |
member_not_found | The member was not found. |
members_full | The company reached the maximum number of members. |
method_not_allowed | This operation is not supported for this address. |
mfa_already_enabled | Two-factor authentication is already turned on. |
mfa_code_invalid | The code does not match. Try the current code from your app or a backup code. |
mfa_not_enabled | Backup codes belong to two-factor authentication. Turn it on first. |
mfa_not_started | Start the two-factor authentication setup first. |
mfa_required | Enter the code from your authenticator app. |
migration_code_live | The previous migration code is still valid. Cancel it first. |
migration_code_none | There is no active migration code request. |
migration_code_pending | A migration code request is already in progress. |
migration_code_rejected | The SMP rejected the migration code. Check it with the previous provider; codes are single-use and time-limited. |
migration_code_required | Enter the migration code from the previous provider. |
migration_rejected | The central SMP rejected the takeover request. Try again or write to us. |
missing_fields | The name and the owner e-mail are required. |
missing_parameter | A required parameter is missing from the request. |
mls_not_available | No delivery receipt (MLS) is available for this document yet. |
name_required | Enter the name (client name or legal name). |
no_billing_account | You do not have a billing account yet. Set up a subscription first. |
no_body | The record has no stored request body and cannot be replayed. |
no_content | The document content is no longer available; the link cannot be issued. |
no_dic | The company has no DIČ (tax ID). |
no_documents | There are no documents (with stored XML) for the selected period. |
no_evidence | Neither the original XML nor a delivery receipt is stored for this document. |
no_ids | Select at least one document. |
no_owner | The company has no owner. Use direct reassignment instead. |
no_secret | The signing key does not exist yet. Set the notification webhook URL first. |
no_verification_token | The company has no stored verification token from the Financial Administration; SMP registration requires it. |
not_a_reseller | This account is not the owner of a reseller registration. |
not_acceptable | The server answers in JSON format only. |
not_available_for_white_label | Not available for companies under a reseller brand. |
not_failed | Only failed webhooks can be retried. |
not_found | Record not found. |
not_reseller | This account is not the owner of a reseller registration. |
not_sandbox_row | This reseller registration is managed by an administrator and cannot be switched off from the account. |
note_too_long | The note can have at most 200 characters. |
notification_emails_too_long | The addresses are too long together (256 characters at most). |
owner_not_found | No owner account exists for this e-mail. Create it first. |
owner_of_companies | To 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_required | Only the owner of the company account can do this. |
participant_not_registered | The company has no record in the central SMP under Verteco yet; set the listing after registration. |
partner_managed | This company is managed by its intermediary; the contract confirmation is issued by them. |
party_missing_in_text | The text being signed does not contain the company identification. Reload the page and try again. |
password_already_set | You already have a password. Use the change password option. |
password_not_set | The account has no password. Set one in Settings and try again. |
password_required | Set a password first (Security); then you can confirm this change. |
payment_mismatch | The payment could not be matched to the application. Please contact us. |
payment_unconfigured | Payment is not available right now. Try later or contact us. |
pdf_unavailable | PDF generation is temporarily unavailable. Try again in a moment or use Print / PDF. |
profile_too_long | One of the profile fields is too long. Shorten the text. |
public_link_exists | The document already has an active link. Choose to replace it if you want a new one. |
public_links_disabled | The company has not enabled invoice downloads without login. The owner can turn it on in the company details (Data archive). |
public_links_unavailable | Public document links are currently switched off. |
rate_limited | Too many requests. Try again in a moment. |
read_only_member | The read-only role cannot change document states or tags. |
received_only | A public link is issued only for received documents. |
receiving_toggle_cooldown | Receiving 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_elsewhere | The participant is still registered with another provider; the code did not trigger the takeover. |
renderer_unavailable | The preview cannot be rendered right now (the rendering service is restarting). Try again in a moment; sending the invoice is not blocked. |
reply_already_cancelled | This reply was cancelled by a colleague in the meantime. |
reply_already_sent | This reply has already been sent; it cannot be cancelled or sent again. |
reply_not_found | The scheduled reply was not found. |
reply_to_invalid | The results address is not a valid e-mail address. |
representative_incomplete | Enter both the name and the position of the authorised person, or leave both fields empty. |
request_rejected | The 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_found | The reseller was not found. |
reseller_owner | Your account owns a reseller registration. Arrange its hand-over with support; then you can delete the account. |
reseller_required | This part is only for the account of a registered intermediary. |
sbd_not_available | This document has no stored transport envelope (SBDH). Download the document XML instead. |
schedule_not_found | This scheduled export no longer exists. |
sender_email_invalid | The sender address is not a valid e-mail address. |
sender_email_system | Automated mailboxes (noreply, postmaster, mailer-daemon…) cannot be added; use a person's or the invoicing system's mailbox. |
sender_exists | This address is already on the allow-list. |
sender_limit | At most 20 allowed senders are possible. |
sending_not_verified | Sending is not allowed: the company does not have a verified provider selection on the Financial Administration portal yet. |
sending_paused | Sending is paused for this company by its managing account. Receiving invoices continues. |
service_unavailable | The service is temporarily unavailable. Please try again in a moment. |
session_full | This conversation is too long. Reload the page and start a new one. |
session_not_found | The device was not found. |
shoptet_feed_blocked | The address points to a private network. Paste the public address of your shop. |
shoptet_feed_http | Shoptet refused the address. Check the hash in the address and that the export is not limited to one IP address. |
shoptet_feed_invalid_xml | The export response is not valid XML. Check the address in Shoptet. |
shoptet_feed_not_configured | The Shoptet connection is not set up yet. |
shoptet_feed_not_orders_xml | This is not a Shoptet order export: the address must end with /export/orders.xml. |
shoptet_feed_not_system_xml | Paste the address of the “System Shoptet XML” export (its address contains patternId=-11). Custom templates, CSV and XLS are not supported. |
shoptet_feed_too_large | The 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_unreachable | The Shoptet export did not respond. Try again in a moment; Shoptet allows only one export at a time. |
sidlo_incomplete | The address must contain street, postal code and city, e.g. "Ulica 1, 010 01 Mesto". |
smp_cancel_failed | Cancelling the code at the central SMP failed. Try again in a moment or write to [email protected]. |
smp_deregister_failed | Deregistration from the Peppol network failed. Try again in a moment. |
smp_held_elsewhere | This company's registration is held by another provider. No migration code from us is needed. |
smp_not_test | The test environment is not connected to the test SMP correctly. Please write to us. |
smp_unavailable | The central SMP is not responding right now; try again in a moment. |
smtp_fromAddress_required | Enter the sender address. |
smtp_fromAddress_too_long | The sender address is too long. |
smtp_from_forbidden | The sender address cannot be on a Verteco domain. |
smtp_from_invalid | The sender address is not a valid e-mail. |
smtp_from_not_yours | The sender address must be on your company's domain (like the owner, member or company notification e-mail). |
smtp_from_taken | This sender address is already used by another company. |
smtp_host_blocked | The server cannot be found in DNS or is not publicly reachable (internal addresses are not allowed). |
smtp_host_invalid | Enter the server's domain name (e.g. smtp.company.com), not an IP address. |
smtp_host_required | Enter the SMTP server address. |
smtp_host_too_long | The SMTP server address is too long. |
smtp_incomplete | Fill in the server, port, username, password and sender address. |
smtp_password_invalid | The password must not contain spaces or line breaks. |
smtp_password_required | Enter the SMTP account password (it must be re-entered when the server changes). |
smtp_port_not_allowed | Allowed ports are 465, 587 and 2525. |
smtp_security_invalid | Security must be STARTTLS or SSL. |
smtp_test_cooldown | A test e-mail can be sent once per minute. Try again in a moment. |
smtp_test_failed | The test e-mail could not be sent. Check the SMTP server settings. |
smtp_username_invalid | The username must not contain spaces or line breaks. |
smtp_username_required | Enter the SMTP account username. |
smtp_username_too_long | The username is too long. |
state_not_for_direction | This state is not possible for the document direction (received or sent). |
stripe_error | The payment gateway could not be opened or the payment could not be verified. Please try again. |
support_not_on_sandbox | Support runs on the production portal peppol.verteco.digital, not in the test environment. |
tag_too_long | The tag is too long. |
target_blocked | The target account is blocked; the transfer is not possible. |
team_full | You reached the maximum number of team members. |
termination_confirmed | A confirmed termination notice cannot be cancelled from the app. Write to [email protected]. |
termination_pending | A termination request is already in progress. Confirm it via the e-mail link or cancel it. |
terms_not_accepted | You need to accept the terms and conditions to create an account. |
test_document_in_production | Test 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_expired | The request has been closed for more than 90 days; the link is no longer valid. Write to us again at [email protected]. |
ticket_not_found | The request was not found or the link is not valid. |
token_companies_required | Select at least one company the key may access. |
token_company_not_allowed | This API key has no access to this company (it was created for selected companies only). |
token_company_not_member | A key can only cover companies your account is a member of. |
token_expired | The link has expired. Request a new one. |
token_invalid | The link or verification token is invalid or no longer valid. |
token_limit | You have too many active API keys (max 50). Revoke unused ones and try again. |
token_not_allowed | This setting can only be changed after signing in to the portal, not with an API key. |
token_not_found | The API key was not found. |
token_not_revoked | This API key is active; there is nothing to restore. |
token_restore_expired | The key was revoked more than 7 days ago and can no longer be restored. Create a new key. |
token_scope_invalid | The key scope must be "all" or "selected". |
too_many_ids | At most 500 documents can be processed at once. |
too_many_notification_emails | Enter at most 5 e-mail addresses. |
too_many_schedules | A company can have at most five scheduled exports. Delete one before adding another. |
too_many_tags | The document has too many tags. |
too_many_tickets | You have too many open requests. Please wait for a reply. |
transfer_canceled | The company transfer was cancelled. |
transfer_expired | The transfer link has expired. Request a new transfer. |
transfer_stale | The company ownership changed in the meantime; the transfer was cancelled. |
unauthorized | Please sign in again. |
unknown_document | Only the DPA, SLA and NDA documents can be signed. |
unsupported_document | The preview can render only an invoice or a credit note (UBL Invoice or CreditNote). |
unsupported_media_type | This content type is not accepted. Send the data as JSON. |
user_not_found | No account with this e-mail was found. The user needs to register first. |
validation_failed | Some fields are not filled in correctly. |
validator_unavailable | Validation is currently unavailable. Try again in a moment. |
verification_code_rejected | The SMP rejected the verification token from the FS selection; repeat the selection. |
verification_token_missing | The verification token from the FS selection is missing; repeat the selection and try again. |
verified_company_required | Only an account with at least one verified company can submit the application. |
version_stale | The document wording changed in the meantime. Reload the page and sign the current version. |
webhook_not_configured | Set and save the webhook URL first. |
webhook_url_https_required | In production the webhook URL must start with https:// (a delivery carries customer identifiers and a signature). |
webhook_url_unreachable | The webhook URL must be publicly reachable. Localhost and internal networks cannot be reached from our servers. |
white_label_owner_fixed | A 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_endpoint | This is not the token endpoint. Use POST /sapi/auth/token with client_id and client_secret. |
xml_not_available | The original XML is not stored for this document; its content is no longer available. |
xml_required | The document XML is missing, the preview cannot be rendered. |
xml_too_large | The 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/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, revoke | IP | 60 / хв |
/api/v1/auth/* (вхід, скидання) | IP | 20 / хв |
Публічні інструменти (/api/v1/public/peppol-check, валідатор) | IP | 15 / хв |
Масова перевірка (/public/peppol-check/batch) | IP | 6 / хв |
Реєстрація, забутий пароль, контактна форма | IP | 15 / год |
Захисна стеля для всього з неперевіреним bearer | IP | 600 / хв |
HTTP/2 200
RateLimit-Limit: 300
RateLimit-Remaining: 287
RateLimit-Reset: 41
RateLimit-Policy: 300;w=60API-токени
Непрозорі (opaque) токени vpt_… для доступу server-to-server. Відкритий текст показується лише один раз при створенні. Збережіть його. Ми зберігаємо лише SHA-256 хеш і 12-символьний префікс для відображення.
/tokenssession / tokenСписок Ваших активних токенів (без секрету), createdAt за спаданням.
/tokenssession / tokenСтворює токен; повертає відкритий текст (лише один раз).
| Поле | Тип | Обовʼязкове | Опис |
|---|---|---|---|
name | string | так | назва токена, макс. 128 |
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":"…" }/tokens/{id}session / tokenВідкликає токен. Повертає 204.
Помилки: token_not_found (404)
Компанії
Компанії, ідентифіковані за реєстраційним номером (IČO) / номером платника ПДВ (IČ DPH), якими Ви керуєте. Доступ залежить від членства: Ви бачите лише компанії, учасником яких є. Творець компанії стає її owner.
/companiessession / tokenСписок компаній, учасником яких Ви є (з Вашою роллю).
/companiessession / tokenДодає компанію; Ви стаєте її owner, status = pending_verification.
| Поле | Тип | Обовʼязкове | Опис |
|---|---|---|---|
ico | string | так | рівно 8 цифр |
dic | string | так | ІПН ПДВ у форматі SK + 10 цифр (напр. SK2121358349); неплатник ПДВ надсилає лише 10 цифр DIČ, SK додаємо ми |
legalName | string | так | юридична (комерційна) назва, макс. 500 |
registeredAddress | string | ні | адреса зареєстрованого офісу, макс. 1000 |
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)
/companies/{id}session / tokenДеталі компанії (Ви маєте бути учасником).
/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 (менеджер компанії).Верифікація для відправлення (верифікаційний токен, Verifikačný údaj)
Перед відправленням компанію необхідно верифікувати за допомогою верифікаційного токена (Verifikačný údaj, VÚ), підписаного токена, який видає Фінансова адміністрація Словаччини (Finančná správa, FS). Після успішної верифікації status компанії змінюється на active і відправлення розблоковується.
/companies/{id}/verificationowner / adminСамостійна верифікація верифікаційного токена (Verifikačný údaj). У разі успіху встановлює status на active.
| Поле | Тип | Обовʼязкове | Опис |
|---|---|---|---|
token | string | так | VÚ = hex-підпис (prod/pPFS 1024 hex, test/tPFS 768 hex) |
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 за спаданням.
/companies/{id}/documentssession / tokenСписок документів компанії. Опціональний фільтр ?direction=sent|received.
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":"…" } ]/companies/{id}/documents/{docId}session / tokenДеталі одного документа.
Помилки: document_not_found (404)
/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× документи)
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
# 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>'client_id/client_secret з порталу (нижче).Автентифікація
/sapi/auth/tokenclient_credentialsОбмінює client_id + client_secret на access-токен (15 хв) і refresh-токен (30 днів). Збережіть токен і використовуйте його всі 15 хвилин: запит нового токена при кожному виклику є зайвими витратами (ліміт запитів враховує і виклики /auth/token).
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)
/sapi/auth/token/statusBearer (access)Дійсність і термін дії access-токена; should_refresh = true, коли залишається менше 3 хв.
/sapi/auth/renewrefresh tokenВидає новий access + refresh-токен. Не вдається, якщо базовий API-токен було відкликано.
// body
{ "refresh_token": "eyJhbGciOi…" }/sapi/auth/revoke–Завжди повертає успіх (RFC 7009). Постійний kill switch: відкликання API-токена в порталі.
Відправлення документа
/sapi/document/sendBearer (access)Відправляє бізнес-документ Peppol (UBL / BIS 3.0) отримувачу через наш Access Point. Відправлення працює за принципом fail-closed: компанія має мати верифікований верифікаційний токен (Verifikačný údaj). Відповідь може містити додатковий масив warnings[] з тими самими необов'язковими підказками, що й /document/validate (номер TEST-, отримувач із того самого облікового запису, дата виставлення, що не є днем відправлення); підказка ніколи не блокує документ.
Обов'язкові заголовки:
| Заголовок | Опис |
|---|---|
Authorization | Bearer <access_token> |
X-Peppol-Participant-Id | учасник, від імені якого Ви відправляєте (напр. 0245:2121358349, цифри DIČ (словацького податкового ідентифікаційного номера) без префікса "SK") |
Idempotency-Key | один ключ на один рахунок, похідний від чогось сталого (наприклад, Ваша система + ідентифікатор або номер рахунку); повторний виклик із ним повертає початковий результат і ніколи не доставляє двічі, а новий ключ для того самого рахунку цей захист обходить. Ключ діє в межах компанії (X-Peppol-Participant-Id). Виняток: якщо перша спроба так і не потрапила в мережу (помилка валідації, неповний запит, одержувач не публікує тип документа, точка доступу припинила повторні спроби, помилка передачі зі статусом failed) або завершилася як undeliverable, той самий ключ виконає відправлення знову, тож «виправити й надіслати повторно» працює під тим самим номером рахунку; порядок дій у примітці Виправлення й повторне надсилання нижче. Ключ ніколи не закінчується: він зберігається в записі документа, який ми зберігаємо постійно (ретенція видаляє лише вміст), тож повтор із тим самим ключем повертає початковий результат навіть через місяці. |
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 це маршрутизаційні та технічні поля: 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)
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 або вебхук.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.
/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 -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: валідатор тимчасово недоступний, повторіть)
Отримання документів
/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 обов'язковий.
// 200 OK
{ "documents": [ { "documentId":"…","documentTypeId":"…",
"senderParticipantId":"0088:…","receiverParticipantId":"0245:…",
"creationDateTime":"2026-06-17T…Z" } ],
"nextPageToken": "50" }/sapi/document/receive/{documentId}Bearer (access)Деталі включно з payload (сирий XML, точно так, як він надійшов через Peppol).
Помилки: SAPI-RES-001 (404) · SAPI-RES-002 (404: payload не архівовано)
/sapi/document/receive/{documentId}/acknowledgeBearer (access)Підтверджує, що Ваша система прийняла документ. Ідемпотентний.
/sapi/document/receive/{documentId}/xmlBearer (access)Архівне посилання (metadata.links.xml): сам діловий документ як XML-файл, той самий вміст, що й payload у деталях.
/sapi/document/receive/{documentId}/htmlBearer (access)Архівне посилання (metadata.links.html): загальне придатне для друку відображення рахунку (HTML).
/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).
/sapi/document/receive/{documentId}/attachments/{index}Bearer (access)Архівне посилання (metadata.links.attachments[].url): байти одного вкладення, вбудованого в документ, напр. PDF-оригінал постачальника. Примусове завантаження.
/sapi/document/receive/{documentId}/public-linkBearer (access)Посилання без входу (необов’язково): видає НОВИЙ випадковий ключ для документа ({"rotate":true} замінює наявний). Повертає url (сторінка), xmlUrl, htmlUrl, pdfUrl та expiresAt; ключ показується лише раз. У компанії має бути увімкнено «завантаження без входу» (інакше 403 SAPI-AUTH-004). DELETE відкликає його.
Стан відправлених документів
/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 тут не потрібен.
/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; фільтр за датою постачання).
// 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 і без підтвердження.
/sapi/document/sent/{documentId}Bearer (access)Деталі одного відправленого документа: той самий рядок, що й у списку (sentAt, deliveredAt, fsReportedAt, hasMls, links) плюс mls.responseCode (AP/AB/RE), mls.receivedAt і mls.url. mls дорівнює null, доки підтвердження не надійде.
// 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: підтвердження ще немає)
/sapi/document/sent/{documentId}/mlsBearer (access)Підтвердження як файл: MLS ApplicationResponse від Access Point отримувача з посиланням на peppolMessageId передачі. Доказ доставки або відхилення; примусове завантаження. SAPI-RES-004, доки підтвердження не надійшло.
/sapi/document/sent/{documentId}/xmlBearer (access)Вміст відправленого документа (SAPI 1.8.15): чистий UBL XML, який ми передали мережі (транспортна обгортка знята), примусове завантаження. Пара до посилань на отримані документи: програма зовнішнього бухгалтера може так завантажити й ВИСТАВЛЕНІ рахунки клієнта. Кожен рядок містить links.xml, links.html і links.pdf. SAPI-RES-002 після видалення вмісту згідно з налаштуванням зберігання компанії.
/sapi/document/sent/{documentId}/htmlBearer (access)Друкований вигляд відправленого документа, згенерований зі збереженого XML (нічого не зберігається).
/sapi/document/sent/{documentId}/pdfBearer (access)PDF відправленого документа: власний PDF виставника, вкладений у XML (BT-125), якщо є, інакше згенерований з XML; заголовок X-Verteco-Pdf-Source: supplier | generated. 503 SAPI-PROC-001, доки генератор недоступний (використайте /html).
Докази звіту ФС, цілісність і хронологія (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 уже при прийнятті. Усе додано як нові поля, наявні поля не змінилися.
/sapi/document/sent/statusBearer (access)Стан до 200 відправлених документів одним викликом: ті самі рядки, що й у списку, плюс mls, якщо підтвердження вже надійшло. Id, що не є відправленими документами цієї компанії, повертаються в missing; виклик через них не провалюється. Замінює N викликів GET /sapi/document/sent/{id} під час синхронізації ERP.
// 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)
/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: чужий або отриманий документ)
/sapi/document/receive/{documentId}/eventsBearer (access)Хронологія отриманого документа: received, acknowledged, fs_reported, fs_c5_verdict, content_wiped, доставки вебхуків.
Пакетне відправлення
/sapi/document/batchBearer (access)До 100 документів в одному виклику. Кожен елемент проходить повну логіку одиночного відправлення (ідемпотентність через itemId + idempotencyKey, резервування, submit, вердикт) і повертає власний результат; збій одного елемента не зупиняє інші. Елементи обробляються послідовно; невдалі елементи повторюйте з тим самим idempotencyKey.
// 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).
{ "error": {
"category": "AUTH",
"code": "SAPI-AUTH-001",
"message": "Invalid client credentials.",
"retryable": false,
"correlation_id": "b4191dfc-…" } }Сповіщення та вебхуки
Про отриманий рахунок ми можемо повідомити компанію електронною поштою або вебхуком (POST на Вашу URL-адресу). Доставка надійна (durable): сповіщення зберігається у вихідній черзі та доставляється асинхронно (тайм-аут 15 с); у разі збою ми повторюємо до 12 разів з експоненційною затримкою (30 с → макс. 8 год, загалом близько 16 годин), потім dead-letter. HTTP 401/403 означає, що Ваш endpoint вимагає автентифікації, якої ми не надсилаємо; натомість перевіряйте підпис webhook-signature і відповідайте 2xx. Отже, збій Вашого сервера не втрачає сповіщення; ми доставимо його при наступній спробі. Захист від SSRF блокує loopback/локальні адреси; URL вебхука має бути публічною.
/companies/{id}/notificationssession / tokenНалаштування сповіщень: { webhookUrl, notificationEmail, notificationEmails, hasSecret }.
/companies/{id}/notificationsowner / adminВстановлює обидва канали (порожній рядок вимикає відповідний канал).
| Поле | Тип | Обовʼязкове | Опис |
|---|---|---|---|
webhookUrl | string | ні | порожньо або http(s) URL, макс. 512 |
notificationEmail | string | ні | одна адреса або до 5 через кому, макс. 256; кожна отримує листи про отримані рахунки (400 invalid_notification_email / too_many_notification_emails) |
/companies/{id}/webhooksession / tokenКонфігурація вебхука: { url, hasSecret } (без секрету).
/companies/{id}/webhookowner / adminВстановлює URL вебхука (автоматично генерує секрет для підпису, якщо його ще немає).
| Поле | Тип | Обовʼязкове | Опис |
|---|---|---|---|
url | string | так | http(s) URL, макс. 512 |
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 }/companies/{id}/webhookowner / adminВидаляє як URL вебхука, так і секрет. Повертає 204.
/companies/{id}/webhook/secretowner / adminГенерує новий секрет для підпису та повертає його ОДИН РАЗ; збережіть його для перевірки X-Verteco-Signature.
// 200 OK
{ "secret": "vpt_8f2a…" }/companies/{id}/webhook/testowner / adminСинхронно надсилає тестове сповіщення (подія webhook.test, підписана, із захистом від SSRF) на збережену URL і повертає, ЩО було надіслано і ЩО повернулося. Те саме запускає кнопка „Otestovať webhook“ (Тестувати вебхук) у деталях компанії.
// 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 storedPayload вебхука
Як для отриманого (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:
{
"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 вебхука для всіх своїх клієнтів).
Вердикт мережі щодо відправленого рахунка:
{
"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):
{
"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.
Перевірка підпису
Якщо компанія має секрет, ми надсилаємо заголовок X-Verteco-Signature у формі sha256=HMAC-SHA256(secret, raw body) (hex у нижньому регістрі). Завжди обчислюйте HMAC над точними байтами тіла:
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 і секрет), тож одним і тим самим токеном Ви можете підключити будь-яку кількість компаній:
# 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
| Поле | Тип | Обовʼязкове | Опис |
|---|---|---|---|
id | UUID | – | ідентифікатор компанії |
ico | string | – | реєстраційний номер компанії (IČO, 8 цифр) |
dic | string|null | – | номер платника ПДВ (IČ DPH) |
legalName | string | – | юридична назва |
registeredAddress | string|null | – | адреса зареєстрованого офісу |
peppolParticipantId | string|null | – | учасник Peppol (після реєстрації) |
status | string | – | pending_verification | active |
role | string | – | owner | admin | member | viewer (Ваша роль) |
createdAt | Instant | – | час створення |
Document
| Поле | Тип | Обовʼязкове | Опис |
|---|---|---|---|
id | UUID | – | ідентифікатор документа |
direction | string | – | sent | received |
peppolMessageId | string|null | – | ID повідомлення Peppol |
docTypeId | string|null | – | тип документа (Peppol) |
senderId | string|null | – | відправник (scheme:id) |
receiverId | string|null | – | отримувач (scheme:id) |
invoiceNumber | string|null | – | номер рахунка |
issueDate | date|null | – | дата виставлення |
currency | string|null | – | валюта (напр. EUR) |
totalAmount | number|null | – | загальна сума |
status | string | – | стан обробки |
createdAt | Instant | – | час запису |
User · Token · Webhook
| Поле | Тип | Обовʼязкове | Опис |
|---|---|---|---|
User | object | – | { id: UUID, email: string } |
Token | object | – | { id, name, prefix, lastUsedAt|null, createdAt } |
Webhook | object | – | { 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.
Вкладення документів (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 та перевірок перед відправленням; на них діє суворіший публічний ліміт запитів.
/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 МБ.
curl -X POST https://peppol.verteco.digital/api/v1/public/peppol-validate \
-H "Content-Type: application/xml" \
--data-binary @faktura.xml// 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)/public/peppol-check?id=0245:2121358349публічнийПеревірка отримувача в робочій мережі Peppol (SML lookup): чи він зареєстрований і які типи документів може отримувати? Параметр id приймає Peppol ID (0245:…), номер платника ПДВ (IČ DPH, SK…) або сам DIČ (словацький податковий ідентифікаційний номер). Автентифікований еквівалент для ERP-конвеєрів: GET /sapi/discovery.
// 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.0send_document: надсилання рахунка від імені компанії, потребує confirm = true, діє перевірка Verifikačný údaj
Підключення в Claude Code
claude mcp add --transport http verteco-peppol https://peppol.verteco.digital/api/mcp \
--header "Authorization: Bearer vpt_..."Claude Desktop (через міст mcp-remote, потрібен Node.js)
{
"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, в IFSOrderIdentifier); продавець і покупець за словацьким ІПН ПДВ (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), придатний для моніторингу.
/pingпублічнийСтан backend.
// 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-ключів у порталі, ключ лише для читання.
- Кілька кінцевих точок вебхуків на компанію з фільтром подій.