A published, read-only API reference is now served at
/reference.
It includes a browsable
error-code catalogue, and every
application/problem+json error now carries a
type URI that deep-links straight to the section for that
code, explaining what the condition means and how to resolve it. The
interactive "Try it out" console here on /docs is
unchanged.
POST /document/send
Cheap structural checks now run synchronously, before the
202. A payload that is not well-formed XML,
declares a DTD, is not a recognised Peppol document, or does not match
the declared metadata.documentTypeId is rejected
immediately with a 400 instead of being accepted and
failing later. All such rejections happen before any side-effect, so
the same Idempotency-Key may be retried with a corrected
payload. The expensive BIS3 / Schematron validation stays
asynchronous, surfaced via document status and webhooks as before.
Behaviour change — receiver reachability is now resolved
asynchronously. Sending to a receiver that is absent from the
SMP (or does not advertise the requested document type / process) is
no longer a synchronous 422. The document is accepted
with 202 and resolves asynchronously to
sendingStatus = SENDING_FAILED (no AS4 attempt is made).
Observe the outcome on GET /document/send/{id} or the
document.sendingFailed webhook — not on
the POST response. The synchronous 422 now covers only
UNSUPPORTED_DOCUMENT_TYPE / UNSUPPORTED_PROCESS
(types this Access Point does not handle at all). This keeps an
undeliverable document in the system for C5 fiscal reporting.
Acceptance is now atomic. A 202 is
returned only once the payload is durably stored and the document is
persisted — acceptance is all-or-nothing. Replaying an accepted
submission (same Idempotency-Key + body) returns the
original 202 verbatim — it is an
acceptance acknowledgement, not a live status, so use
GET /document/send/{id} or webhooks for current state.
This release introduces error codes you may now receive. If you branch
on the stable code field, add handling for:
MALFORMED_XML, XML_DTD_FORBIDDEN,
DOCTYPE_DETECTION_FAILED, DOCTYPE_MISMATCH
— synchronous 400 on /document/send from
the new structural pre-validation. Permanent; fix the payload and
retry with the same Idempotency-Key.
RECEIVER_NOT_FOUND,
RECEIVER_DOES_NOT_SUPPORT_DOCUMENT_TYPE,
RECEIVER_DOES_NOT_SUPPORT_PROCESS — asynchronous
errorCode on a SENDING_FAILED document
(and on the document.sendingFailed webhook), replacing
the former synchronous 422. The receiver is unroutable;
fix the address or document type rather than blindly resubmitting.
PAYLOAD_STORE_UNAVAILABLE — transient 503
on /document/send when the payload store is briefly
unavailable. Nothing is persisted (no document, your
Idempotency-Key is not consumed, no webhook), so retry
with the same key — a transient infra outage is
never recorded as a terminal document failure.
PAYLOAD_UNAVAILABLE — 404 on payload-read
endpoints (GET /document/send/{id}/payload,
GET /document/receive/{id}/payload): the document exists
but its stored payload can no longer be retrieved. Permanent and
distinct from DOCUMENT_NOT_FOUND and from the transient
PAYLOAD_STORE_UNAVAILABLE.
Make sure every code above is covered in your
integration. The full, authoritative set a client can
receive — with the meaning and recommended action for each — is in
the error-code catalogue at
/reference.
Branch on the
stable code field, and treat any code you do not
recognise as a non-retryable failure to surface for investigation.
creationDateTime surfaced on receive
Received documents now expose the document creation timestamp from
the inbound SBDH as metadata.creationDateTime. Inbound
wrappers from the Peppol network do not always carry it, so the field
is nullable — clients MUST handle null.
Failed webhook deliveries are now retried for roughly
72 hours (up to 26 attempts, each backoff gap capped
at 6 hours) so a weekend-long outage on your endpoint can recover
before delivery is abandoned. The X-Everifin-Attempt
counter now ranges up to 26.
POST /document/validate — valid now means structural acceptance only
To make the result more intuitive, valid no longer
folds in whether the receiver is reachable. It now equals
structuralValid — it answers a single question:
will /send accept this document? A new
required deliverable: boolean carries the routing check
(the logical AND of receiverReachable,
receiverSupportsDocType, and
processIdAdvertised), and those three fields are now
advisory / warning only.
Previously valid was the AND of all four layers, which
misleadingly signalled "do not send" whenever the receiver's
Access Point was unreachable — even though such a document should
still be sent (and, where applicable, reported to Finančná správa).
Gate sending on valid only; treat
deliverable and the reachability fields as advisory. A
document with valid: true, deliverable: false is correct
to submit.
Lifecycle events are now delivered as HMAC-signed
webhooks — the preferred way to observe document
progress without polling. Each delivery carries an
X-Everifin-Delivery-Id and a signature over the body;
failed deliveries are retried with exponential backoff. The event
payload includes participantId, so a single endpoint
can be reused across tenants and routed internally.
There is no self-service subscription API yet.
To enable webhooks for your tenant, request a subscription by
email at
[email protected]
— Everifin operations provisions the endpoint URL and signing
secret for you. REST polling
(GET /document/inbox, GET /document/send/{id})
remains available as a fallback when no webhook is configured or a
delivery fails.
GET /document/send/{id}/events and
GET /document/receive/{id}/events are now liveThey return the ordered lifecycle event
journal for a single document — the same events that drive
webhooks — so you can reconcile a document's full history on
demand.
GET /participants/{participantId} now lets you check
whether a business partner is already registered in the Peppol
network — anywhere in it, not just on our Access Point. A
200 means the partner is reachable over Peppol; a
404 means they are not (yet) registered. The response
additionally lists which document types they advertise and
(when published) their Business Card.
POST /document/validate — new processIdAdvertised check
ValidateResponse gains a required
processIdAdvertised: boolean. valid is now
the logical AND of four layers (was three):
structuralValid, receiverReachable,
receiverSupportsDocType, and the new
processIdAdvertised. The new field is
true only when the receiver's SMP record advertises
the requested processId under the requested
documentTypeId — closes a previous gap where a
mismatched processId would pass /validate
and then fail on the actual send.
VALIDATION_FAILED
When sendingStatus = VALIDATION_FAILED, the response
now includes a violations[] array (new required field
on SentDocumentSummary, returned by
GET /document/send and
GET /document/send/{id}) with rule-level detail: rule
code, XPath, and message. Empty array on the happy path, on
non-validation terminal states, and when the verifier rejected
without enumerable rule detail (e.g. XML parse failure, unknown
document type).
Stage is wired to the Peppol test network — documents really travel through AS4 to a real receiver AP, but only test participants live there. Two pre-provisioned test firms are available for end-to-end exercises (request for access if you didn't obtain test credentials).
POST /document/send — submit a UBL document for delivery.GET /document/send — list sent documents (cursor pagination, filters, sort by submittedAt). New.GET /document/send/{id} — sent-document status (three-axis snapshot: sending / C3 delivery / C5 reporting).GET /document/send/{id}/payload — download the raw bytes of a sent document. New.GET /document/receive — list received documents (cursor pagination, filters, sort by receivedAt).GET /document/inbox — polling-friendly worklist of not-yet-acknowledged received documents, oldest first.GET /document/receive/{id} — received-document detail (with payload, controlled by payloadFormat).GET /document/receive/{id}/payload — download the raw bytes of a received document. New.POST /document/receive/{id}/acknowledge — mark a received document as processed by the downstream system.Idempotency-Key scope is now per-participant
(was per-tenant).
payloadTransferEncoding default and enum changed.
New values: raw (default) and base64 —
replacing the previous base64 (default) / none.
The default switched from base64 to raw XML; clients relying on the
default will now send/receive raw XML inline in JSON. The receive
side additionally accepts none (omit payload,
fetch bytes via the new /payload endpoint).
SendDocumentResponse fields renamed.
receivedAt → submittedAt, the
timestamp field has been removed, and a new required
payloadSize (bytes, int64) was added.
from → receivedAtFrom,
to → receivedAtTo, and the single
sort parameter has been split into
SortReceivedAt (receive endpoints) and
SortSubmittedAt (send list). The upper-bound semantics
also changed: the previous to was exclusive
(< to), receivedAtTo is now inclusive
(<= receivedAtTo).
TIMED_OUT value on both
c3DeliveryStatus and c5DeliveryStatus.
On C3, returned when the receiving Access Point did not
acknowledge the message via MLS within the expected window — the
message was received by the receiving AP, but the receiver
participant might not be reachable or the receiving AP did not
send the MLS response due to a technical error. On C5, mirrors
the same shape on the reporting side — set when the fiscal
authority does not return an acceptance or rejection within the
expected window. Treat both as "sent successfully without
read receipt": do not auto-resend or auto-resubmit.
GET /document/receive/{id} accepts a new
payloadFormat query parameter
(raw | base64 | none)
controlling how the payload is encoded in the JSON response
(or whether it is included at all).
hasMore boolean alongside
nextPageToken. Prefer checking hasMore
over relying on the absence of nextPageToken.
payloadSize (bytes, int64) added to
send and receive summary/detail schemas — the size of the stored
payload after transfer-encoding has been decoded.
ReceivedDocumentMetadata
for inbound documents: creationDateTime is now optional
and nullable, because inbound SBDH wrappers from the
Peppol network do not always carry a creation timestamp.