Dokumentation

Für Entwickler: API-Referenz

Die REST-API des Portals und die nationale Schnittstelle SAPI-SK 1.0: Authentifizierung, Firmen, Belege, Webhooks, Fehler und Limits.

Einführung

Die Verteco API ist REST über HTTPS. Request und Response sind JSON (UTF-8). Beginnen Sie mit dem Anlegen eines Kontos, dann eines API-Tokens, und führen Sie den ersten Aufruf innerhalb einer Minute aus. Alle Pfade sind relativ zur unten angegebenen Basis-URL.

Die komplette Testumgebung (Sandbox) finden Sie auf test.peppol.verteco.digital. Sie verhält sich genauso wie die Produktion und bietet zusätzlich Testwerkzeuge (FS-Webhook, Verifizierungsmerkmal (Verifikačný údaj), Löschen einer Firma) und eine simulierte Anbieterauswahl anstelle des Portals der Finanzverwaltung der Slowakischen Republik (Finančná správa, FS).

Base URL
https://peppol.verteco.digital/api/v1
Version
v1 (im Pfad). Rückwärtsinkompatible Änderungen erscheinen unter einer neuen Version.
Protokoll
nur HTTPS · TLS 1.2+ · TLS A+
Format
application/json (UTF-8)
Auth
Cookie-Session (Portal) oder Bearer-Token (Server-to-Server)
Zeitangaben
ISO-8601 (UTC), z. B. 2026-06-03T09:40:27Z

Zertifizierter AP

Ein echter Peppol Access Point (Seat ID PSK001128), kein Reseller. Wir haben die OpenPeppol-Conformance bestanden (19/19), im Produktivbetrieb.

Valide Belege

Serverseitige Validierung nach EN 16931 + Peppol BIS 3.0 Schematron bei jedem empfangenen UND gesendeten Beleg. Sie können einen Beleg auch vorab prüfen: der öffentliche Validator läuft unter /validator (und als API unter POST /api/v1/public/peppol-validate); Fehler geben wir mit der konkreten Regel zurück (z. B. BR-CO-15). Validierte Muster für slowakische Fälle (Nichtzahler, Fremdwährung, Reverse Charge, Gutschrift, Anzahlungen, eingebettetes PDF) finden Sie unter /de/vzory.

Multi-tenant

Ein Konto und ein Token für N Firmen, ideal für SaaS, ERP und Buchhalter.

SK TDD automatisch

Die Steuermeldung (corner-5 / TDD) an die Finanzverwaltung erzeugen und senden wir für Sie.

Maschinenlesbare Schnittstelle (OpenAPI 3.1): /api/v1/openapi.json. Importieren Sie sie in Postman, öffnen Sie sie im Swagger Editor, oder generieren Sie sich über openapi-generator einen typisierten Client in einer beliebigen Sprache (TS, Java, PHP, Python…). Sie deckt sowohl die Portal-API als auch SAPI-SK ab.

Schnellstart

Welche Schnittstelle passt zu Ihnen

SAPI-SK 1.0 (/sapi)

Buchhaltungs- oder Rechnungssoftware, ERP, Plattformen für mehrere Firmen: die nationale Schnittstelle für Versand, Empfang, Status, Empfangsbestätigungen und FS-Meldungen. Empfohlen für jede Integration, die Belege sendet oder liest.

OAuth2 Client Credentials: client_id = UUID des API-Schlüssels, client_secret = der vpt_-Schlüssel, 15-Minuten-Access-Token.

Portal API (/api/v1)

Firmen, Webhooks, Benachrichtigungen, Exporte und Downloads; Partnerkonsole (/resellers/me). Ergänzt SAPI, ersetzt es nicht.

Authorization: Bearer vpt_… (API-Schlüssel des Kontos).

MCP-Server (/api/mcp)

Ein KI-Assistent (Claude Code, Cursor, Claude Desktop) soll Belege lesen, Empfänger prüfen und nach ausdrücklicher Bestätigung senden.

Bearer vpt_… über den MCP-Client.

E-Mail an das Firmenpostfach

Ohne Programmierung: die XML-Rechnung als Anhang an die geheime Adresse der Firma; wird validiert und wie aus dem Portal gesendet.

Absenderadresse auf der Freigabeliste + SPF/DKIM.

Konto und API-Token legen Sie im Portal an (über den Browser). Die Integration läuft danach ausschließlich über den API-Token. Registrierung, Anmeldung und Passwörter muss Ihre App nicht behandeln.

  1. 1

    Legen Sie ein Konto im Portal an

    Registrieren Sie sich per E-Mail und bestätigen Sie es über den Link in der E-Mail.
  2. 2

    Generieren Sie einen API-Token

    Im Portal API tokeny → Vytvoriť (API-Tokens → Erstellen). Der Token vpt_… wird nur einmal angezeigt. Bewahren Sie ihn sicher auf.
  3. 3

    Führen Sie den ersten Aufruf aus

    Verwenden Sie den Token im Header Authorization:
    javascript
    const res = await fetch('https://peppol.verteco.digital/api/v1/companies', {
    headers: { Authorization: 'Bearer vpt_8f2a…' },
    });
    const companies = await res.json();
  4. 4

    Anbieterauswahl im Portal der Finanzverwaltung

    In der Produktion ist die Auswahl von Verteco im FS-Portal (vpds.financnasprava.sk) auch bei reinem Versand nötig: sie schaltet das Senden frei (Verifizierungsmerkmal) und aktiviert die Firma. Der Empfang kann beim Anbieter Ihres Buchhaltungsprogramms bleiben: eine Firma hat im Netz genau einen Empfänger, aber beliebig viele Sender.

Schnellstart mit curl (zuerst in der Testumgebung)

Sechs Aufrufe vom Konto bis zur ersten zugestellten Rechnung, alle gegen test.peppol.verteco.digital, wo eine Firma sofort aktiv ist und Belege ins Peppol-Testnetz gehen. Erwartete Antworten sind gekürzt.

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

    Konto und API-Schlüssel

    Registrieren Sie sich auf test.peppol.verteco.digital/register (in der Testumgebung ohne Bestätigungs-E-Mail) und erstellen Sie auf der Seite API-Schlüssel einen Schlüssel. Er wird einmal angezeigt; unten $KEY.

  2. 2

    Schlüssel prüfen

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

    Firma anlegen

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

    SAPI-Access-Token

    shell
    curl -s -X POST $BASE/sapi/auth/token -H "Content-Type: application/json" -d '{"grant_type":"client_credentials","client_id":"<Schlüssel-UUID von der Seite API-Schlüssel>","client_secret":"'$KEY'"}'
    json
    { "access_token": "eyJhbGciOiJIUzI1NiJ9…", "token_type": "Bearer", "expires_in": 900,
      "refresh_token": "eyJhbGciOiJIUzI1NiJ9…" }
  5. 5

    Ohne Versand validieren

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

    Senden und Status verfolgen

    shell
    curl -s -X POST $BASE/sapi/document/send -H "Authorization: Bearer $ACCESS" -H "X-Peppol-Participant-Id: 0245:2120000001" -H "Idempotency-Key: FA-2026-0001" -H "Content-Type: application/json" -d @send.json, danach curl -s "$BASE/sapi/document/sent?since=2026-10-01T00:00:00Z" -H "Authorization: Bearer $ACCESS" -H "X-Peppol-Participant-Id: 0245:2120000001"
    json
    HTTP/2 202
    { "providerDocumentId": "6a3f…", "status": "ACCEPTED", "peppolMessageId": "f1c7…", "receivedAt": "2026-10-03T12:00:01Z" }
    
    { "documents": [ { "documentId": "6a3f…", "status": "delivered", "sentAt": "2026-10-03T12:00:01Z",
      "deliveredAt": "2026-10-03T12:00:14Z", "hasMls": true, "fsReport": { "state": "reported" } } ] }
Go-live: $BASE durch peppol.verteco.digital ersetzen, Produktionskonto und -schlüssel anlegen und den Kunden den Anbieter im Portal der Finanzverwaltung wählen lassen (die Firma aktiviert sich selbst, der Versand wird durch das Verifikationstoken freigeschaltet).

Testumgebung (Sandbox)

Testbelege werden nach 60 Tagen automatisch gelöscht: Die Umgebung dient zum Ausprobieren, nicht zur Archivierung. Das Produktivportal ist von dieser Aufbewahrungsfrist nicht betroffen.

Neben der SAPI-Mock-Sandbox (unten) betreiben wir auch eine vollwertige Testumgebung, eine vollständige Kopie dieses Portals mit getrennten Daten, in der Sie den gesamten Ablauf (Registrierung → Firma → Senden → Empfangen → Benachrichtigungen) end-to-end ausprobieren können, ohne jegliche Auswirkung auf den Produktivbetrieb.

Registrierung
ohne Bestätigungs-E-Mail; das Konto ist sofort nutzbar
Genehmigung der Firma
automatisch, direkt in der Oberfläche oder über die API; ohne Auswahl des Anbieters im Portal der Finanzverwaltung der Slowakischen Republik (Finančná správa, FS) und ohne Anmeldung im FS-Portal; unmittelbar nach dem Anlegen einer Firma mit USt-IdNr. (IČ DPH) können Sie sowohl senden als auch empfangen
Registrierung im Netzwerk
automatisch in das Peppol-Testnetzwerk. Beachten Sie die zwei Ebenen des Identifikators: API und Portal verwenden dasselbe Format wie die Produktion (peppolParticipantId = 0245:<DIČ-Ziffern>, DIČ = slowakische Steuernummer; Ihr Integrationscode ändert sich nicht); im Test-SMP/SML wird die Firma technisch als 9950:SK<DIČ> eingetragen, weil das Schema 0245 einen Verifizierungscode der Finanzverwaltung verlangt, der im Test nicht existiert. In der Produktion wird 0245:<DIČ-Ziffern> erst nach der Auswahl des Anbieters im FS-Portal (Anmeldung per eID oder mit den Zugangsdaten) in das produktive Netzwerk registriert
Validierung
real: Regeln nach EN 16931 + Peppol BIS 3.0, dieselben wie im Produktivbetrieb
Zustellung
real über das Peppol-Testnetzwerk (AS4, Testzertifikat, Test-SML/SMP): ein im Testnetzwerk registrierter Empfänger erhält die Rechnung als empfangene Rechnung (inklusive E-Mail, PDF und Webhook); in das produktive Netzwerk geht nichts hinaus
Zustellnachweis (MLS)
echter MLS-Zustellnachweis aus dem Testnetzwerk
E-Mails
werden real versendet (an die Adressen, die Sie angeben), mit dem Präfix [TEST]
Fehlersimulation
der Header X-Sandbox-Simulate: 503 (oder 502, 500, 429) auf einem beliebigen /sapi/document/*-Aufruf mit gültigem Token liefert den passenden Fehler; nichts wird verarbeitet oder gespeichert. Bei 500 (SAPI-PROC-500) und 429 (SAPI-SYS-003 mit Retry-After) erhalten Sie den SAPI-Fehlerumschlag; 503 und 502 kommen über den Netzwerkrand (DigitalOcean, Cloudflare) als HTTP 504 mit HTML-Body ohne Umschlag an, genau so sieht ein echter Ausfall von außen aus, sodass Sie auch die Verarbeitung einer Nicht-JSON-Antwort testen. Validierungsfehler erzeugen Sie mit ungültigem XML, 429 auch durch mehr als 300 Aufrufe pro Minute. Die Produktion ignoriert den Header
Preis
kostenlos, ohne Limits zum Ausprobieren

Dort funktioniert alles wie hier: Portal, REST API, SAPI-SK 1.0, E-Shop-Plugins und Webhooks. Es genügt, in Ihrer Integration die Domain durch test.peppol.verteco.digital zu ersetzen und die in der Testumgebung erstellten Token zu verwenden. Ideal für die Entwicklung der Integration, CI-Tests und die Schulung von Buchhaltern vor dem Produktivstart. Testbelege gehören nur dorthin: In der Produktion wird jeder inländische Beleg zwischen Umsatzsteuerzahlern an die Finanzverwaltung gemeldet, und die Meldung lässt sich nicht zurückziehen. Im Produktivportal testen Sie nur mit der Schaltfläche „Poslať skúšobnú faktúru“ (Testrechnung senden, 0,00 €); ab dem 1. 1. 2027 lehnt die Produktion Nummern TEST-/VITAJTE-ab (test_document_in_production).

Hinweis: Der Edge-Schutz der Testdomain blockiert die generischen Header User-Agent: Python-urllib und User-Agent: Java/1.8.x (der Standard-User-Agent von HttpsURLConnection in Java 8) mit HTTP 403 "error code: 1010" noch vor unserer API; die Produktivdomain peppol.verteco.digital lässt sie durch. Setzen Sie einen eigenen User-Agent: in Java entweder per JVM-Parameter -Dhttp.agent=meine-app/1.0(ohne Codeänderung; Java hängt "Java/1.8" an, das resultierende "meine-app/1.0 Java/1.8.0_xxx" wird durchgelassen, blockiert wird nur ein Header, der direkt mit "Java/1.8" beginnt) oder auf der Verbindung mit conn.setRequestProperty("User-Agent", "meine-app/1.0"). Gängige Clients (requests, httpx, Java 11+, Apache HttpClient, okhttp, axios, Go, PHP, curl) funktionieren unverändert.

Warum Firmen automatisch genehmigt werden

Die Finanzverwaltung hat keine Testumgebung des VPDS-Portals: Die Auswahl des Anbieters auf vpds.financnasprava.sk läuft nur in der Produktion und wird durch Anmeldung im FS-Portal (eID oder FS-Zugangsdaten) verifiziert, sodass Sie im Produktivbetrieb keine beliebige fremde Firma „auswählen" können. Damit Sie Ihre Integration trotzdem testen können, simulieren wir diesen Schritt in der Testumgebung: Jede Firma, die Sie anlegen, wird automatisch genehmigt (ohne Auswahl bei der FS), sodass Sie Absender und Empfänger anlegen und den gesamten Ablauf durchlaufen können.

Zum Testen der FS-Webhooks (Auswahl des Anbieters) haben wir ein eigenes Gegenstück zum Werkzeug der Finanzverwaltung: test.peppol.verteco.digital/sandbox-nastroje. Dort erzeugen Sie ein gültiges Verifizierungs-Token (Verifizierungsmerkmal, Verifikačný údaj) im Stil der FS und senden einen vollständigen Webhook an Ihren Endpoint, genau so, wie es das FS-Portal bei einer realen Auswahl tut. Zu Testzwecken angelegte Firmen können Sie wiederum deregistrieren (aus dem Portal und aus dem Test-SMP), gerade weil es auf Seiten der Finanzverwaltung keinen Testmodus gibt.

Die Testumgebung ist nicht Teil des produktiven Peppol-Netzwerks: Firmen werden in ein getrenntes Peppol-Testnetzwerk (Test-SMP/SML) registriert, nichts geht an reale Endpoints, und die darin enthaltenen Daten können jederzeit gelöscht werden. Verwenden Sie sie nicht für reale Rechnungen; dafür gibt es den Produktivbetrieb unter peppol.verteco.digital, wo die Registrierung im produktiven Netzwerk durch die per Anmeldung (eID oder FS-Zugangsdaten) bestätigte Auswahl des Anbieters im Portal der Finanzverwaltung freigeschaltet wird.

Authentifizierung

Die Integration authentifiziert sich mit einem API-Token im Header Authorization: Bearer vpt_…. Den Token erstellen Sie im Portal (API-Tokens); er hat das Format vpt_ + 40 Hex-Zeichen, wir speichern nur seinen SHA-256-Hash und er hat dieselben Zugriffsrechte wie Ihr Konto. Testen Sie ihn über /auth/me:

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

Bei fehlendem oder ungültigem Token gibt die API zurück:

json
// 401 Unauthorized
{ "error": "unauthorized", "message": "Authentication required" }
Das Portal (Browser) verwendet ein internes Session-Cookie (portal_session, JWT, 7 Tage); bei einer Server-to-Server-Integration benötigen Sie es nicht. Öffentlich ohne Auth sind /ping, /openapi.json und die Endpoints unter /public/* (Prüfung peppol-check, Validator peppol-validate, Details dazu im Abschnitt Öffentliche Werkzeuge, sowie der Dienststatus status); alles andere erfordert eine Session oder einen Bearer-Token.

Konventionen & Formate

TypFormatBeispiel
idUUID (String)08dd6c1e-…
ZeitstempelISO-8601 Instant (UTC)2026-06-03T09:40:27Z
issueDateDatum (YYYY-MM-DD)2026-06-03
totalAmountDezimalzahl120.00
fehlende Wertenull (Feld ist vorhanden, wird nicht weggelassen)"dic": null

Paginierung & Idempotenz

/companies und /companies/{id}/documents unterstützen optional ?page&limit (die Response bleibt ein JSON-Array; die Gesamtzahl finden Sie in den Headern X-Total-Count / X-Total-Pages). Ohne Parameter geben sie das gesamte Array zurück, Belege nach createdAt absteigend sortiert; /tokens gibt immer das gesamte Array zurück. Den Header Idempotency-Key unterstützt die nationale Schnittstelle SAPI-SK auf POST /sapi/document/send; für den programmatischen Versand verwenden Sie genau diese.

Versionierung und Abwärtskompatibilität

  • Der Vertrag wächst nur: neue Felder (bei null weggelassen), neue optionale Parameter, neue Endpunkte und Ereignisse. Bestehende Feldnamen, Enum-Werte und Statuscodes ändern sich nicht.
  • Ein neuer Enum-Wert oder ein neues Webhook-Ereignis kann jederzeit erscheinen; ignorieren Sie Unbekanntes und beantworten Sie ein unbekanntes Ereignis mit 2xx.
  • Zeitstempel sind ISO 8601 UTC mit variabler Anzahl Nachkommastellen; parsen, nie als Text vergleichen. Beträge kommen als Zeichenketten mit zwei Dezimalstellen.
  • Sollte eine Änderung je nicht additiv sein, kündigen wir sie im Changelog (E-Mail-Abo verfügbar) mindestens 90 Tage vorher an und behalten die alte Form während einer Übergangszeit.
  • Sicherheitsmodell des API-Schlüssels (seit 3. Oktober 2026): ein Schlüssel liest und sendet Belege und verwaltet Firmen, Benachrichtigungen und Webhooks. Konto- und Schlüsselverwaltung (Schlüssel erstellen, einschränken oder widerrufen, MFA, Passwort, Sitzungen, Einladungen, Firmenübertragung, Vertragsunterschriften) erledigt nur eine angemeldete Person; ein Schlüssel erhält dort 403 token_not_allowed. GET /api/v1/tokens bleibt für Schlüssel offen.
  • Die Vertragsversion steht in info.version von openapi.json, jede Änderung hat eine Changelog-Zeile mit Tag API oder Webhooks.

/changelog · /changelog/odber · openapi.json

Fehler

Fehlerwörterbuch zum Herunterladen: dasselbe Wörterbuch, mit dem das Portal ein Ablehnungsdetail übersetzt (Regel-IDs nach EN 16931 und Peppol BIS, Muster der Netzwerkfehler, die statusReason-Codes von GET /sapi/document/sent), steht als JSON unter /docs/peppol-errors.json bereit (sk, en, de, hu). Geeignet für eine Tabelle häufiger Fehler in der Buchhaltungssoftware: die Regel-ID irgendwo im Detail suchen, unbekannte Regeln samt ID anzeigen. Seit dem 7. 10. 2026 trägt jede JSON-Antwort Content-Type: application/json;charset=UTF-8.

Fehler haben eine einheitliche Form mit einem maschinenlesbaren error-Code. Validierungsfehler ergänzen eine Map fields (erster Fehler pro Feld).

json
// Business-Fehler
{ "error": "invalid_credentials", "message": "Invalid email or password" }

// Validierungsfehler (400); die Texte in "fields" liefert die API auf Slowakisch
{ "error": "validation_failed", "message": "Some fields are invalid",
"fields": { "ico": "IČO musí byť 8 číslic" } }

HTTP-Status

200 / 201 / 204
Erfolg (OK / erstellt / kein Inhalt)
400
ungültige Eingabe (siehe error / fields)
401
fehlende oder ungültige Authentifizierung
403
unzureichende Berechtigung (Rolle)
404
Ressource existiert nicht oder Sie haben keinen Zugriff darauf
405
HTTP-Methode für diesen Pfad nicht unterstützt
409
Konflikt (Handelsregisternummer IČO / E-Mail existiert bereits)
415
nicht unterstützter Content-Type (XML-Endpoints erwarten application/xml)
429
Rate-Limit überschritten (Header RateLimit-* und Retry-After, JSON-Body rate_limited)
Unsere API antwortet immer mit JSON und einem Feld error. Eine Antwort ohne JSON-Body (HTML oder Text wie error code: 1010 mit Status 403, oder 502/504 während eines Deployments) kam nicht von der API, sondern von der davor liegenden Infrastruktur (Edge-Schutz, Gateway). Typische Ursache von 403/1010 ist ein generischer Bibliotheks-User-Agent (Python-urllib, Java/1.8.x auf der Testdomain); die Lösung steht im Abschnitt Testumgebung.

Häufigste Fehlercodes

CodeHTTPWann
validation_failed400Body hat die Validierung nicht bestanden (siehe fields)
unauthorized401API-Token fehlt oder ist ungültig
forbidden403Aktion erfordert die Rolle owner/admin
company_not_found404Firma existiert nicht oder Sie sind nicht Mitglied
ico_taken409eine Firma mit diesem IČO existiert bereits
ico_immutable400IČO kann nicht geändert werden
company_dic_missing400Verifizierung des Versands ohne DIČ (slowakische Steuernummer) der Firma
token_invalid400Verifizierungsmerkmal (Verifikačný údaj, Signatur) stimmt nicht
document_not_found404Beleg existiert nicht
token_not_found404API-Token existiert nicht / gehört nicht Ihnen
rate_limited429zu viele Requests

Ausfall des Access Points und Wiederholung

  • Antwortet die API mit 502, 503 oder 504 oder gar nicht, haben wir den Beleg nicht übernommen: wiederholen Sie den Aufruf später mit demselben Idempotency-Key, nichts wird doppelt gesendet.
  • Ein von der API angenommener Beleg (202 ACCEPTED, auch mit retrying: true) geht nach der Wiederherstellung von selbst hinaus: der Access Point wiederholt die Zustellung, den Stand sehen Sie über GET /sapi/document/sent oder per Webhook; gibt er die Zustellung am Ende auf, endet der Beleg als fehlgeschlagen und derselbe Key sendet ihn erneut.
  • Der Empfang auf Netzebene hängt nicht vom Portal ab: eine Zustellung, die während eines Portalausfalls nicht durchkam, wiederholt der sendende Access Point nach den Peppol-Regeln, und der Beleg erscheint nach der Wiederherstellung im Portal. Meldungen an die Finanzverwaltung, die wegen des Ausfalls nicht hinausgingen, holt ein automatischer Wiederherstellungslauf nach (ein Übertragungsfehler wird wiederholt, eine inhaltliche Ablehnung nicht).
  • Status und Verfügbarkeitshistorie finden Sie auf /status; in der Testumgebung simulieren Sie einen Ausfall mit dem Header X-Sandbox-Simulate (Abschnitt Testumgebung).

SAPI-SK-Codes (Feld error.code)

CodeBedeutung
SAPI-AUTH-001ungültige client_id/client_secret oder gesperrtes Konto (401)
SAPI-AUTH-002fehlender oder fehlerhafter Header Authorization: Bearer (401)
SAPI-AUTH-003Schlüssel nicht für den Teilnehmer berechtigt, Versand nicht freigeschaltet oder pausiert (403)
SAPI-AUTH-004IP-Adresse nicht auf der Freigabeliste des Schlüssels (403)
SAPI-VAL-001ungültiger Request-Body (400)
SAPI-VAL-002X-Peppol-Participant-Id fehlt (400)
SAPI-PROC-001vorübergehend: ein Versand mit diesem Schlüssel läuft, gleich erneut versuchen (502, retryable)
SAPI-PROC-002Beleg vor dem Versand abgelehnt (422 mit Prefer: handling=strict)
SAPI-PROC-003ohne Idempotency-Key: unter dieser Nummer wurde bereits ein anderer Beleg übertragen (409, details: documentId, status)
SAPI-RES-001Beleg existiert nicht oder gehört einem anderen Teilnehmer (404)
SAPI-RES-002Beleginhalt nicht mehr gespeichert (Aufbewahrung der Firma) oder nie archiviert (404; Code bleibt aus Kompatibilitätsgründen)
SAPI-RES-003 / 004Anhang oder MLS-Empfangsbestätigung existiert noch nicht (404)
SAPI-SYS-001 / 002vorübergehender Infrastruktur- oder Validatorfehler (503/502, retryable)
SAPI-SYS-003Rate-Limit überschritten (429, Retry-After)
SAPI-PROC-500unerwarteter Fehler, correlation_id an den Support senden (500)

Vollständiger Fehlerkatalog der Portal-API (326)

Jeder Code, den das Backend im Feld error zurückgibt, mit dem Text, den das Portal anzeigt. Aus demselben Wörterbuch wie die Oberfläche erzeugt, kann also nicht veralten.

Vollständiger Fehlerkatalog der Portal-API
account_existsFür diese E-Mail existiert bereits ein Konto. Melden Sie sich an und nehmen Sie die Einladung im Portal an.
account_inactiveIhr Konto ist nicht aktiv. Bitte kontaktieren Sie uns.
account_under_reviewIhr Konto wird gerade geprüft. Rufen Sie uns an oder schreiben Sie an [email protected].
acknowledge_requiredBestätigen Sie, dass Sie die Risiken des Downloads ohne Anmeldung verstehen.
acknowledgement_requiredBestätigen Sie, dass Sie die Folgen der Vertragskündigung verstehen.
address_book_fullDas Adressbuch ist voll. Entfernen Sie nicht genutzte Kunden und versuchen Sie es erneut.
admin_email_unverifiedDer Zugang zur Administration erfordert eine bestätigte E-Mail-Adresse. Klicken Sie auf den Link in der Nachricht, die wir Ihnen bei der Registrierung geschickt haben.
admin_mfa_requiredDer Zugang zur Administration erfordert die Zwei-Faktor-Authentifizierung. Aktivieren Sie sie in den Einstellungen.
ai_budgetDas Budget für KI-Entwürfe ist aufgebraucht oder das Tageslimit ist erreicht. Schreiben Sie die Antwort manuell.
ai_failedDer Antwortentwurf konnte nicht erstellt werden. Bitte versuchen Sie es erneut.
ai_unavailableKI-Antwortentwürfe sind derzeit nicht verfügbar.
already_completedDie Übertragung der Firma wurde bereits abgeschlossen.
already_memberDieser Benutzer hat bereits Zugriff (Mitglied der Firma oder Ihres Teams).
attachment_externalDieser Anhang liegt beim Absender als Link vor, nicht in der Rechnung selbst.
attachment_invalidEine Anlage konnte nicht gesendet werden (Typ nicht erlaubt, beschädigter Inhalt oder Größe überschritten). Prüfen Sie die Anlagen und versuchen Sie es erneut.
attachment_not_foundDer Anhang wurde nicht gefunden.
attachment_not_readableDer Anhang konnte nicht gelesen werden.
billing_unconfiguredAbonnementzahlungen sind noch nicht verfügbar.
blockedAn diese Adresse kann der Test-Webhook nicht gesendet werden (lokale oder interne Adressen sind nicht erlaubt).
body_requiredBitte geben Sie den Text Ihrer Nachricht ein.
body_too_longDie Nachricht darf höchstens 4000 Zeichen lang sein.
cannot_change_selfDie eigene Rolle können Sie nicht ändern. Bitten Sie den anderen Verwalter der Firma.
cannot_invite_selfSie können sich nicht selbst einladen oder Ihre eigene Einladung annehmen.
cannot_release_to_selfDie Firma ist bereits diesem Konto zugeordnet.
cannot_remove_ownerDer Inhaber der Firma kann nicht entfernt werden. Der Inhaber wechselt nur durch eine Übertragung der Firma.
cannot_restrict_adminEin Administratorkonto des Portals kann so nicht eingeschränkt werden.
cannot_transfer_selfDie Firma gehört bereits zu dieser E-Mail-Adresse.
captcha_failedDie Bot-Prüfung ist fehlgeschlagen. Bitte versuchen Sie es erneut.
captcha_requiredDie Bot-Prüfung ist fehlgeschlagen; laden Sie die Seite neu und versuchen Sie es erneut.
channel_unknownEin alter Eintrag ohne bekannten Kanal kann nicht erneut abgespielt werden. Senden Sie ihn manuell an den richtigen Endpunkt.
chat_not_foundDie Konversation wurde nicht gefunden oder ist leer.
client_not_foundDie Firma gehört nicht zu diesem Partnerkonto.
client_not_removableDie Firma kann nicht entfernt werden: Sie ist von der Finanzverwaltung verifiziert, aktiv, im SMP registriert oder hat Belege. Verwenden Sie stattdessen die Freigabe (release).
company_activeEine aktive Firma kann nicht gelöscht werden.
company_address_requiredErgänzen Sie vor dem Senden einer Rechnung den Firmensitz (Straße, Ort, PLZ) in den Firmendetails.
company_already_activeDie Firma ist bereits aktiv; Aktivierungshinweise sind nicht nötig.
company_dic_missingErgänzen Sie zuerst die DIČ (Steuer-ID) der Firma und versuchen Sie die Verifizierung erneut.
company_incompleteErgänzen Sie vor dem Signieren die Firmendaten: Firmenname, IČO, Peppol-Identifikator und vollständiger Sitz.
company_limitSie haben die maximale Anzahl von Firmen pro Konto erreicht. Kontaktieren Sie den Support, wir erhöhen das Limit.
company_name_mismatchDer Firmenname stimmt nicht mit dem amtlichen Register (ŽR/OR SR) für diese IČO überein.
company_not_activeEin Migrationscode kann nur für eine aktive, im Peppol-Netzwerk registrierte Firma ausgestellt werden.
company_not_foundDie Firma wurde nicht gefunden.
company_not_registeredDie Firma ist noch nicht aktiviert: Schließen Sie die Verteco-Auswahl im Portal der Finanzverwaltung ab, danach können Sie versenden.
company_not_verifiedEine Migration ist erst nach der Auswahl von Verteco im Portal der Finanzverwaltung möglich (die Firma muss aktiv und verifiziert sein).
company_verified_lockedDer Name einer verifizierten Firma kann nur auf den amtlichen Registereintrag geändert werden. Ergänzen Sie zuerst die IČO oder schreiben Sie uns.
confirm_name_mismatchDer eingegebene Name stimmt nicht mit dem Namen des eingetragenen Vermittlers überein.
confirmation_requiredDie Unterschrift erfordert die Bestätigung Ihrer Berechtigung und Ihres Einverständnisses mit dem Wortlaut.
conflictDieser Datensatz existiert bereits.
content_unavailableDer Inhalt dieses Belegs ist nicht mehr gespeichert oder kann nicht als Rechnung gelesen werden.
contract_pendingDas Vertragsverhältnis entsteht mit dem ersten Eintritt in das Portal (Art. 4 AGB); für diese Firma wurde noch keiner erfasst, die Vertragsausfertigung ist daher noch nicht möglich.
country_invalidDas Land muss ein zweibuchstabiger ISO-Code sein (SK, CZ, AT, DE…), kein Name.
country_outside_euDer Online-Antrag steht Unternehmen mit Sitz in einem EU-Mitgliedstaat offen. Unternehmen außerhalb der EU schreiben an [email protected].
current_ip_missingDie Liste muss auch Ihre aktuelle IP-Adresse enthalten, sonst würden Sie sich nach dem Abmelden aussperren.
daily_limitSie haben das tägliche Nachrichtenlimit erreicht. Versuchen Sie es morgen erneut oder schreiben Sie an [email protected].
delivery_failedDer Test-Webhook konnte nicht zugestellt werden; Ihr Endpunkt hat nicht geantwortet.
delivery_not_foundDer Eintrag zur Webhook-Zustellung wurde nicht gefunden.
deregister_cooldownPro IP-Adresse kann nur eine Firma alle 60 Sekunden entfernt werden. Versuchen Sie es gleich erneut.
dic_immutableDer Peppol-Identifikator kann nicht geändert werden: Er ist die Identität der Firma im Peppol-Netzwerk.
dic_requiredGeben Sie die DIČ (Steuer-ID) der Firma ein (SK + 10 Ziffern).
dic_takenEine Firma mit dieser DIČ existiert bereits im Portal.
directory_unavailableDas zentrale SMP antwortet nicht oder hat die Änderung abgelehnt. Bitte versuchen Sie es gleich noch einmal.
document_no_xmlDas gespeicherte Original-XML existiert nicht mehr; der Bericht kann nicht neu erstellt werden.
document_not_foundDer Beleg wurde nicht gefunden.
document_too_largeDas Dokument ist zu groß (Limit 3 MB).
domestic_subjectEin slowakisches Unternehmen stellt den Antrag nach der Anmeldung unter /sprostredkovatel/ziadost.
duplicate_invoice_numberEin Beleg mit dieser Nummer wurde bereits gesendet. Ein neuer Beleg braucht eine neue Nummer; derselbe Beleg wird nie zweimal gesendet.
email_change_cooldownWir haben die Bestätigungs-E-Mail bereits gesendet. Eine weitere können Sie in 10 Minuten anfordern.
email_invalidGeben Sie eine gültige E-Mail-Adresse ein.
email_not_verifiedBestätigen Sie zuerst Ihre E-Mail. Den Link haben wir Ihnen gesendet.
email_send_company_not_activeDer Versand per E-Mail lässt sich nur für ein aktives Unternehmen mit Peppol-Kennung einschalten.
email_send_unavailableDer Versand per E-Mail ist in dieser Umgebung nicht verfügbar.
email_takenDiese E-Mail-Adresse wird bereits von einem anderen Konto verwendet.
email_unchangedDas ist Ihre aktuelle E-Mail-Adresse.
empty_documentFügen Sie das XML der Rechnung ein.
empty_ideaBitte schreiben Sie, was wir verbessern sollten.
empty_messageDie Nachricht ist leer.
empty_replyDie Antwort ist leer.
entry_not_foundDer Kunde im Adressbuch wurde nicht gefunden.
export_format_unknownUnbekanntes Exportformat.
forbiddenDafür fehlt Ihnen die Berechtigung.
forwarder_unreachableDer Dienst zur Belegverarbeitung antwortet nicht. Versuchen Sie es gleich erneut.
fs_change_already_sentDer Antrag ist bereits bei der Finanzverwaltung und kann nicht storniert werden. Stellen Sie bei Bedarf einen neuen.
fs_change_confirm_requiredBestätigen Sie, dass Sie alle Änderungen auf einmal beantragen.
fs_change_cooldownDer nächste Änderungsantrag ist erst 48 Stunden nach dem letzten möglich.
fs_change_field_readonlyFirmen-ID und Steuernummer sind nicht änderbar; eine neue Identität ist ein neuer Eintrag.
fs_change_no_changesSie haben keine Änderung gegenüber den Daten bei der Finanzverwaltung eingegeben.
fs_change_not_foundDer Änderungsantrag wurde nicht gefunden.
fs_change_not_openDer Antrag ist bereits abgeschlossen.
fs_change_not_queuedSofort senden geht nur bei einem wartenden Antrag.
fs_change_pendingEin Änderungsantrag wartet bereits oder liegt bei der Finanzverwaltung. Den nächsten stellen Sie nach dessen Abschluss.
fs_secret_invalidDer Schlüssel hat 32 Zeichen (Ziffern und die Buchstaben a bis f). Kopieren Sie den gesamten Inhalt der .txt-Datei aus dem Zip der Finanzverwaltung.
fs_secret_mismatchDer Schlüssel stimmt nicht mit der Signatur der Aufrufe überein, die die Finanzverwaltung bereits an Ihren Endpunkt gesendet hat. Prüfen Sie Zip und Schlüssel; verändert Ihr Proxy den Aufrufkörper, schreiben Sie uns.
has_documentsDie Firma hat Belege im Archiv; das Löschen ist gesperrt (gesetzliche Archivierung).
holding_unavailableDas Freigeben des Kunden ist derzeit nicht möglich. Kontaktieren Sie den Support.
ico_immutableDie IČO kann nicht geändert werden.
ico_requiredDie IČO ist erforderlich (8 Ziffern).
ico_takenEine Firma mit dieser IČO existiert bereits unter einem anderen Konto. Melden Sie sich damit an oder schreiben Sie uns.
instructions_cooldownDie Anleitung zu dieser Firma haben wir bereits gesendet. Erneut senden ist nach 24 Stunden möglich.
integration_not_foundUnbekannte Integration.
internalEin unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es erneut.
internal_errorEin unerwarteter Serverfehler ist aufgetreten. Bitte versuchen Sie es erneut; der Fehler wurde protokolliert.
invalid_actionUnbekannte Aktion.
invalid_afterDer Parameter after muss Datum und Uhrzeit im ISO-8601-Format sein (z. B. 2026-09-05T10:00:00Z).
invalid_amountDer Betrag muss eine Zahl sein.
invalid_billing_modelUnbekanntes Abrechnungsmodell. Wählen Sie eines der angebotenen Modelle.
invalid_countryWählen Sie das Land des Firmensitzes.
invalid_credentialsE-Mail oder Passwort ist falsch.
invalid_current_passwordDas aktuelle Passwort ist nicht korrekt.
invalid_dateDas Datum muss im Format JJJJ-MM-TT angegeben werden.
invalid_default_companyDie Standardfirma muss eine Ihrer Firmen sein.
invalid_dicGeben Sie eine gültige DIČ (10 Ziffern, optional mit Präfix SK) oder USt-IdNr. ein.
invalid_directionDie Belegrichtung muss gesendet oder empfangen sein.
invalid_due_daysDas Zahlungsziel muss 0 bis 365 Tage betragen.
invalid_emailGeben Sie eine gültige E-Mail-Adresse ein.
invalid_feed_urlDie Feed-URL muss mit https:// beginnen.
invalid_icoGeben Sie eine gültige IČO (8 Ziffern) oder Handelsregisternummer ein.
invalid_idGeben Sie eine slowakische IČ DPH oder DIČ (z. B. SK2121358349) oder eine Peppol-ID (z. B. 0245:2121358349) ein.
invalid_idsDie Belegliste ist ungültig.
invalid_inviteDie Einladung ist ungültig oder wurde bereits verwendet.
invalid_ip_entryDie Liste enthält einen ungültigen Eintrag. Erlaubt sind IP-Adressen (z. B. 185.76.8.211) und CIDR-Bereiche (z. B. 185.76.8.0/24).
invalid_keyDer Vermittler-Schlüssel muss 3 bis 40 Zeichen haben: Kleinbuchstaben, Ziffern und Bindestriche.
invalid_limitDas Limit muss mindestens 1 sein oder leer (Standardwert).
invalid_linkDer Anmeldelink ist ungültig oder abgelaufen. Fordern Sie einen neuen an.
invalid_localeNicht unterstützte Sprache.
invalid_monthDer Monat muss im Format JJJJ-MM angegeben werden.
invalid_notification_emailEine der Adressen ist keine gültige E-Mail:
invalid_notify_eventUnbekanntes Benachrichtigungsereignis.
invalid_notify_localeDie E-Mail-Sprache muss Slowakisch, Englisch, Deutsch oder Ungarisch sein.
invalid_notify_modeUnbekannter Benachrichtigungsmodus. Wählen Sie: jedes Ereignis, tägliche Zusammenfassung, wöchentliche Zusammenfassung oder keine.
invalid_passwordFalsches Passwort.
invalid_patternDas Nummernformat darf höchstens 64 Zeichen haben und muss die laufende Nummer {N}, {NNN} oder {NNNN} genau einmal enthalten.
invalid_payloadDie Rechnung (XML) fehlt oder ist zu groß.
invalid_personaUnbekannte Kontorolle.
invalid_phoneGeben Sie die Telefonnummer als +421 9xx xxx xxx ein (Ziffern, Leerzeichen, optional Bindestriche).
invalid_prefsDie Anzeigeeinstellungen enthalten einen ungültigen Wert und konnten nicht gespeichert werden.
invalid_receiverDer Empfänger muss einen Peppol-Identifikator im Format Schema:Wert haben (z. B. 0245:2121358349).
invalid_requestPflichtangaben fehlen (z. B. Firmenname, 10-stellige DIČ, gültige E-Mail oder Endpunkt-URL).
invalid_roleDie Rolle muss Administrator, Mitglied oder Nur-Lesen sein.
invalid_seqDie nächste laufende Nummer muss mindestens 1 sein.
invalid_sessionUngültige Konversation. Laden Sie die Seite neu und versuchen Sie es erneut.
invalid_signatureDie Zahlungsbenachrichtigung konnte nicht verifiziert werden.
invalid_signupDie Registrierung ist nicht mehr gültig oder abgelaufen. Beginnen Sie die Registrierung erneut.
invalid_sortUnbekannte Sortierung.
invalid_stateUnbekannter Status.
invalid_statusUnbekannter Status.
invalid_tagDer Tag darf nicht leer sein.
invalid_tokenDer Link ist ungültig oder wurde bereits verwendet.
invalid_vpds_urlDer Auswahllink muss mit https://vpds.financnasprava.sk/ beginnen.
invalid_webDie Website muss eine gültige Adresse sein (https://...).
invalid_webhook_urlDie Webhook-URL muss eine gültige https://-Adresse sein (höchstens 512 Zeichen).
invalid_windowDas Zeitfenster ist ungültig: Beginn vor Ende und höchstens 31 Tage.
invalid_xmlDas XML des Belegs lässt sich nicht lesen (beschädigte Datei oder eine nicht erlaubte DOCTYPE-Deklaration).
invite_email_mismatchDiese Einladung gilt für eine andere E-Mail-Adresse. Melden Sie sich mit dem Konto an, an das sie gesendet wurde.
invite_expiredDie Einladung ist abgelaufen. Bitten Sie um eine neue.
ip_not_allowedDie Anmeldung von dieser IP-Adresse ist für dieses Konto nicht erlaubt.
lead_no_emailDer Lead hat keine E-Mail-Adresse und kann nicht kontaktiert werden.
lead_not_contactableNur ein Lead im Status neu kann kontaktiert werden.
lead_not_foundDer Lead wurde nicht gefunden.
link_goneDieser Link ist nicht mehr gültig (abgelaufen, widerrufen oder der Beleginhalt ist nicht mehr gespeichert).
lookup_unavailableDas Register oder der Prüfdienst ist derzeit nicht erreichbar. Versuchen Sie es gleich erneut.
malformed_requestDie Anfrage hat kein gültiges Format. Laden Sie die Seite neu und versuchen Sie es erneut.
manager_requiredDiese Änderung kann nur der Inhaber oder ein Administrator der Firma vornehmen.
member_is_ownerDieser Benutzer ist Inhaber der Firma. Der Inhaber wechselt nur durch eine Übertragung der Firma.
member_not_foundDas Mitglied wurde nicht gefunden.
members_fullDie Firma hat die maximale Anzahl von Mitgliedern erreicht.
method_not_allowedDieser Vorgang wird für diese Adresse nicht unterstützt.
mfa_already_enabledDie Zwei-Faktor-Authentifizierung ist bereits aktiviert.
mfa_code_invalidDer Code stimmt nicht. Versuchen Sie den aktuellen Code aus Ihrer App oder einen Backup-Code.
mfa_not_enabledBackup-Codes gehören zur Zwei-Faktor-Authentifizierung. Aktivieren Sie sie zuerst.
mfa_not_startedStarten Sie zuerst die Einrichtung der Zwei-Faktor-Authentifizierung.
mfa_requiredGeben Sie den Code aus Ihrer Authentifizierungs-App ein.
migration_code_liveDer vorherige Migrationscode ist noch gültig. Widerrufen Sie ihn zuerst.
migration_code_noneEs gibt keine aktive Anfrage für einen Migrationscode.
migration_code_pendingEine Anfrage für einen Migrationscode läuft bereits.
migration_code_rejectedDas SMP hat den Migrationscode abgelehnt. Prüfen Sie ihn beim bisherigen Anbieter; Codes sind einmalig und zeitlich begrenzt.
migration_code_requiredGeben Sie den Migrationscode des bisherigen Anbieters ein.
migration_rejectedDas zentrale SMP hat die Übernahmeanfrage abgelehnt. Versuchen Sie es erneut oder schreiben Sie uns.
missing_fieldsName und E-Mail des Inhabers sind erforderlich.
missing_parameterIn der Anfrage fehlt ein erforderlicher Parameter.
mls_not_availableFür diesen Beleg liegt noch kein Zustellbeleg (MLS) vor.
name_requiredGeben Sie den Namen ein (Kundenname oder Firmenname).
no_billing_accountSie haben noch kein Abrechnungskonto. Richten Sie zuerst ein Abonnement ein.
no_bodyDer Eintrag hat keinen gespeicherten Anfragetext und kann nicht erneut abgespielt werden.
no_contentDer Beleginhalt ist nicht mehr verfügbar; der Link kann nicht erstellt werden.
no_dicDie Firma hat keine DIČ (Steuer-ID).
no_documentsFür den gewählten Zeitraum gibt es keine Belege (mit gespeichertem XML).
no_evidenceFür diesen Beleg ist weder das Original-XML noch ein Zustellbeleg gespeichert.
no_idsWählen Sie mindestens einen Beleg aus.
no_ownerDie Firma hat keinen Inhaber. Verwenden Sie stattdessen die direkte Zuweisung.
no_secretDer Signaturschlüssel existiert noch nicht. Legen Sie zuerst die Benachrichtigungs-Webhook-URL fest.
no_verification_tokenDie Firma hat keinen gespeicherten Verifizierungstoken der Finanzverwaltung; die SMP-Registrierung erfordert ihn.
not_a_resellerDieses Konto ist nicht Inhaber einer Vermittler-Registrierung.
not_acceptableDer Server antwortet nur im JSON-Format.
not_available_for_white_labelFür Unternehmen unter einer Vermittlermarke nicht verfügbar.
not_failedNur fehlgeschlagene Webhooks können wiederholt werden.
not_foundDatensatz nicht gefunden.
not_resellerDieses Konto ist nicht Inhaber einer Vermittler-Registrierung.
not_sandbox_rowDiese Vermittler-Registrierung wird von einem Administrator verwaltet und kann nicht vom Konto aus deaktiviert werden.
note_too_longDie Notiz darf höchstens 200 Zeichen lang sein.
notification_emails_too_longDie Adressen sind zusammen zu lang (höchstens 256 Zeichen).
owner_not_foundFür diese E-Mail existiert kein Inhaberkonto. Legen Sie es zuerst an.
owner_of_companiesUm das Konto zu löschen, fordern Sie zuerst einen Migrationscode an oder melden Sie die Firma aus dem Peppol-Netzwerk ab. Danach können Sie das Konto endgültig löschen.
owner_requiredDiese Aktion kann nur der Inhaber des Firmenkontos ausführen.
participant_not_registeredDie Firma hat noch keinen Eintrag im zentralen SMP unter Verteco; stellen Sie die Veröffentlichung nach der Registrierung ein.
partner_managedDas Vertragsverhältnis dieser Firma führt ihr Vermittler; die Vertragsbestätigung stellt er aus.
party_missing_in_textDer zu signierende Text enthält keine Identifikation der Firma. Laden Sie die Seite neu und versuchen Sie es erneut.
password_already_setSie haben bereits ein Passwort. Verwenden Sie die Passwortänderung.
password_not_setDas Konto hat kein Passwort. Legen Sie eines in den Einstellungen fest und versuchen Sie es erneut.
password_requiredLegen Sie zuerst ein Passwort fest (Sicherheit); danach können Sie diese Änderung bestätigen.
payment_mismatchDie Zahlung konnte dem Antrag nicht zugeordnet werden. Bitte kontaktieren Sie uns.
payment_unconfiguredDie Zahlung ist derzeit nicht verfügbar. Versuchen Sie es später oder kontaktieren Sie uns.
pdf_unavailableDie PDF-Erstellung ist vorübergehend nicht verfügbar. Versuchen Sie es gleich erneut oder nutzen Sie Drucken / PDF.
profile_too_longEines der Profilfelder ist zu lang. Kürzen Sie den Text.
public_link_existsDer Beleg hat bereits einen aktiven Link. Wählen Sie Ersetzen, wenn Sie einen neuen möchten.
public_links_disabledDie Firma hat den Download von Rechnungen ohne Anmeldung nicht aktiviert. Der Inhaber kann ihn in den Firmendetails (Datenarchiv) einschalten.
public_links_unavailableÖffentliche Beleglinks sind derzeit deaktiviert.
rate_limitedZu viele Anfragen. Versuchen Sie es gleich noch einmal.
read_only_memberDie Rolle Nur-Lesen kann weder Status noch Tags von Belegen ändern.
received_onlyEin öffentlicher Link wird nur für empfangene Belege erstellt.
receiving_toggle_cooldownDer Empfang lässt sich höchstens dreimal pro Stunde umschalten. Die nächste Änderung ist möglich, sobald seit der ältesten der letzten drei Änderungen eine Stunde vergangen ist.
registered_elsewhereDer Teilnehmer ist weiterhin bei einem anderen Anbieter registriert; der Code hat die Übernahme nicht ausgelöst.
renderer_unavailableDie Vorschau kann gerade nicht erstellt werden (der Rendering-Dienst startet neu). Versuchen Sie es gleich noch einmal; das Senden der Rechnung ist nicht blockiert.
reply_already_cancelledDiese Antwort wurde inzwischen von einem Kollegen storniert.
reply_already_sentDiese Antwort wurde bereits gesendet; sie kann weder storniert noch erneut gesendet werden.
reply_not_foundDie geplante Antwort wurde nicht gefunden.
reply_to_invalidDie Ergebnisadresse ist keine gültige E-Mail-Adresse.
representative_incompleteGeben Sie Name und Funktion der vertretungsberechtigten Person an oder lassen Sie beide Felder leer.
request_rejectedDie Anfrage enthält ein unzulässiges Zeichen in einem Header oder in der URL. Falls Sie einen API-Schlüssel gesendet haben, verwenden Sie das vollständige client_secret, das beim Erstellen angezeigt wurde (die Liste zeigt nur den Anfang mit …), und gerade Anführungszeichen.
reseller_not_foundDer Vermittler wurde nicht gefunden.
reseller_ownerIhr Konto besitzt einen Vermittler-Eintrag. Vereinbaren Sie dessen Übergabe mit dem Support; danach können Sie das Konto löschen.
reseller_requiredDieser Teil ist nur für das Konto eines eingetragenen Vermittlers.
sbd_not_availableFür diesen Beleg ist kein Transportumschlag (SBDH) gespeichert. Laden Sie stattdessen das Beleg-XML herunter.
schedule_not_foundDieser regelmäßige Export existiert nicht mehr.
sender_email_invalidDie Absenderadresse ist keine gültige E-Mail-Adresse.
sender_email_systemAutomatische Postfächer (noreply, postmaster, mailer-daemon…) können nicht hinzugefügt werden; verwenden Sie das Postfach einer Person oder des Rechnungssystems.
sender_existsDiese Adresse steht bereits auf der Freigabeliste.
sender_limitEs sind höchstens 20 freigegebene Absender möglich.
sending_not_verifiedSenden ist nicht erlaubt: Die Firma hat noch keine verifizierte Anbieterauswahl im Portal der Finanzverwaltung.
sending_pausedDas Senden ist für diese Firma durch das verwaltende Konto pausiert. Der Rechnungsempfang läuft weiter.
service_unavailableDer Dienst ist vorübergehend nicht verfügbar. Bitte versuchen Sie es gleich erneut.
session_fullDiese Konversation ist zu lang. Laden Sie die Seite neu und beginnen Sie eine neue.
session_not_foundDas Gerät wurde nicht gefunden.
shoptet_feed_blockedDie Adresse zeigt auf ein privates Netz. Fügen Sie die öffentliche Adresse Ihres Shops ein.
shoptet_feed_httpShoptet hat die Adresse abgelehnt. Prüfen Sie den Hash in der Adresse und ob der Export nicht auf eine IP-Adresse beschränkt ist.
shoptet_feed_invalid_xmlDie Antwort des Exports ist kein gültiges XML. Prüfen Sie die Adresse in Shoptet.
shoptet_feed_not_configuredDie Shoptet-Verbindung ist noch nicht eingerichtet.
shoptet_feed_not_orders_xmlDas ist kein Shoptet-Bestellexport: Die Adresse muss auf /export/orders.xml enden.
shoptet_feed_not_system_xmlFügen Sie die Adresse des Exports „System-Shoptet-XML“ ein (die Adresse enthält patternId=-11). Eigene Vorlagen, CSV und XLS werden nicht unterstützt.
shoptet_feed_too_largeDie Antwort des Exports ist zu groß (über 10 MB). Wir fragen Bestellungen wochenweise ab, eine solche Antwort ist meist ein Produkt- und kein Bestellexport. Prüfen Sie den Exporttyp.
shoptet_feed_unreachableDer Shoptet-Export hat nicht geantwortet. Versuchen Sie es gleich noch einmal; Shoptet erlaubt nur einen Export gleichzeitig.
sidlo_incompleteDer Sitz muss Straße, PLZ und Ort enthalten, z. B. „Ulica 1, 010 01 Mesto“.
smp_cancel_failedDas Widerrufen des Codes im zentralen SMP ist fehlgeschlagen. Versuchen Sie es gleich erneut oder schreiben Sie an [email protected].
smp_deregister_failedDie Abmeldung aus dem Peppol-Netzwerk ist fehlgeschlagen. Versuchen Sie es gleich erneut.
smp_held_elsewhereDie Registrierung dieser Firma liegt bei einem anderen Anbieter. Ein Migrationscode von uns ist nicht nötig.
smp_not_testDie Testumgebung ist nicht korrekt mit dem Test-SMP verbunden. Bitte schreiben Sie uns.
smp_unavailableDas zentrale SMP antwortet gerade nicht; versuchen Sie es gleich erneut.
smtp_fromAddress_requiredGeben Sie die Absenderadresse ein.
smtp_fromAddress_too_longDie Absenderadresse ist zu lang.
smtp_from_forbiddenDie Absenderadresse darf nicht auf einer Verteco-Domain liegen.
smtp_from_invalidDie Absenderadresse ist keine gültige E-Mail.
smtp_from_not_yoursDie Absenderadresse muss auf der Domain Ihrer Firma liegen (wie die E-Mail des Inhabers, eines Mitglieds oder die Benachrichtigungs-E-Mail).
smtp_from_takenDiese Absenderadresse wird bereits von einer anderen Firma verwendet.
smtp_host_blockedDer Server ist im DNS nicht zu finden oder nicht öffentlich erreichbar (interne Adressen sind nicht erlaubt).
smtp_host_invalidGeben Sie den Domainnamen des Servers ein (z. B. smtp.firma.de), keine IP-Adresse.
smtp_host_requiredGeben Sie die Adresse des SMTP-Servers ein.
smtp_host_too_longDie Adresse des SMTP-Servers ist zu lang.
smtp_incompleteFüllen Sie Server, Port, Benutzername, Passwort und Absenderadresse aus.
smtp_password_invalidDas Passwort darf keine Leerzeichen oder Zeilenumbrüche enthalten.
smtp_password_requiredGeben Sie das Passwort des SMTP-Kontos ein (bei Serverwechsel muss es erneut eingegeben werden).
smtp_port_not_allowedErlaubte Ports sind 465, 587 und 2525.
smtp_security_invalidDie Verschlüsselung muss STARTTLS oder SSL sein.
smtp_test_cooldownEine Test-E-Mail kann einmal pro Minute gesendet werden. Versuchen Sie es gleich erneut.
smtp_test_failedDie Test-E-Mail konnte nicht gesendet werden. Prüfen Sie die SMTP-Servereinstellungen.
smtp_username_invalidDer Benutzername darf keine Leerzeichen oder Zeilenumbrüche enthalten.
smtp_username_requiredGeben Sie den Benutzernamen des SMTP-Kontos ein.
smtp_username_too_longDer Benutzername ist zu lang.
state_not_for_directionDieser Status ist für die Belegrichtung (empfangen oder gesendet) nicht möglich.
stripe_errorDas Zahlungsportal konnte nicht geöffnet oder die Zahlung nicht überprüft werden. Bitte versuchen Sie es erneut.
support_not_on_sandboxDer Support läuft im Produktivportal peppol.verteco.digital, nicht in der Testumgebung.
tag_too_longDer Tag ist zu lang.
target_blockedDas Zielkonto ist gesperrt; die Übertragung ist nicht möglich.
team_fullSie haben die maximale Anzahl von Teammitgliedern erreicht.
termination_confirmedEine bestätigte Kündigung kann nicht aus der App zurückgenommen werden. Schreiben Sie an [email protected].
termination_pendingEine Kündigungsanfrage läuft bereits. Bestätigen Sie sie über den Link in der E-Mail oder brechen Sie sie ab.
terms_not_acceptedZum Erstellen eines Kontos müssen Sie die Geschäftsbedingungen akzeptieren.
test_document_in_productionTestbelege (Nummer TEST-… oder VITAJTE-…) werden ab dem 1. Januar 2027 nicht mehr über das Produktivnetz gesendet. Nutzen Sie für Tests die Testumgebung test.peppol.verteco.digital.
ticket_link_expiredDie Anfrage ist seit mehr als 90 Tagen geschlossen; der Link ist nicht mehr gültig. Schreiben Sie uns erneut an [email protected].
ticket_not_foundDie Anfrage wurde nicht gefunden oder der Link ist ungültig.
token_companies_requiredWählen Sie mindestens ein Unternehmen, auf das der Schlüssel zugreifen darf.
token_company_not_allowedDieser API-Schlüssel hat keinen Zugriff auf dieses Unternehmen (er gilt nur für ausgewählte Unternehmen).
token_company_not_memberEin Schlüssel kann nur Unternehmen umfassen, deren Mitglied Ihr Konto ist.
token_expiredDer Link ist abgelaufen. Fordern Sie einen neuen an.
token_invalidDer Link oder Verifizierungstoken ist ungültig oder nicht mehr gültig.
token_limitSie haben zu viele aktive API-Schlüssel (max. 50). Widerrufen Sie ungenutzte und versuchen Sie es erneut.
token_not_allowedDiese Einstellung kann nur nach Anmeldung im Portal geändert werden, nicht per API-Schlüssel.
token_not_foundDer API-Schlüssel wurde nicht gefunden.
token_not_revokedDieser API-Schlüssel ist aktiv, es gibt nichts wiederherzustellen.
token_restore_expiredDer Schlüssel wurde vor mehr als 7 Tagen widerrufen und kann nicht mehr wiederhergestellt werden. Erstellen Sie einen neuen Schlüssel.
token_scope_invalidDer Schlüsselbereich muss „alle“ oder „ausgewählt“ sein.
too_many_idsEs können höchstens 500 Belege auf einmal verarbeitet werden.
too_many_notification_emailsGeben Sie höchstens 5 E-Mail-Adressen ein.
too_many_schedulesEine Firma kann höchstens fünf regelmäßige Exporte haben. Löschen Sie zuerst einen, bevor Sie einen weiteren anlegen.
too_many_tagsDer Beleg hat zu viele Tags.
too_many_ticketsSie haben zu viele offene Anfragen. Bitte warten Sie auf eine Antwort.
transfer_canceledDie Übertragung der Firma wurde abgebrochen.
transfer_expiredDer Übertragungslink ist abgelaufen. Fordern Sie eine neue Übertragung an.
transfer_staleDer Inhaber der Firma hat sich inzwischen geändert; die Übertragung wurde abgebrochen.
unauthorizedBitte melden Sie sich erneut an.
unknown_documentEs können nur die Dokumente DPA, SLA und NDA signiert werden.
unsupported_documentDie Vorschau kann nur eine Rechnung oder eine Gutschrift darstellen (UBL Invoice oder CreditNote).
unsupported_media_typeDieser Inhaltstyp wird nicht akzeptiert. Senden Sie die Daten als JSON.
user_not_foundEs wurde kein Konto mit dieser E-Mail gefunden. Der Benutzer muss sich zuerst registrieren.
validation_failedEinige Felder sind nicht korrekt ausgefüllt.
validator_unavailableDie Validierung ist derzeit nicht verfügbar. Versuchen Sie es gleich erneut.
verification_code_rejectedDas SMP hat den Verifizierungstoken aus der FS-Auswahl abgelehnt; wiederholen Sie die Auswahl.
verification_token_missingDer Verifizierungstoken aus der FS-Auswahl fehlt; wiederholen Sie die Auswahl und versuchen Sie es erneut.
verified_company_requiredDen Antrag kann nur ein Konto mit mindestens einer verifizierten Firma stellen.
version_staleDer Wortlaut des Dokuments hat sich inzwischen geändert. Laden Sie die Seite neu und signieren Sie die aktuelle Fassung.
webhook_not_configuredLegen Sie zuerst die Webhook-URL fest und speichern Sie sie.
webhook_url_https_requiredIn der Produktion muss die Webhook-URL mit https:// beginnen (eine Zustellung enthält Kundenkennungen und eine Signatur).
webhook_url_unreachableDie Webhook-URL muss öffentlich erreichbar sein. Localhost und interne Netze sind von unseren Servern nicht erreichbar.
white_label_owner_fixedEine über einen Partner geführte Firma verwaltet das Partnerkonto. Einen weiteren Eigentümer fügt der Partner durch Freigabe der Firma hinzu, oder die Auswahl von Verteco auf dem Portal der Finanzverwaltung.
wrong_endpointDies ist nicht der Token-Endpunkt. Verwenden Sie POST /sapi/auth/token mit client_id und client_secret.
xml_not_availableFür diesen Beleg ist kein Original-XML gespeichert; der Inhalt ist nicht mehr verfügbar.
xml_requiredDas XML des Belegs fehlt, die Vorschau kann nicht erstellt werden.
xml_too_largeDer Beleg ist für eine Vorschau zu groß (höchstens 8 MB einschließlich Anlagen).

Rate-Limits

Die API ist durch Rate-Limiting in einem Fenster von 60 Sekunden geschützt (pro Instanz). Limit und Restkontingent liefern wir in jeder Response über Header; bei Überschreitung kommt 429 Too Many Requests mit Retry-After zurück.

Normale Aufrufe
dynamisches Limit mit großer Reserve, pro API-Token (oder Session, sonst IP); den aktuellen Wert liefert der Header RateLimit-Limit
Auth (/auth/*)
strengeres Limit pro IP (Anti-Brute-Force; außer /auth/me und /auth/logout)
RateLimit-Limit
Limit im Fenster
RateLimit-Remaining
wie viel noch übrig ist
RateLimit-Reset
Sekunden bis zum Zurücksetzen des Fensters
Retry-After
Sekunden bis zum nächsten Versuch (bei 429)
http
HTTP/2 429 Too Many Requests
RateLimit-Limit: <Limit im Fenster>
RateLimit-Remaining: 0
RateLimit-Reset: 37
Retry-After: 37

{ "error": "rate_limited", "message": "Too many requests. Slow down." }
Praktische Antworten für Integratoren:
  • Rabatte und Rundung: Die Regeln R040 (Rabattbetrag = Basis × % / 100) und R120 (Zeilenbetrag = Menge × Preis − Zeilenrabatte) tolerieren 0,02 €; exakt ist nur R046 für den Rabatt auf Preisebene (PriceAmount = BaseAmount − Amount). Einzelpreis (BT-146) sowie Bruttopreis und Preisnachlass (BT-147, BT-148) haben keine Begrenzung der Nachkommastellen, alle anderen Beträge 2. Wendet Ihr System den Rabatt auf den Einzelpreis an und rundet ihn, schreiben Sie ihn auf Preisebene: PriceAmount = gerundeter Nettopreis, BaseAmount = Listenpreis, Amount = exakte Differenz, Zeilenbetrag = round(Menge × PriceAmount, 2); ein Prozentsatz ist dort nicht möglich (er gehört in die Zeilennotiz). Zweite Möglichkeit ist ein Zeilenrabatt nur mit Betrag und Grundcode 95; Prozent und Basis im Zeilenrabatt nur, wenn Basis = round(Menge × exportierter PriceAmount, 2) und Amount = round(Basis × % / 100, 2). Eine negative Menge mit positivem Preis (Rückgabe, Abzug einer versteuerten Anzahlung) ist in Gutschrift und Rechnung erlaubt. Muster 11, 15 und 16 auf /de/vzory.
  • Limits sind an das Credential gebunden, nicht an die IP: 300 Aufrufe pro Minute pro API-Token (SAPI: pro Access-Token), Auth-Endpunkte 20 pro Minute pro IP und eine Schutzobergrenze von 600 pro Minute pro IP auf /api/v1. Eine serverseitige Integration hinter einer IP ist nicht betroffen; höhere Limits setzen wir auf Anfrage, nennen Sie uns die erwartete Spitze.
  • Kapazität: das Volumen ist nicht durch die Preisliste begrenzt, der Versand ist asynchron (der Aufruf übergibt den Beleg, die Zustellung läuft im Hintergrund) und ein Batch-Aufruf nimmt bis zu 100 Belege auf einmal an; für eine geplante Spitze schreiben Sie uns vorab das erwartete Volumen, und wir heben das Limit des Keys an.
  • Polling ist ein vollwertiger Weg: GET /sapi/document/sent und /receive mit ?since und ?until alle 1 bis 5 Minuten; Webhooks sind eine Ergänzung, keine Voraussetzung.
  • Zeitstempel (§ 76a Abs. 2 Buchst. d): sentAt = Übergabe an den Zustelldienst (damit ist die Pflicht des Ausstellers nach § 85o Abs. 11 erfüllt), deliveredAt = Bestätigung des Empfänger-Access-Points per MLS, fsReportedAt = Meldung an die Finanzverwaltung; bei empfangenen Dokumenten creationDateTime = Empfang. Alle drei stehen in jeder Zeile von /sapi/document/sent, in /sapi/document/sent/{id} und in den Webhooks (zusätzlich occurredAt).
  • PDF: GET /sapi/document/receive/{id}/pdf und GET /sapi/document/sent/{id}/pdf (auch als links.pdf verlinkt) liefern das PDF des Lieferanten, wenn der Beleg eines enthält, sonst ein aus dem XML erzeugtes PDF; druckbares HTML gibt es unter …/html (Portal ?format=html).
  • C#/.NET und andere Sprachen: generieren Sie den Client aus OpenAPI (NSwag, Kiota, openapi-generator); ein eigenes NuGet-Paket liefern wir nicht.
  • Schlüsselbereich: beim Anlegen eines API-Schlüssels (Seite API-Schlüssel) wählen Sie, ob er alle Unternehmen des Kontos umfasst (auch später hinzugefügte) oder nur ausgewählte. Ein Aufruf mit dem Schlüssel für ein anderes Unternehmen liefert 403 token_company_not_allowed (SAPI-SK: SAPI-AUTH-003); die Rotation behält den Bereich bei. Einen Nur-Lese-Schlüssel gibt es noch nicht.
  • Basispfad: jeder SAPI-SK-Aufruf, einschließlich unserer Erweiterungen (GET /sapi/document/sent, GET /sapi/document/receive/{id}/pdf, GET /sapi/discovery), läuft unter /sapi mit demselben Access-Token und dem Header X-Peppol-Participant-Id. Ein 401 „Authentication required“ ohne SAPI-…-Code bedeutet, dass der Pfad außerhalb von /sapi liegt (zum Beispiel /api/v1/document/sent); /api/v1 ist die Portal-API und erwartet als Bearer den vpt_-Schlüssel, kein SAPI-Access-Token.
  • Das Ausstellungsdatum (BT-2) prüfen wir nicht gegen den Tag der Übergabe: der Beleg geht in dem Moment ins Netz, in dem wir ihn erhalten; senden Sie ihn daher am Ausstellungstag und stellen Sie ihn nicht über Mitternacht in eine Warteschlange. Einen Beleg in Fremdwährung melden wir der Finanzverwaltung mit dem Steuerbetrag in EUR aus BT-110 und BT-111 (TaxCurrencyCode EUR), wie Muster 03 zeigt.
  • Lieferdatum: das XML führt es als BT-72 (cac:Delivery/cbc:ActualDeliveryDate); ein Steuerbeleg zur erhaltenen Zahlung führt in BT-72 das Zahlungsdatum (Muster 12). Unsere eigenen Dienstleistungsrechnungen und Belege aus dem Portal geben es immer an, auch wenn es dem Ausstellungsdatum entspricht (§ 74 Abs. 1 Buchst. d des USt-Gesetzes verlangt es nur bei Abweichung). Beim Lesen nehmen Sie BT-72, sonst BT-7 (cbc:TaxPointDate), sonst das Ausstellungsdatum.

Rate-Limit-Budgets (aktuelle Werte)

Das Fenster beträgt 60 Sekunden. Jede Antwort trägt RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset und RateLimit-Policy (limit;w=Fenster in Sekunden), eine 429 zusätzlich Retry-After. Werte können ohne Ankündigung erhöht werden; lesen Sie die Header, nicht diese Tabelle.

AufrufeBudget-SchlüsselLimit
/sapi/* und /api/mcp mit Tokenclient_id hinter dem Token (Rotation des Access-Tokens setzt nicht zurück)300 / min
/api/v1/* mit API-Schlüssel oder SessionSchlüssel (Hash) oder Session300 / min
POST /sapi/auth/token, renew, revokeIP60 / min
/api/v1/auth/* (Login, Reset)IP20 / min
Öffentliche Werkzeuge (/api/v1/public/peppol-check, Validator)IP15 / min
Massenprüfung (/public/peppol-check/batch)IP6 / min
Live-Netzwerkabfragen (peppol-check, /sapi/discovery, MCP check_participant)IP oder Schlüssel; dazu das ganze Portal40 / h je Aufrufer und 150 / h insgesamt; darüber antwortet die nächtliche Erhebung (source: index), die Massenprüfung ist nicht begrenzt
Registrierung, Passwort vergessen, KontaktformularIP15 / Std
Schutzgrenze für alles mit ungeprüftem BearerIP600 / min
http
HTTP/2 200
RateLimit-Limit: 300
RateLimit-Remaining: 287
RateLimit-Reset: 41
RateLimit-Policy: 300;w=60
Eine 429 auf /sapi trägt neben error und message auch code SAPI-SYS-003, retryable true und correlation_id. Plattformen mit vielen Mandanten hinter einer IP: nennen Sie uns die erwartete Spitze, wir bemessen das Budget individuell.

API-Tokens

Opake Tokens vpt_… für den Server-to-Server-Zugriff. Der Klartext wird nur einmal bei der Erstellung angezeigt. Speichern Sie ihn. Wir speichern nur den SHA-256-Hash und ein 12-stelliges Präfix zur Anzeige.

GET/tokensSession / Token

Liste Ihrer aktiven Tokens (ohne Secret), nach createdAt absteigend.

POST/tokensSession / Token

Erstellt einen Token; gibt den Klartext zurück (ein einziges Mal).

FeldTypPflichtBeschreibung
namestringjaName des Tokens, max. 128
curl
curl -X POST https://peppol.verteco.digital/api/v1/tokens -b cookies.txt \
-H 'Content-Type: application/json' -d '{"name":"moja-appka"}'
# 201 Created
{ "id":"…","name":"moja-appka","token":"vpt_8f2a…","prefix":"vpt_8f2a3b…","createdAt":"…" }
DELETE/tokens/{id}Session / Token

Widerruft den Token. Gibt 204 zurück.

Fehler: token_not_found (404)

Firmen

Firmen (Handelsregisternummer IČO / USt-IdNr. IČ DPH), die Sie verwalten. Der Zugriff ist an die Mitgliedschaft gebunden: Sie sehen nur Firmen, deren Mitglied Sie sind. Wer eine Firma anlegt, wird ihr owner.

GET/companiessession / token

Liste der Firmen, deren Mitglied Sie sind (mit Ihrer Rolle).

POST/companiessession / token

Legt eine Firma an; Sie werden owner, status = pending_verification.

FeldTypPflichtBeschreibung
icostringjagenau 8 Ziffern
dicstringjaUID als SK + 10 Ziffern (z. B. SK2121358349); ein Nicht-Umsatzsteuerzahler sendet nur die 10-stellige DIČ, SK ergänzen wir
legalNamestringjaFirmenname, max. 500
registeredAddressstringneinFirmensitz, max. 1000
curl
curl -X POST https://peppol.verteco.digital/api/v1/companies \
-H 'Authorization: Bearer vpt_8f2a…' -H 'Content-Type: application/json' \
-d '{"ico":"53412834","dic":"SK2121358349","legalName":"Verteco digital services, s. r. o."}'

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

Fehler: ico_taken (409) · validation_failed (400)

GET/companies/{id}session / token

Firmendetails (Sie müssen Mitglied sein).

PUT/companies/{id}owner / admin

Firma bearbeiten. Die IČO ist unveränderlich (muss der bestehenden entsprechen).

Fehler: forbidden (403) · ico_immutable (400) · company_not_found (404)

Feld status

pending_verification
nach dem Anlegen; das Senden ist noch nicht freigeschaltet
active
verifiziert, Senden freigeschaltet

Rolle des Mitglieds

owner
Ersteller der Firma (Vollzugriff)
admin
Administrator (Änderungen, Webhooks, Verifizierung)
member
Mitglied (Lesen)
viewer
nur Lesen
Aktionen „owner / admin" stehen sowohl der Rolle owner als auch admin (Firmenmanager) zur Verfügung.

Verifizierung für das Senden (Verifizierungsmerkmal)

Vor dem Senden muss die Firma über das Verifizierungsmerkmal (Verifikačný údaj, VÚ) verifiziert werden, ein signiertes Token der Finanzverwaltung der Slowakischen Republik (Finančná správa, FS). Nach erfolgreicher Verifizierung wechselt der status der Firma auf active und das Senden wird freigeschaltet.

POST/companies/{id}/verificationowner / admin

Self-Verify des Verifizierungsmerkmals. Bei Erfolg wird der status auf active gesetzt.

FeldTypPflichtBeschreibung
tokenstringjaVÚ = Hex-Signatur (prod/pPFS 1024 hex, test/tPFS 768 hex)
curl
curl -X POST https://peppol.verteco.digital/api/v1/companies/{id}/verification \
-H 'Authorization: Bearer vpt_8f2a…' -H 'Content-Type: application/json' \
-d '{"token":"<1024-hex VÚ>"}'

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

Fehler: company_dic_missing (400) · token_invalid (400) · forbidden (403)

Dokumente

Protokoll der Peppol-Belege (empfangene und gesendete) je Firma. Es füllt sich, während Rechnungen über den Access Point fließen. An die Mitgliedschaft in der Firma gebunden, sortiert nach createdAt absteigend.

GET/companies/{id}/documentssession / token

Liste der Belege der Firma. Optionaler Filter ?direction=sent|received.

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

Details eines einzelnen Belegs.

Fehler: document_not_found (404)

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

Eigenständiges HTML der Rechnung zum Drucken. ?inline=1 → Anzeige im Browser, sonst Download.

Liefert text/html, Content-Disposition mit dem Dateinamen faktura-<číslo>.html (číslo = Rechnungsnummer).

SAPI-SK 1.0 (nationale Schnittstelle)

SAPI-SK ist die standardisierte nationale REST-Schnittstelle zwischen dem Kunden-/ERP-System und dem Access Point (sapi-sk.sk). Wir implementieren sie in vollem Umfang. Dadurch sind Sie nicht an die proprietäre Form unserer API gebunden und schreiben die Integration einmal für jeden beliebigen SAPI-SK Access Point.

Base URL
https://peppol.verteco.digital/sapi
Authentifizierung
OAuth2 client_credentials → kurzlebiger Access Token (JWT)
client_id
UUID Ihres API-Tokens (Liste im Dashboard-Bereich „API tokeny“, dt. API-Tokens)
client_secret
der vpt_…-Token selbst aus dem Portal
Version
1.3 (10 Operationen: 4× Auth, 6× Dokumente)
Der SAPI Access Token ist mit einem separaten Schlüssel signiert (es ist weder der vpt_-Token des Portals noch die Session). Der Widerruf des API-Tokens im Portal macht sofort sowohl /auth/token als auch /auth/renew ungültig.

Sandbox (Probeumgebung)

Möchten Sie SAPI-SK ohne Registrierung und ohne Risiko ausprobieren? Verwenden Sie die öffentlichen Sandbox-Zugangsdaten. Die Sandbox validiert Requests genau wie der Produktivbetrieb, sendet aber niemals etwas in das Peppol-Netzwerk und arbeitet nicht mit realen Daten; sie liefert realistische Mock-Responses. Ideal für Entwicklung, CI und das Onboarding einer Integration.

client_id
sandbox
client_secret
sandbox
send
vollständige Validierung des API-Kontrakts + Mock 202 (es wird nichts zugestellt)
receive
1 Beispielbeleg sandbox-doc-0001 zum Testen von Parsing und Acknowledge
curl
# 1) Sandbox-Token (ohne Registrierung)
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-Versand: wird validiert, aber es wird NICHTS real zugestellt
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) Beispiel-Postfach + Detail des Beispielbelegs
curl https://peppol.verteco.digital/sapi/document/receive \
-H 'Authorization: Bearer <sandbox access_token>'
curl https://peppol.verteco.digital/sapi/document/receive/sandbox-doc-0001 \
-H 'Authorization: Bearer <sandbox access_token>'
Sandbox-Tokens sind isoliert: Sie stellen niemals in Peppol zu und sehen keine realen Belege. Für den produktiven Versand verwenden Sie client_id/client_secret aus dem Portal (unten).

Authentifizierung

POST/sapi/auth/tokenclient_credentials

Tauscht client_id + client_secret gegen einen Access Token (15 Min.) und einen Refresh Token (30 Tage). Speichern Sie den Token und verwenden Sie ihn die vollen 15 Minuten: ein neuer Token bei jedem Aufruf ist unnötiger Overhead (das Request-Limit gilt auch für /auth/token).

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

Fehler: SAPI-AUTH-001 (401) · SAPI-AUTH-003 (401: IP außerhalb der Allowlist des Schlüssels) · SAPI-VAL-001 (400)

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

Gültigkeit und Ablauf des Access Tokens; should_refresh = true bei < 3 Min. bis zum Ablauf.

POST/sapi/auth/renewrefresh token

Stellt einen neuen Access + Refresh Token aus. Schlägt fehl, wenn der zugrunde liegende API-Token widerrufen wurde.

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

Gibt immer success zurück (RFC 7009). Dauerhafter Kill-Switch = Widerruf des API-Tokens im Portal.

Versand eines Dokuments

POST/sapi/document/sendBearer (access)

Sendet ein Peppol-Geschäftsdokument (UBL / BIS 3.0) über unseren Access Point an den Empfänger. Der Versand ist fail-closed: die Firma muss ein verifiziertes Verifizierungsmerkmal (Verifikačný údaj) besitzen. Die Antwort kann ein additives Array warnings[] mit denselben unverbindlichen Hinweisen wie /document/validate tragen (TEST-Nummer, Empfänger aus demselben Konto, Rechnungsdatum ungleich Versandtag); ein Hinweis blockiert den Beleg nie.

Pflicht-Header:

HeaderBeschreibung
AuthorizationBearer <access_token>
X-Peppol-Participant-IdTeilnehmer, in dessen Namen Sie senden (z. B. 0245:2121358349, also die Ziffern der DIČ, der slowakischen Steuernummer, ohne „SK“)
Idempotency-Keyein Schlüssel pro Rechnung, abgeleitet aus etwas Stabilem (z. B. Ihr System + ID oder Nummer der Rechnung); ein wiederholter Aufruf damit liefert das ursprüngliche Ergebnis und stellt nie doppelt zu, ein neuer Schlüssel für dieselbe Rechnung umgeht diesen Schutz. Der Schlüssel gilt je Firma (X-Peppol-Participant-Id). Ausnahme: ist der erste Versuch nie ins Netz gelangt (Validierungsfehler, unvollständige Anfrage, der Empfänger veröffentlicht den Dokumenttyp nicht, der Access Point hat die Wiederholungen aufgegeben, Transportfehler mit Status failed) oder endete er als undeliverable, führt derselbe Schlüssel den Versand erneut aus, „korrigieren und erneut senden“ funktioniert also unter derselben Rechnungsnummer; Vorgehen im Hinweis Korrigieren und erneut senden unten. Der Schlüssel läuft nie ab: er ist am Datensatz des Dokuments gespeichert, den wir dauerhaft aufbewahren (die Aufbewahrungsfrist löscht nur den Inhalt), eine Wiederholung mit demselben Schlüssel liefert das ursprüngliche Ergebnis also auch nach Monaten.
curl
curl -X POST https://peppol.verteco.digital/sapi/document/send \
-H 'Authorization: Bearer eyJ…' \
-H 'X-Peppol-Participant-Id: 0245:2121358349' \
-H 'Idempotency-Key: 7b1f0e2a-…' \
-H 'Content-Type: application/json' \
-d '{ "metadata": {
        "documentId": "INV-2026-001",
        "documentTypeId": "urn:…::Invoice##…::2.1",
        "processId": "urn:…:bis:billing:3.0",
        "senderParticipantId": "0245:2121358349",
        "receiverParticipantId": "0088:7300010000001",
        "creationDateTime": "2026-06-17T10:00:00Z" },
      "payload": "<Invoice …>…</Invoice>",
      "payloadFormat": "XML" }'
# 202 Accepted
{ "providerDocumentId": "…", "status": "ACCEPTED",
"receivedAt": "2026-06-17T10:00:01Z", "timestamp": "…" }
# bei Status "REJECTED" enthält die Response zusätzlich das Feld "detail"
# mit dem Ablehnungsgrund (Validierungsregeln, z. B. BR-CO-15)
metadata vs. UBL: die Felder in metadata dienen dem Routing und sind technisch: documentId ist Ihr interner Identifikator, nicht die Rechnungsnummer. Die Geschäftsdaten (Rechnungsnummer cbc:ID, Ausstellungsdatum, Fälligkeit, Lieferdatum, Währung, Betrag) übernehmen wir direkt aus dem UBL-Payload; nichts davon senden Sie in metadata, und UBL ist stets die Quelle der Wahrheit für die Anzeige im Portal wie auch für Webhooks. documentTypeId: der vollständige busdox-docid-qns-Identifikator; einen bloßen Namespace oder eine alleinstehende CustomizationID normalisieren wir auf den aus dem Payload abgeleiteten Typ, einen Typ, der dem Payload widerspricht, lehnen wir mit SAPI-VAL-001 ab; das Teilnehmerschema muss aus der EAS-Liste stammen.

Fehler: SAPI-AUTH-002 (401) · SAPI-AUTH-003 (403) · SAPI-VAL-001 (400) · SAPI-PROC-001 (502) · SAPI-PROC-002 (503) · SAPI-PROC-500 (500: nicht wiederholen, melden Sie die correlation_id)

HTTP-Status vs. Verdikt. Nach dem nationalen SAPI-SK-Vertrag antwortet ein Versand immer mit 202, das Verdikt steht im Body (status ACCEPTED oder REJECTED). Soll auch der HTTP-Status das Verdikt tragen, senden Sie Prefer: handling=strict (RFC 7240): eine synchrone Ablehnung kommt dann als 422 mit der SAPI-Fehlerhülle zurück (SAPI-VAL-002 bei einem Validierungsfehler, SAPI-RES-003, wenn an den Empfänger nicht zugestellt werden kann; details[] enthalten providerDocumentId und detail), und die Antwort trägt Preference-Applied: handling=strict. ACCEPTED bleibt unverändert. Vor der Übergabe an den Access Point führen wir denselben SML-Lookup aus wie er. Das Dokument wird zuerst validiert: Nur ein gültiges Dokument wird übernommen und gemeldet, ein ungültiges erhält REJECTED mit validation_failed, auch wenn der Empfänger nicht im Netz ist. Ein Empfänger, der gar nicht im Peppol-Netz ist, bedeutet ACCEPTED mit undeliverable: true: Wir haben das Dokument übernommen und melden es der Finanzverwaltung unabhängig von der Zustellung (§ 85o Abs. 11, FS FAQ 9/DPH/2025/IM, Teil II, Beispiel 9), zugestellt wird es aber niemandem; auf GET /sapi/document/sent hat es den Status undeliverable, der Webhook erhält invoice.undeliverable, eine E-Mail geht an niemanden, und derselbe Idempotency-Key sendet erneut, sobald die Empfängerkennung korrigiert ist oder der Empfänger sich registriert hat (Vorgehen im Hinweis Korrigieren und erneut senden unten). Ein Empfänger, der im Netz ist, aber den Dokumenttyp nicht veröffentlicht, erhält sofort REJECTED, ohne Zustellversuch. retrying: true bei ACCEPTED bedeutet, dass der erste Zustellversuch fehlschlug (z. B. vorübergehend nicht erreichbares SMP) und der Access Point ihn selbst wiederholt, in der Regel innerhalb von 20 Minuten; detail nennt den Grund, das endgültige Verdikt kommt über GET /sapi/document/sent oder den Webhook.
Korrigieren und erneut senden. Jeder Versuch, den die API zur Verarbeitung annimmt (Antwort 202, bei handling=strict auch 422), erhält eine eigene providerDocumentId, auch ein abgelehnter.
  • REJECTED durch unsere Prüfung vor dem Versand (Validierungsfehler, unvollständige Anfrage, der Empfänger veröffentlicht den Dokumenttyp nicht, sein SMP-Eintrag hat für den Typ keinen Endpoint, der Access Point hat die Wiederholungen aufgegeben): Nichts ist ins Netz gelangt, nichts wurde zugestellt und nichts wird der Finanzverwaltung gemeldet. Korrigieren Sie die Daten und senden Sie das Dokument erneut mit demselben Idempotency-Key. Der neue Versuch erhält eine neue providerDocumentId; der erste Eintrag bleibt in der Liste der gesendeten Dokumente als rejected mit seinem Grund, nur als Nachweis des gescheiterten Versuchs, und lässt sich nicht löschen. Verknüpfen Sie die Rechnung in Ihrem System immer mit der letzten providerDocumentId. Die Rechnungsnummer kann gleich bleiben, die Rechnung ist im Sinne des Gesetzes noch nicht ausgestellt. Das Ausstellungsdatum (BT-2) muss aber der Tag sein, an dem die Rechnung tatsächlich hinausgeht: Eine E-Rechnung gilt an dem Tag als ausgestellt, an dem sie dem Zustelldienst übergeben wird, und muss spätestens 15 Tage nach der Lieferung oder dem Zahlungseingang versendet werden (FS FAQ 9/DPH/2025/IM, Teil I, Beispiel 74). Geht die korrigierte Rechnung an einem späteren Tag hinaus, ändern Sie das Ausstellungsdatum auf diesen Tag.
  • An das Netz übergeben (ACCEPTED ohne undeliverable: submitted, delivered oder Wiederholung im Hintergrund; dazu gehört auch ein Dokument, das die MLS des Empfängers nach der Übertragung abgelehnt hat und das ein erneuter Aufruf als REJECTED mit Grund zurückgibt): Derselbe Schlüssel liefert das Ergebnis dieses Versands, nichts wird doppelt gesendet. Senden Sie eine zugestellte Rechnung nie erneut; sie wird mit einer Gutschrift (381) oder einer Belastungsanzeige (383) korrigiert.
  • undeliverable (der Empfänger hat keine Adresse im Peppol-Netz): Die Rechnung wurde übergeben, sie wird der Finanzverwaltung unabhängig von der Zustellung gemeldet und die Pflicht des Ausstellers ist erfüllt (FS FAQ 9/DPH/2025/IM, Teil I, Beispiele 42 und 75). Der Schlüssel wird freigegeben. War die Empfängerkennung falsch (zum Beispiel eine IČO oder eine DIČ mit Tippfehler statt 0245:<10 Ziffern der DIČ>, oder der Empfänger ist unter einer anderen Kennung im Netz), korrigieren Sie die Kennung und senden Sie erneut mit demselben Schlüssel; lassen Sie die Rechnung unverändert (gleiche Nummer und gleiches Datum), sie wurde bereits übergeben. Eine 8-stellige Nummer ist eine IČO und wird im Netz nie gefunden. Ist die Kennung richtig und der Empfänger nur nicht registriert, senden Sie ihm dieselbe Rechnung auf anderem Weg, am besten ihr XML per E-Mail (PDF nur als Vorschau). Nach FS FAQ Teil I, Beispiel 75 ist das ein erneutes Zusenden derselben Rechnung, keine neue Rechnung, stellen Sie daher keine neue Rechnung mit anderer Nummer aus. Sobald sich der Empfänger registriert, können Sie ihm dieselbe Rechnung über Peppol erneut senden, indem Sie den Aufruf mit demselben Idempotency-Key wiederholen.
  • Falsche Empfängerkennung oder leere eigene Kennung: Ein X-Peppol-Participant-Id-Header nur mit dem Schema (zum Beispiel 0245:, wenn in den Programmeinstellungen die DIČ des Unternehmens fehlt) wird beim Versand mit 403 SAPI-AUTH-003 und einer Erklärung abgewiesen, und /document/validate mit einem solchen Header ergänzt schon vor dem Versand eine Warnung in warnings. Ein Empfänger als 0088 (GLN) oder als 0245 mit 8 Ziffern (IČO statt DIČ) wird im slowakischen Netz nicht gefunden: Das Dokument endet als undeliverable und sein statusReason (das Detail in der Antwort auf send) nennt die Korrektur: 0245 und die 10 Ziffern der DIČ.
  • Fehlern vorbeugen: Rufen Sie vor dem Versand POST /sapi/document/validate (dieselben Regeln wie beim Versand, speichert und sendet nichts) und GET /sapi/discovery?receiverId=… auf (ist der Empfänger im Netz und welche Dokumenttypen nimmt er an). Den Endstand liefern GET /sapi/document/sent?invoiceNumber=…, GET /sapi/document/sent/{id}, POST /sapi/document/sent/status oder die Webhooks invoice.delivered, invoice.rejected und invoice.undeliverable.
POST/sapi/document/validateBearer (access)

Validiert ein Dokument ohne Versand: dieselben Regeln EN 16931 + Peppol BIS 3.0, die der Access Point vor dem Versand anwendet. Nichts wird gespeichert oder versendet; funktioniert auch mit dem Sandbox-Token. Body = das JSON-Paar { payload, payloadFormat } wie bei /document/send oder direkt das XML (Content-Type: application/xml). Limit 10 MB. Die Antwort trägt zusätzlich ein Array warnings[] mit unverbindlichen Hinweisen (zum Beispiel eine TEST-Nummer, ein Empfänger, der eine andere Firma desselben Kontos ist, oder ein Rechnungsdatum BT-2, das nicht der Versandtag ist); ein Hinweis blockiert den Beleg nie.

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

Fehler: SAPI-AUTH-002 (401) · SAPI-VAL-001 (400: leerer Body, ungültiges JSON, payloadFormat ungleich XML, > 10 MB) · SAPI-SYS-002 (502: Validator vorübergehend nicht verfügbar, erneut versuchen)

Empfang von Dokumenten

GET/sapi/document/receiveBearer (access)

Liste der empfangenen Dokumente (älteste zuerst); die Metadaten enthalten auch invoiceNumber, sodass Sie den Beleg ohne Download des Payloads identifizieren. Query: ?pageToken, ?limit (max. 200), ?status (Filter: received = nur noch nicht bestätigte Belege, acknowledged = nur bestätigte, ohne Parameter alle empfangenen Belege; unabhängig von Groß-/Kleinschreibung, ein anderer Wert liefert den Fehler SAPI-VAL-001), ?invoiceNumber (exakte Übereinstimmung mit cbc:ID), ?since und ?until (ISO-8601-Instant; Zeitfenster nach Empfangszeitpunkt, z. B. Belege der letzten 5 Tage, Massendownload für eine externe Archivierung oder die Rekonstruktion der Buchhaltung), ?deliveryDateFrom und ?deliveryDateTo (ISO-8601-Datum; Filter nach dem Lieferdatum aus dem Beleg). Der Header X-Peppol-Participant-Id ist Pflicht.

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

Detail inklusive Payload (Roh-XML, so wie es über Peppol eingegangen ist).

Fehler: SAPI-RES-001 (404) · SAPI-RES-002 (404: Payload nicht archiviert)

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

Bestätigt die Übernahme des Dokuments durch Ihr System. Idempotent.

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

Archivlink (metadata.links.xml): das Geschäftsdokument selbst als XML-Datei, gleicher Inhalt wie der Payload im Detail.

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

Archivlink (metadata.links.html): generische druckbare Darstellung der Rechnung (HTML).

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

Archiv-Link (metadata.links.pdf): das PDF des Belegs. Hat der Lieferant sein eigenes Rechnungs-PDF ins XML eingebettet (BT-125), erhalten Sie dieses Original; sonst ein auf Anfrage aus dem gespeicherten XML erzeugtes PDF (kein PDF wird gespeichert). Header X-Verteco-Pdf-Source: supplier | generated. 404 SAPI-RES-002 nach Löschung des Inhalts, 503 bei nicht verfügbarem Renderer (später erneut oder /html).

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

Archivlink (metadata.links.attachments[].url): die Bytes eines im Dokument eingebetteten Anhangs, z. B. das PDF-Original des Lieferanten. Erzwungener Download.

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

Link ohne Anmeldung (optional): erzeugt einen NEUEN Zufallsschlüssel für den Beleg ({"rotate":true} ersetzt den bestehenden). Liefert url (Seite), xmlUrl, htmlUrl, pdfUrl und expiresAt; der Schlüssel wird nur einmal angezeigt. Die Firma muss „Download ohne Anmeldung“ aktiviert haben (sonst 403 SAPI-AUTH-004). DELETE widerruft ihn.

Archiv statt Kopie: jedes empfangene Dokument trägt in den Metadaten links (xml, html, pdf, Anhänge) und retention. Ein Integrator kann neben dem gebuchten Beleg nur den Link speichern und das Dokument erst beim Anzeigen laden; die Links verlangen denselben Bearer-Token und den Header X-Peppol-Participant-Id. retention.mode = storage bedeutet, dass die Firma empfangene Belege bei uns archiviert und wir das Original während der gesamten Vertragsbeziehung aufbewahren (AGB 11a.1). retention.mode = secure bedeutet, dass die Firma empfangene Belege bei uns nicht archiviert: der Inhalt wird zum Zeitpunkt retention.contentAvailableUntil unwiderruflich gelöscht, dem je Dokument gespeicherten geplanten Löschdatum (standardmäßig 14 Tage nach Empfang; die Frist gilt getrennt für empfangene und gesendete Belege, und jede Änderung der Einstellung zählt für bestehende Belege ab dem Tag der Änderung, nie früher), danach liefern die Links SAPI-RES-002; ein null-Wert bei mode secure heißt, dass wir den Inhalt wegen einer noch offenen Steuermeldung halten und kein Datum versprechen. Der Firmeninhaber stellt das Archiv im Firmendetail getrennt für empfangene und ausgestellte Belege ein. Links ohne Anmeldung: aktiviert der Inhaber im Firmendetail „Rechnungen ohne Anmeldung herunterladen“, liefert POST /sapi/document/receive/{id}/public-link einen Link mit eigenem Zufallsschlüssel, der den Beleg ohne Token öffnet (url für Menschen, xmlUrl und htmlUrl für Programme). Der Schlüssel steht genau einmal in dieser Antwort; der Link endet spätestens mit contentAvailableUntil, ist widerrufbar (DELETE) und antwortet nach Ablauf mit 410 und Grund, dann fordern Sie einen neuen an. Ohne die Portaleinstellung antwortet der Aufruf mit 403 SAPI-AUTH-004.
Links ohne Anmeldung: die Felder links.* verlangen immer den Bearer-Token (Archiv-Links). Hat die Firma „Download ohne Anmeldung“ aktiviert (Firmendetail → Datenarchiv oder PUT /companies/{id}/public-links), trägt der Belegdetail metadata.publicLink mit fertigen Adressen url, xmlUrl, htmlUrl und pdfUrl – bei jedem Lesen dieselbe Adresse und dieselbe, die der Nutzer im Portal an der Rechnung sieht. Speichern Sie sie zum gebuchten Beleg; POST …/public-link brauchen Sie nur, um einen neuen Schlüssel zu erzwingen. Bei ausgeschalteter Option ist publicLink.issued=false mit reason=public_links_disabled. Der Link ist dauerhaft: Er gilt, solange der Beleginhalt gespeichert ist (bei einer Firma ohne Archivierung empfangener Belege bis retention.contentAvailableUntil); expiresAt ist deshalb null (in SAPI-Antworten fehlt das Feld), nichts muss erneuert werden. xmlUrl und links.xml liefern den Geschäftsbeleg selbst (Wurzel Invoice/CreditNote) ohne die SBDH-Transporthülle. pdfUrl und links.pdf liefern das vom Lieferanten ins XML eingebettete PDF (BT-125), falls vorhanden, sonst ein aus dem XML erzeugtes PDF; der Header X-Verteco-Pdf-Source sagt, welches (supplier | generated).

Status gesendeter Dokumente

GET/sapi/discovery?receiverId=0245:2121358349

Preflight vor dem Versand: Ist der Empfänger im Peppol-Netzwerk registriert und welche Belegtypen kann er empfangen? Derselbe SML-Lookup, den auch der Access Point durchführt; receiverId akzeptiert eine Peppol-ID, eine USt-IdNr. (IČ DPH) sowie die DIČ selbst. Response: {registered, participantId, smp, documentTypes, checkedAt}. Der Header X-Peppol-Participant-Id ist hier nicht erforderlich.

GET/sapi/document/sentBearer (access)

Zustellstatus gesendeter Belege: pending (Übergabe an das Netzwerk) → submitted → delivered / rejected (bestätigt durch den Zustellnachweis (MLS) vom AP des Empfängers); failed = Transportfehler (ein Retry mit demselben Idempotency-Key sendet erneut). Query: ?pageToken, ?limit, ?status (pending / submitted / sent / delivered / rejected / failed; unabhängig von Groß-/Kleinschreibung, ein anderer Wert liefert den Fehler SAPI-VAL-001), ?invoiceNumber (exakte Übereinstimmung mit cbc:ID: der Status einer konkreten Rechnung mit einem einzigen Aufruf), ?since und ?until (ISO-8601-Instant; Zeitfenster), ?deliveryDateFrom und ?deliveryDateTo (ISO-8601-Datum; Filter nach Lieferdatum).

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

Fehler: SAPI-AUTH-002 (401) · SAPI-AUTH-003 (403) · SAPI-VAL-001 (400: ungültiges since)

MLS-Empfangsbestätigung und Zustellnachweise

Die MLS-Empfangsbestätigung (Peppol Message Level Status) ist die Antwort des empfangenden Access Points auf unsere Übertragung: AP = angenommen und zugestellt, AB = zugestellt ohne fachliche Bestätigung, RE = abgelehnt mit Grund. Das Portal speichert sie beim gesendeten Dokument und setzt den Status entsprechend: AP und AB bedeuten beide delivered (bei AB beginnt statusDetail mit „MLS AB: “ und mls.responseCode ist AB; nach SPOG on MLS ist das eine Zustellung ohne fachliche Bestätigung, kein Vorbehalt), RE bedeutet rejected. Nach § 76a Abs. 2 Buchst. d des Gesetzes 222/2004 muss der Anbieter Datum und Uhrzeit von Versand, Zustellung und Empfang nachweisen können; jede Zeile von GET /sapi/document/sent und jeder Webhook trägt diese drei Zeiten: sentAt (Übergabe an den Zustelldienst, damit ist nach § 85o Abs. 11 die Pflicht des Ausstellers erfüllt), deliveredAt (Bestätigung des Empfänger-Access-Points per MLS) und fsReportedAt (Meldung an die Finanzverwaltung). Ein ausländischer Access Point sendet unter Umständen nie eine MLS: das Dokument bleibt dann delivered mit dem Detail as4_receipt_only und ohne Bestätigung.

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

Detail eines gesendeten Dokuments: dieselbe Zeile wie in der Liste (inkl. sentAt, deliveredAt, fsReportedAt, hasMls, links) plus mls.responseCode (AP/AB/RE), mls.receivedAt und mls.url. mls ist null, bis eine Bestätigung eintrifft.

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

Fehler: SAPI-AUTH-002 (401) · SAPI-AUTH-003 (403) · SAPI-RES-001 (404: fremdes oder empfangenes Dokument) · SAPI-RES-004 (404: noch keine Bestätigung)

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

Die Bestätigung als Datei: die MLS ApplicationResponse des Empfänger-Access-Points mit Bezug auf die peppolMessageId der Übertragung. Nachweis der Zustellung oder Ablehnung; erzwungener Download. SAPI-RES-004, solange keine Bestätigung vorliegt.

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

Inhalt eines gesendeten Dokuments (SAPI 1.8.15): das reine UBL-XML, das wir dem Netz übergeben haben (Transporthülle entfernt), erzwungener Download. Gegenstück der Links auf empfangene Dokumente: das Programm eines externen Buchhalters kann so auch die AUSGESTELLTEN Rechnungen des Mandanten laden. Jede Zeile trägt links.xml, links.html und links.pdf. SAPI-RES-002, sobald die Aufbewahrungsfrist der Firma den Inhalt gelöscht hat.

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

Druckansicht eines gesendeten Dokuments, aus dem gespeicherten XML erzeugt (nichts wird gespeichert).

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

PDF eines gesendeten Dokuments: das im XML eingebettete PDF des Ausstellers (BT-125), sonst aus dem XML gerendert; Header X-Verteco-Pdf-Source: supplier | generated. 503 SAPI-PROC-001, solange der Renderer nicht verfügbar ist (dann /html).

Vermittler: dieselben Aufrufe mit dem X-Peppol-Participant-Id-Header des Kunden liefern die Bestätigungen aller verwalteten Firmen mit einem Token; im Portal steht dieselbe Bestätigung im Detail der gesendeten Rechnung (Empfangsbestätigung herunterladen), das MCP-Werkzeug get_document enthält sie ebenfalls.

Nachweise der FS-Meldung, Integrität und Zeitleiste (SAPI 1.8.14)

Seit 1.8.14 tragen jede Zeile von GET /sapi/document/sent, das Detail sowie Liste und Detail der empfangenen Belege ein Objekt fsReport: state = reported (Meldung an die Sammelstelle C5 übergeben, reportedAt = fsReportedAt), pending (Meldung geschuldet, Übergabe fehlgeschlagen, wird automatisch wiederholt, reason = c5_unavailable) oder not_required (keine Meldung; reason erklärt warum: cross_border, self_send_test, issuer_without_vat_id, recipient_without_vat_id, not_billing_document, tdd_disabled, before_2026_09_01, not_recorded). Nach der Übergabe kommt tddMessageId (SBDH InstanceIdentifier der Meldung) hinzu, nach der Antwort von C5 c5ResponseCode (AP/AB/RE), c5ResponseAt, c5Detail und die Zusammenfassung outcome: accepted (AP), accepted_with_reservations (AB), rejected (RE) oder null, solange C5 nicht geantwortet hat. outcome = rejected heißt: die Meldung wurde übergeben, aber die Finanzverwaltung hat sie abgelehnt (c5Detail trägt die verletzte Regel, z. B. BR-AE-08); state bleibt reported, weil die Übergabe stattgefunden hat, und das Portal sendet die korrigierte Meldung automatisch erneut (nach der Annahme wird outcome zu accepted). Gesendete Zeilen haben zusätzlich statusReason (Maschinencode hinter statusDetail: network_retrying, network_retrying_sent, as4_receipt_only, recipient_not_registered, transport_failed, mls_rejected, validation_failed), xmlSha256 (SHA-256 des übergebenen XML, bleibt nach der Inhaltslöschung erhalten), retention und receiptRetention = permanent (die MLS-Bestätigung wird nie gelöscht). Die Bestätigung im Detail hat mls.sha256 und mls.messageId. Empfangene Belege erhielten peppolMessageId, status (received/acknowledged), receivedAt, acknowledgedAt und xmlSha256 (SHA-256 der Bytes des Geschäftsdokuments genau so, wie links.xml sie liefert, ohne SBDH-Transporthülle; beim Empfang berechnet und nach der Inhaltslöschung erhalten). Beide Listen filtern Sie mit ?fsReport=reported|pending|not_required|rejected (rejected = outcome rejected), gesendete auch mit ?status=undeliverable. Die Antwort von POST /sapi/document/send trägt peppolMessageId bereits bei der Annahme. Alles ist additiv, bestehende Felder bleiben unverändert.

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

Status von bis zu 200 gesendeten Belegen in einem Aufruf: dieselben Zeilen wie in der Liste plus mls, wenn die Bestätigung schon vorliegt. Ids, die keine gesendeten Belege dieser Firma sind, kommen in missing zurück; der Aufruf scheitert deswegen nie. Ersetzt N Aufrufe von GET /sapi/document/sent/{id} bei der ERP-Synchronisation.

json
// POST { "documentIds": ["7c1e…", "9af0…", "unbekannt"] }  (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…", "unbekannt"] }

Fehler: SAPI-AUTH-002 (401) · SAPI-AUTH-003 (403) · SAPI-VAL-001 (400: 0 / > 200 id)

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

Zeitleiste des Belegs nach Zeit sortiert: submitted, network_retrying, delivered / rejected / undeliverable / failed, mls_received, fs_reported, fs_c5_verdict, content_wiped, webhook_delivered und weitere (unbekannte Typen ignorieren). Phase 1 wird aus den gespeicherten Fakten abgeleitet, kein Journal jeder Zwischenänderung.

Fehler: SAPI-AUTH-002 (401) · SAPI-AUTH-003 (403) · SAPI-RES-001 (404: fremder oder empfangener Beleg)

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

Zeitleiste eines empfangenen Belegs: received, acknowledged, fs_reported, fs_c5_verdict, content_wiped, Webhook-Zustellungen.

Webhooks: jedes invoice.*-Ereignis trägt dasselbe fsReport-Objekt; neue Ereignisse invoice.report_pending (Übergabe der Meldung fehlgeschlagen, bleibt geschuldet und wird wiederholt; einmal je Beleg) und invoice.report_rejected (C5 hat die Meldung abgelehnt, c5Detail nennt den Grund). Neue Ereignisse erreichen nur Integrationen, die alle Ereignisse abonnieren; auf unbekannte Typen mit 2xx antworten. Die Testumgebung liefert beim Musterbeleg fsReport not_required mit reason tdd_disabled und beim Batch-Aufruf ein leeres documents. Bei einer Ablehnung hat fsReport.outcome den Wert rejected, und der Beleg erscheint unter ?fsReport=rejected. Self-Billing (Belegcode 389, die Rechnung stellt der Käufer aus): den Beleg stellen wir zu, die Meldung an die Finanzverwaltung garantieren wir dafür noch nicht, weil die Meldung aus dem im Beleg genannten Lieferanten gebildet wird, nicht aus dem Absender; fsReport kann pending oder rejected bleiben. Schreiben Sie uns, bevor Sie Self-Billing einführen.

Massenversand

POST/sapi/document/batchBearer (access)

Bis zu 100 Dokumente in einem Aufruf. Jedes Element durchläuft die vollständige Logik des Einzelversands (Idempotenz über itemId + idempotencyKey, Reservierung, Submit, Verdikt) und liefert ein eigenes Ergebnis; der Fehler eines Elements stoppt die übrigen nicht. Die Elemente werden sequenziell verarbeitet; failed-Elemente wiederholen Sie mit demselben idempotencyKey.

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

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

Fehler: SAPI-AUTH-002 (401) · SAPI-AUTH-003 (403) · SAPI-VAL-001 (400: leere/zu große Liste)

Fehlermodell

Alle SAPI-Fehler haben einen einheitlichen Envelope mit Kategorie, stabilem Code, dem Flag retryable und einer correlation_id für den Support. Bei einem Anmeldefehler (SAPI-AUTH-001) enthält der Envelope zusätzlich hint (eine verständliche Erklärung, was in Client Id und Client Secret gehört) und docs (Link zur Anleitung; MK-soft-Programme direkt auf /navody/mksoft#prepojenie). Beide Felder sind optional und fehlen sonst (1.8.20).

json
{ "error": {
  "category": "AUTH",
  "code": "SAPI-AUTH-001",
  "message": "Invalid client credentials.",
  "retryable": false,
  "correlation_id": "b4191dfc-…" } }
Hinweis: beim Versand stellen wir das Geschäftsdokument zu; die C2-Seite der Steuermeldung (TDD) zu gesendeten Belegen ist in Vorbereitung. Die Steuermeldung beim Empfang (C3) erzeugen und übermitteln wir automatisch an die Finanzverwaltung der Slowakischen Republik (Finančná správa, FS).

Benachrichtigungen & Webhooks

Bei einer empfangenen Rechnung können wir die Firma per E-Mail oder per Webhook (POST an Ihre URL) benachrichtigen. Die Zustellung ist durable: Sie wird in eine Ausgangsqueue geschrieben und asynchron zugestellt (15 s Timeout); bei einem Fehlschlag wiederholen wir bis zu 12× mit exponentiellem Backoff (30 s → max. 8 h, insgesamt rund 16 Stunden), danach Dead-Letter. HTTP 401/403 bedeutet, dass Ihr Endpunkt eine Authentifizierung verlangt, die wir nicht mitsenden; prüfen Sie stattdessen die Signatur webhook-signature und antworten Sie mit 2xx. Ein Ausfall Ihres Servers verliert die Benachrichtigung also nicht, wir stellen sie beim nächsten Versuch zu. Der SSRF-Schutz blockiert Loopback-/lokale Adressen; die Webhook-URL muss öffentlich erreichbar sein.

GET/companies/{id}/notificationssession / token

Benachrichtigungseinstellungen: { webhookUrl, notificationEmail, notificationEmails, hasSecret }.

PUT/companies/{id}/notificationsowner / admin

Setzt beide Kanäle (leerer String = hebt den jeweiligen Kanal auf).

FeldTypPflichtBeschreibung
webhookUrlstringneinleer oder http(s)-URL, max. 512
notificationEmailstringneineine Adresse oder bis zu 5 durch Kommas getrennt, max. 256; jede erhält die E-Mails zu empfangenen Rechnungen (400 invalid_notification_email / too_many_notification_emails)
GET/companies/{id}/webhooksession / token

Webhook-Konfiguration: { url, hasSecret } (ohne Secret).

PUT/companies/{id}/webhookowner / admin

Setzt die Webhook-URL (generiert automatisch ein Signatur-Secret, falls noch keines existiert).

FeldTypPflichtBeschreibung
urlstringjahttp(s)-URL, max. 512
curl
curl -X PUT https://peppol.verteco.digital/api/v1/companies/{id}/webhook \
-H 'Authorization: Bearer vpt_8f2a…' -H 'Content-Type: application/json' \
-d '{"url":"https://vas-system.sk/peppol/webhook"}'
# 200 OK { "url":"https://vas-system.sk/peppol/webhook", "hasSecret": true }
DELETE/companies/{id}/webhookowner / admin

Entfernt Webhook-URL und Secret. Gibt 204 zurück.

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

Generiert ein neues Signatur-Secret und gibt es EINMALIG zurück; speichern Sie es zur Prüfung von X-Verteco-Signature.

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

Sendet synchron eine Testbenachrichtigung (Event webhook.test, signiert, SSRF-geschützt) an die gespeicherte URL und gibt zurück, WAS gesendet wurde und WAS zurückkam. Dasselbe lösen Sie mit der Schaltfläche „Otestovať webhook“ (Webhook testen) in den Firmendetails aus.

json
// 200 OK
{
"sent":     { "url": "https://vas-system.sk/peppol/webhook", "event": "webhook.test",
              "signed": true, "payload": "{…}" },
"received": { "status": 200, "body": "OK", "durationMs": 142, "error": null }
}
// 400 webhook_not_configured, wenn keine Webhook-URL gespeichert ist

Webhook-Payload

Sowohl bei einer empfangenen (invoice.received) als auch bei einer gesendeten (invoice.sent) Rechnung senden wir einen POST mit diesem Body; das Feld event unterscheidet den Typ.

Zwei weitere Events melden das Urteil des Netzwerks zu einer Rechnung, die Sie gesendet haben: invoice.delivered (der Access Point des Empfängers hat die Zustellung mit einem Zustellnachweis (MLS) bestätigt) und invoice.rejected (abgelehnt, entweder durch das Netzwerk oder bereits bei der Validierung vor dem Versand); invoice.undeliverable meldet einen Empfänger ohne Eintrag im Peppol-Netz (übernommen, der FS gemeldet, nicht zugestellt). Sie tragen die Identifikation des Belegs und der Firma (documentId, invoiceNumber, receiverId, peppolMessageId, companyDic, peppolParticipantId) sowie status, statusDetail mit dem Ablehnungsgrund und statusDateTime. Ist der erste Zustellversuch fehlgeschlagen und wiederholt ihn der Access Point selbst (in der Regel innerhalb einer Stunde), bleibt das Dokument submitted und statusDetail beginnt mit network_retrying: ; eine Zustellung ergibt dann delivered, ein Aufgeben rejected mit dem Präfix network_gave_up: . Dank ihnen müssen Sie den Status gesendeter Rechnungen nicht per Polling abfragen.

Das Event company.activated kommt, wenn ein Kunde die Auswahl des Anbieters im FS-Portal (VPDS) der Finanzverwaltung der Slowakischen Republik (Finančná správa, FS) abschließt (Body: event, companyId, companyDic, peppolParticipantId, status, verifiedAt); company.deactivated dagegen bei der Abmeldung der Firma aus dem Netzwerk (gleicher Body ohne verifiedAt). company.smp_registered_elsewhere kommt, wenn eine Firma die FS-Auswahl abgeschlossen hat, ihr Eintrag im nationalen SMP aber von einem anderen Anbieter gehalten wird (Body wie company.activated plus action: "migration_code_required" und migrateUrl). Das Vorgehen für Partner steht in der Vermittler-Dokumentation. Bis der Kunde einen Migrationscode eingibt, stellt das Netzwerk an den alten Anbieter zu. Details in der Anleitung /saas:

json
{
"event": "invoice.received",
"eventId": "7f1c2d9e-4b1a-4e3d-9c1f-0a2b3c4d5e6f",
"occurredAt": "2026-09-03T15:04:05Z",
"companyId": "08dd…",
"documentId": "…",
"invoiceNumber": "2026001",
"senderId": "0088:7300010000001",
"supplierName": "Dodávateľ s.r.o.",
"receiverId": "0245:2121358349",
"issueDate": "2026-06-03",
"dueDate": "2026-06-17",
"deliveryDate": "2026-06-03",
"currency": "EUR",
"totalAmount": "120.00",
"peppolMessageId": "…",
"companyDic": "SK2121358349",
"peppolParticipantId": "0245:2121358349"
}

Die Felder companyDic und peppolParticipantId identifizieren die Firma, auf die sich das Event bezieht (wichtig für Partner, die eine einzige Webhook-URL für alle ihre Kunden verwenden).

Urteil des Netzwerks zu einer gesendeten Rechnung:

json
{
"event": "invoice.delivered",          // oder "invoice.rejected"
"occurredAt": "2026-09-03T15:04:05Z",
"companyId": "08dd…",
"companyDic": "SK2121358349",
"peppolParticipantId": "0245:2121358349",
"documentId": "…",
"invoiceNumber": "2026001",
"receiverId": "0245:2120049096",
"peppolMessageId": "…",
"status": "delivered",                 // oder "rejected"
"statusDetail": null,                  // bei rejected: Ablehnungsgrund
"statusDateTime": "2026-06-03T10:15:42Z"
}

Aktivierung der Firma nach der Auswahl im FS-Portal (VPDS):

json
{
"event": "company.activated",          // company.deactivated hat denselben Body ohne verifiedAt
"occurredAt": "2026-09-03T15:04:05Z",
"companyId": "08dd…",
"companyDic": "SK2121358349",
"peppolParticipantId": "0245:2121358349",
"status": "active",
"verifiedAt": "2026-06-03T10:02:11Z"
}

Den Event-Namen trägt auch der Header X-Verteco-Event. Vollständige Liste der Events: 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 sowie das Test-Event webhook.test. Einen unbekannten Event-Typ sollten Sie beiseitelegen und protokollieren; einen neuen Typ kündigen wir immer im Voraus an. Jedes Event trägt zusätzlich occurredAt (Ereigniszeit, ISO-8601 UTC) zum Sortieren sowie eventId (derselbe Wert wie im Header X-Verteco-Delivery-Id): eindeutig pro Event und bei jeder Wiederholung unverändert, also der richtige Schlüssel zum Deduplizieren (peppolMessageId wiederholt sich über invoice.sent, invoice.delivered und invoice.reported). invoice.*-Events tragen zusätzlich die Zeiten sentAt, deliveredAt, receivedAt und fsReportedAt (ISO-8601 UTC, null, bis das Ereignis eingetreten ist). invoice.reported kommt, wenn die Steuermeldung an die Finanzverwaltung (TDD) zum Beleg dem Zustellnetz übergeben wurde (§ 85o Abs. 11), bei einem Ausfall des C5 auch Tage später. Formale Schemata aller Events stehen im Abschnitt webhooks der OpenAPI-Spezifikation.

Der Partner-Benachrichtigungs-Webhook, die Kundenverwaltung (release, pause-sending) und das Abrechnungsmodell stehen nur eingetragenen Vermittlern zur Verfügung und sind beschrieben unter Für Vermittler.

Signaturprüfung

Hat die Firma ein Secret, senden wir den Header X-Verteco-Signature in der Form sha256=HMAC-SHA256(secret, raw Body) (lowercase hex). Berechnen Sie den HMAC immer über die exakten Bytes des Bodys:

javascript
import crypto from 'node:crypto';

// rawBody = die exakten Bytes des Request-Bodys (kein erneut serialisiertes 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));
}

Header jeder Zustellung: X-Verteco-Event (Event-Name), X-Verteco-Delivery-Id (= eventId im Body, bei jeder Wiederholung identisch), X-Verteco-Signature (der HMAC oben) und parallel die Standard-Webhooks-Header: webhook-id (= eventId), webhook-timestamp (Unix-Sekunden dieses Versuchs) und webhook-signature = v1,base64(HMAC-SHA256(secret, id + "." + timestamp + "." + body)). Schlüssel sind die UTF-8-Bytes Ihres Secrets; eine standardwebhooks-Bibliothek erwartet es als whsec_ + base64(secret). Empfohlene Verarbeitung: Signatur prüfen, Zustellungen mit einem webhook-timestamp älter als 5 Minuten ablehnen (Replay-Schutz), idempotent nach eventId verarbeiten, innerhalb von 15 Sekunden mit 2xx antworten und schwere Arbeit in die eigene Queue verlagern. Eine fehlgeschlagene Zustellung wiederholen wir 12-mal im Abstand von 30 s bis 8 h (insgesamt rund 16 Stunden); danach landet sie im Dead-Letter mit E-Mail-Hinweis und bleibt im Realtime-Log sichtbar. Eine produktive Webhook-URL muss https:// sein; die Testumgebung akzeptiert auch http://.

Das Secret erhalten Sie über POST /companies/{id}/webhook/secret; es wird einmalig zurückgegeben (eine Rotation erzeugt ein neues). Ohne Secret senden wir den Header X-Verteco-Signature nicht.

Massenkonfiguration: ein Token, mehrere Firmen

Ein einziger API-Token (an Ihr Konto/Ihre E-Mail gebunden) verwaltet alle Firmen, die dieses Konto besitzt: Wer eine Firma über POST /companies anlegt, wird deren owner und kann ihren Webhook einrichten. Der Webhook gilt pro Firma (eigene URL und eigenes Secret), sodass Sie mit demselben Token beliebig viele Firmen anbinden:

bash
# 1) Liste Ihrer Firmen (seitenweise, siehe Firmen)
curl 'https://peppol.verteco.digital/api/v1/companies?page=0&limit=100' -H 'Authorization: Bearer vpt_8f2a…'

# 2) für JEDE Firma {id}: Webhook (und/oder E-Mail) setzen
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) Signatur-Secret abholen (wird NUR EINMAL zurückgegeben) und für die Signaturprüfung speichern
curl -X POST https://peppol.verteco.digital/api/v1/companies/{id}/webhook/secret -H 'Authorization: Bearer vpt_8f2a…'
# → { "secret": "…" }
  • Der Token muss owner/admin der jeweiligen Firma sein; bei einer Firma, in der er nur member/viewer ist, kommt 403 forbidden zurück (kein Cross-Tenant-Zugriff).
  • Sie können jeder Firma eine andere URL geben oder allen dieselbe; im Payload unterscheiden Sie sie anhand von companyId (und receiverId).
  • Bei Hunderten von Firmen beachten Sie das Rate-Limit pro Token (den aktuellen Wert liefert der Header RateLimit-Limit); arbeiten Sie in Batches mit Backoff bei 429 (Header Retry-After).
  • Der Webhook wird erst dann tatsächlich ausgelöst, wenn die Firma in Peppol aktiv ist (nach der Auswahl von Verteco als Anbieter bei der Finanzverwaltung) und somit tatsächlich Belege empfängt.

Datenmodelle

Felder der von der API zurückgegebenen Objekte.

Company

FeldTypPflichtBeschreibung
idUUID–Kennung der Firma
icostring–Handelsregisternummer (IČO, 8 Ziffern)
dicstring|null–USt-IdNr. (IČ DPH)
legalNamestring–Firmenname
registeredAddressstring|null–Sitz
peppolParticipantIdstring|null–Teilnehmer im Peppol-Netzwerk (nach der Registrierung)
statusstring–pending_verification | active
rolestring–owner | admin | member | viewer (Ihre Rolle)
createdAtInstant–Zeitpunkt der Erstellung

Document

FeldTypPflichtBeschreibung
idUUID–Kennung des Belegs
directionstring–sent | received
peppolMessageIdstring|null–ID der Peppol-Nachricht
docTypeIdstring|null–Dokumenttyp (Peppol)
senderIdstring|null–Absender (scheme:id)
receiverIdstring|null–Empfänger (scheme:id)
invoiceNumberstring|null–Rechnungsnummer
issueDatedate|null–Ausstellungsdatum
currencystring|null–Währung (z. B. EUR)
totalAmountnumber|null–Betrag
statusstring–Verarbeitungsstatus
createdAtInstant–Zeitpunkt der Erfassung

User · Token · Webhook

FeldTypPflichtBeschreibung
UserObjekt–{ id: UUID, email: string }
TokenObjekt–{ id, name, prefix, lastUsedAt|null, createdAt }
WebhookObjekt–{ url: string|null, hasSecret: boolean }

Die Felder werden direkt aus der veröffentlichten openapi.json geladen, die Tabellen sind also immer identisch mit dem, was die API liefert. Beschreibungen auf Englisch.

Datenmodelle werden aus openapi.json geladen…

Glossar

DIČ
Slowakische Steueridentifikationsnummer (10 Ziffern). Die slowakische Peppol-ID ist 0245: + die DIČ-Ziffern, ohne SK.
IČ DPH
Umsatzsteuer-Identifikationsnummer (SK + DIČ). Nur Umsatzsteuerzahler haben sie; ein Nichtzahler stellt mit Steuerkategorie O aus.
IČO
Unternehmensregisternummer (8 Ziffern). Feld ico in der API, BT-30 in UBL.
Verifikationstoken (VÚ)
Signatur der Finanzverwaltung, die bei der Anbieterwahl im FS-Portal entsteht; sie schaltet den Versand für die Firma frei.
VPDS
Die FS-Anwendung, in der ein Steuerpflichtiger seinen Zustelldienstleister (uns) wählt.
TDD
Tax Data Document, die Rechnungsmeldung an die Finanzverwaltung; wir erstellen und senden sie für Sie.
C5 / C6
Fünfte und sechste Ecke des Peppol-Modells: der Zugangspunkt der Finanzverwaltung, der TDDs empfängt (0242:001180).
MLS
Message Level Status, die Empfangsbestätigung des Zugangspunkts des Empfängers (AP = angenommen, RE = abgelehnt, AB = bestätigt).
SBDH
Standard Business Document Header, der Umschlag, in dem ein Beleg reist; sein InstanceIdentifier ist die peppolMessageId.
SML / SMP
Das Netzverzeichnis: SML findet das SMP des Empfängers, das SMP nennt Zugangspunkt und akzeptierte Belegtypen.

Slowakische Konventionen aus der Praxis der Implementierer

Über Peppol BIS Billing 3.0 hinaus einigen sich die slowakischen Hersteller von ERP- und Fakturierungssystemen laufend auf eine gemeinsame Interpretation optionaler Felder (die Diskussion läuft im Slack-Kanal der Finanzverwaltung der Slowakischen Republik, Finančná správa, FS). Nachfolgend die Konventionen, die unser Portal bereits heute berücksichtigt: Alles sind gültige BIS-Konstrukte, sie passieren unsere API unverändert, und empfangene Belege zeigen sie auch in der menschenlesbaren Vorschau und im PDF an.

  • Abzug einer versteuerten Anzahlung auf Positionsebene: eine negative Position mit cac:DocumentReference, wobei cbc:ID die Nummer des Steuerbelegs zur erhaltenen Zahlung trägt und cbc:DocumentTypeCode den Wert 130 hat (BIS: invoice line object identifier, max. 1 pro Position). Eine empfangene Rechnung mit einer solchen Position wird in unserer Vorschau mit dem Hinweis „odpočet zálohy – daňový doklad č. …" (Abzug der Anzahlung, Steuerbeleg Nr. …) angezeigt.
  • Steuerbeleg zur erhaltenen Zahlung: gemäß den FAQ der Finanzverwaltung wird InvoiceTypeCode 388 (Tax invoice) verwendet. Er passiert sowohl unsere API als auch die Validierung; der Abzug einer nicht bezahlten (nicht versteuerten) Anzahlung wird über cbc:PrepaidAmount ausgedrückt.
  • Stornierung einer Rechnung: Gutschrift 381 (CreditNote) mit cac:BillingReference auf die ursprüngliche Rechnung, keine negative Rechnung 380. Achtung: Den Code 384 lehnt das Netzwerk für slowakische Parteien ab (die Regel PEPPOL-EN16931-P0112 erlaubt ihn nur zwischen deutschen Subjekten); für eine Korrektur nach oben dient die Belastungsanzeige 383.
  • BT-83 PaymentID: in der slowakischen Praxis setzt sich für die Zahlerreferenz das Format /VS…/SS…/KS… durch; das variable Symbol allein ist ebenfalls üblich. Unsere Verarbeitung überträgt den Wert unverändert und zeigt ihn bei den Zahlungsangaben an.
  • Zusätzliche Positionsangaben (Chargen, Seriennummern, Verfallsdaten) über cac:AdditionalItemProperty mit etablierten Bezeichnungen wie BatchNumber, SerialNumber, ExpirationDate.
Es handelt sich um Konventionen der Community, nicht um verbindliche nationale Regeln: Das empfangende System muss auch einen Beleg verarbeiten können, der sie nicht verwendet. Sobald die Diskussion bei der Finanzverwaltung abgeschlossen wird, aktualisieren wir diesen Abschnitt laufend (verfolgen Sie /changelog).

Anlagen zu Belegen (BT-125)

An eine E-Rechnung können Anlagen (PDF, Bilder) als base64 im Element cac:AdditionalDocumentReference (BT-125) angehängt werden. Bei empfangenen Belegen verarbeiten wir Anlagen bis 25 MB je Anlage; beim Senden muss das gesamte XML einschließlich Base64-Anlagen unter 10 MB über SAPI-SK und unter 2 MB über den Portal-Reiter Odoslať súborom bleiben. Peppol legt kein einheitliches netzwerkweites Limit fest, die einzelnen Anbieter bestimmen es selbst (FS FAQ 9/DPH/2025/IM, Beispiel Nr. 67); prüfen Sie daher bei sehr großen Anlagen auch das Limit des Anbieters der Gegenseite.

Öffentliche Werkzeuge (Validierung, Empfängerprüfung)

Zwei Hilfs-Endpoints ohne Authentifizierung: derselbe Validierungskern und derselbe SML-Lookup, die auch unser Access Point verwendet. Sie eignen sich für CI ebenso wie für Prüfungen vor dem Versand; für sie gilt ein strengeres öffentliches Rate Limit.

POST/public/peppol-validateöffentlich

Validierung einer E-Rechnung gegen das UBL-2.1-Schema, EN 16931 und Peppol BIS Billing 3.0, dasselbe wie der UI-Validator unter /validator. Request-Body = direkt das UBL 2.1 XML (Invoice / CreditNote, ggf. das gesamte Peppol SBD), Content-Type application/xml, Limit 3 MB.

bash
curl -X POST https://peppol.verteco.digital/api/v1/public/peppol-validate \
-H "Content-Type: application/xml" \
--data-binary @faktura.xml
json
// 200 OK
{
"valid": false,
"errors": [
  "BR-CO-09: [BR-CO-09]-The Seller VAT identifier (BT-31) … shall have a prefix in accordance with ISO code…"
],
"warnings": []
}
// 400 = leerer Body (empty_document) oder Dokument über 3 MB (document_too_large)
GET/public/peppol-check?id=0245:2121358349öffentlich

Prüfung des Empfängers im produktiven Peppol-Netzwerk (SML-Lookup): Ist er registriert, und welche Belegtypen kann er empfangen? Der Parameter id akzeptiert eine Peppol ID (0245:…), eine USt-IdNr. (IČ DPH, SK…) sowie die reine DIČ (slowakische Steuernummer). Die Bezeichnungen in capabilities werden auf Slowakisch zurückgegeben. Authentifiziertes Gegenstück für ERP-Pipelines: GET /sapi/discovery.

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

MCP-Server (KI-Assistenten)

Das Portal betreibt einen eigenen Server für das Model Context Protocol, den offenen Standard, über den KI-Assistenten (Claude Code, Claude Desktop, Cursor, VS Code Copilot und andere) externe Systeme anbinden. Der Assistent meldet sich mit einem gewöhnlichen API-Schlüssel des Kontos an und erhält sechs Werkzeuge; er sieht nie mehr als dieses Konto, und jeder Aufruf erscheint im API-Log des Schlüssels.

Adresse: https://peppol.verteco.digital/api/mcp. Transport: Streamable HTTP, JSON-RPC 2.0, zustandslos (POST /api/mcp, kein SSE-Stream, GET antwortet 405). Anmeldung mit dem Header Authorization: Bearer <API-Schlüssel>. Unterstützte Methoden: initialize, ping, tools/list, tools/call, resources/list, prompts/list.

Werkzeuge

  • list_companies: Firmen des Kontos mit Peppol-ID, Status und Rolle (Beginn jedes Gesprächs)
  • list_documents: gesendete/empfangene Rechnungen einer Firma mit Zustell- und Meldestatus, seitenweise
  • get_document: eine Rechnung im Detail samt MLS-Quittung und Meldung, optional das UBL-XML (bis 1 MB)
  • check_participant: Live-Prüfung des Empfängers im Peppol-Netz (SML)
  • validate_document: UBL-Validierung gegen EN 16931 + Peppol BIS 3.0
  • send_document: Versand einer Rechnung im Namen der Firma, erfordert confirm = true, die Versandfreigabe (Verifikačný údaj) gilt

Anbindung in Claude Code

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

Claude Desktop (über die Brücke mcp-remote, benötigt Node.js)

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

Der Versand einer Rechnung ist rechtlich bindend: Das Werkzeug lehnt einen Aufruf ohne confirm = true ab, und die Serveranweisungen verpflichten den Assistenten, die ausdrückliche Zustimmung des Nutzers zur konkreten Rechnung und zum Empfänger einzuholen. Fertige Konfigurationen für Cursor und VS Code sowie eine Schaltfläche zum Erstellen des Schlüssels finden Sie im Portal: API-Schlüssel → Reiter MCP-Server. API-Schlüssel → MCP-Server

Versand per E-Mail (Adresse des Unternehmens)

Im Portal aktiviert ein Unternehmen seine eigene Adresse <24 zufällige Zeichen>@peppol.send.verteco.app. Eine E-Mail mit UBL-XML-Anhang, die aus einem freigegebenen Postfach an diese Adresse geht, versenden wir über das Peppol-Netz genau so, als wäre die Datei auf dem Reiter Per Datei senden hochgeladen worden; der Absender erhält eine Antwort mit dem Ergebnis je Anhang, und der Beleg steht mit Zustellstatus, MLS-Empfangsbestätigung und FS-Meldung im Portal und in der API. Einrichtung: Anbindungen und Integrationen → Versand per E-Mail (Eigentümer oder Administrator des Unternehmens, angemeldet). /dashboard/integrations/email

Verarbeitungsregeln

  • Angenommen wird nur Post von einer Adresse auf der Freigabeliste des Unternehmens (höchstens 20); alles andere wird ohne Antwort verworfen.
  • Standardmäßig muss die Absenderdomain beim zustellenden Server SPF oder DKIM bestehen (Angleichung wie bei DMARC, relaxed). Der zustellende Server weist zusätzlich Post ab, die weder SPF noch DKIM besteht, sowie Post gegen die DMARC-Richtlinie des Absenders. Die Prüfung lässt sich in den Einstellungen abschalten; nicht empfohlen.
  • Anhang: UBL 2.1 Invoice oder CreditNote (Peppol BIS Billing 3.0), Endung .xml, optional in einer SBDH-Hülle; höchstens 10 Anhänge pro Nachricht, 15 MB pro Anhang, 200 Nachrichten pro Adresse und Tag. PDF und Nachrichtentext werden nicht verarbeitet.
  • IFS Finvoice 2.0: ein .xml-Anhang mit IFS-SOAP-Hülle (IFSFinvoice) oder ein reines Finvoice wird in UBL umgewandelt und dann gleich verarbeitet. Umwandlungsregeln: INV02 oder negative Summe = Gutschrift (381) mit positiven Beträgen und Verweis auf die Ursprungsrechnung (OriginalInvoiceNumber, bei IFS OrderIdentifier); Verkäufer und Käufer nach slowakischer USt-IdNr. (SellerOrganisationTaxCode, BuyerOrganisationTaxCode → 0245:DIČ), ein Käufer außerhalb der Slowakei wird nicht umgewandelt; MwSt.-Aufschlüsselung aus VatSpecificationDetails, 0-%-Zeilen als Kategorie E mit Begründung aus VatFreeText, sonst „Oslobodené od DPH“; IFS-Rundungszeilen (Netto 0,00, MwSt. 0,01) entfallen, ein Einzelpreis, der nicht zur Zeilensumme passt, wird neu berechnet; Einheiten nach UN/ECE (kg → KGM, pcs → H87, h → HUR, unbekannt → C62 mit Originaltext in der Zeilennotiz); das eingebettete Rechnungsbild (InvoiceAttachments, PDF) wird bis 5 MB als Anhang mitgeführt; nur EUR. Das Ergebnis der Umwandlung steht in der Antwort und im Firmenprotokoll.
  • Ergebnisadresse: sendet ein Systempostfach die Rechnungen, wählen Sie in den Einstellungen eine andere Adresse für die Antwort mit dem Ergebnis (replyTo in PUT /companies/{id}/email-send, leer = dem Absender antworten).
  • Der Verkäufer im XML (EndpointID des Lieferanten, BT-34) muss dieses Unternehmen sein, sonst wird die Nachricht abgelehnt (eine weitergeleitete Rechnung Ihres eigenen Lieferanten wird nie als Ihre versendet). Der Käufer braucht eine EndpointID mit Schema (BT-49).
  • Dieselbe Nachricht (Message-ID) wird einmal verarbeitet. Der Beleg trägt in API und Webhooks origin = email, Akteur = Absenderadresse.
Die Adresse ist eine Berechtigung: Wer sie kennt und auf der Freigabeliste steht, versendet im Namen des Unternehmens. Deshalb lässt sie sich jederzeit austauschen (Neue Adresse erzeugen; die alte gilt sofort nicht mehr), und jeder Eingang steht im Protokoll des Unternehmens und im Sicherheitsjournal.

Status (ping)

Öffentlicher Health-Check-Endpoint, geeignet für das Monitoring.

GET/pingöffentlich

Status des Backends.

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

Eine Live-Übersicht aller Komponenten finden Sie auf der Systemstatus-Seite.

Was fertig ist und was kommt

Bereits in Produktion (oft fälschlich als fehlend angenommen)

  • POST /companies/{id}/documents/send ist eine stabile Portalschnittstelle; für ERP-Integrationen bleibt SAPI-SK mit Idempotency-Key die Empfehlung.
  • Die SMP-Registrierung erfolgt automatisch nach der Wahl im FS-Portal; Wechsel von einem anderen Anbieter über POST /companies/{id}/smp-migrate mit Migrationscode.
  • MLS-Empfangsbestätigungen, Zustellnachweise und FS-Meldungen (fsReport) in jeder Zeile von /sapi/document/sent; Webhook-Replay für ein Zeitfenster.
  • Auf Firmen beschränkte Schlüssel; MCP-Server für KI-Assistenten; UBL-Muster auf /vzory; öffentlicher Validator.

In Vorbereitung (Reihenfolge nach Nachfrage der Integratoren)

  • Asynchroner Batch: POST /sapi/document/batch antwortet 202 mit Job-Link und Status je Position.
  • Änderungsfeed GET /sapi/document/changes?since&cursor mit Cursor statt Offset-Paging.
  • Ablauf und Rotation von API-Schlüsseln im Portal, Nur-Lese-Schlüssel.
  • Mehrere Webhook-Endpunkte je Firma mit Ereignisfilter.
Fehlt Ihnen etwas Konkretes? Schreiben Sie an [email protected], was und für wie viele Belege; das beeinflusst die Reihenfolge.