Scheduled and bulk Peppol sending
An invoice sent via Peppol should leave on its issue day — so the platform releases held sends early enough for them to leave by 21:00 Europe/Bratislava. Instead of sending invoice by invoice, you can let sends collect over the day and leave together — either at a fixed time, or on your command.
Sending modes
| Mode | When it leaves | Use case |
|---|---|---|
immediate | Right away (default, existing behavior). | Low volume, instant feedback. |
scheduled | Held until the configured send_time, then leaves automatically. | A regular daily batch export from an accounting system. |
manual | Held until you release it via batches/send. | Your own scheduler, review before sending. |
Raw-UBL paths (POST /peppol/connector/send, the CSV connector, SAPI-SK, SFTP) are not controlled by the send mode — they always send immediately (the connector has its own dispatch: later parameter for that). They are still subject to the issue-date protection below.
Configuration (send-settings)
| Method | Path | Scope |
|---|---|---|
| GET | /v1/agent/peppol/send-settings | invoice:read |
| PUT | /v1/agent/peppol/send-settings | invoice:send |
PUT /v1/agent/peppol/send-settings
X-API-Key: efk_pk_live_...
X-Organization-Id: 0a2c1f3e-…
Content-Type: application/json
{
"send_mode": "scheduled",
"send_time": "18:00"
}
{
"data": {
"send_mode": "scheduled",
"send_time": "18:00",
"timezone": "Europe/Bratislava",
"deadline": "21:00"
}
}send_time is required for scheduled and at most 21:00; for immediate/manual it is dropped (GET then returns null). The only supported timezone is Europe/Bratislava — the deadlines follow Slovak VAT law. An invalid body returns 400 VALIDATION_ERROR with field-level details. The change is written to the organization's audit log.
Sending while an invoice is held
POST /v1/agent/peppol/send/{invoiceId} and POST /v1/agent/peppol/send/batch work exactly as before — in scheduled/manual mode they hold the invoice instead of queuing it.
POST /v1/agent/peppol/send/b1f0d7a2-…
X-API-Key: efk_pk_live_...
X-Organization-Id: 0a2c1f3e-…
HTTP/1.1 202
{
"data": {
"invoice_id": "b1f0d7a2-…",
"status": "scheduled",
"send_at": "2026-09-23T16:00:00.000Z"
}
}A batch call holds the whole batch the same way; individual invoices that fail validation (including the issue-date protection below) are still listed in skipped:
POST /v1/agent/peppol/send/batch
X-API-Key: efk_pk_live_...
X-Organization-Id: 0a2c1f3e-…
{ "invoiceIds": ["b1f0d7a2-…", "c2a1e8b3-…"] }
HTTP/1.1 202
{
"data": {
"batch_id": null,
"status": "scheduled",
"send_at": "2026-09-23T16:00:00.000Z",
"queued": 0,
"scheduled": 1,
"skipped": [
{ "id": "c2a1e8b3-…", "reason": "INVOICE_ISSUE_DATE_NOT_SEND_DATE: …" }
],
"total": 2
}
}Manual release (batches/send)
| Method | Path | Scope |
|---|---|---|
| POST | /v1/agent/peppol/batches/send | invoice:send |
Releases all of the organization's held sends for the calling key's mode (live/test) right away — no request body. A send that no longer qualifies (e.g. the issue day has since moved on) becomes error and fires the peppol.document.failed webhook.
POST /v1/agent/peppol/batches/send
X-API-Key: efk_pk_live_...
X-Organization-Id: 0a2c1f3e-…
HTTP/1.1 202
{
"data": {
"batch_id": "8b2e1c4a-…",
"queued": 42,
"skipped": []
}
}Queue and states
| Method | Path | Scope |
|---|---|---|
| GET | /v1/agent/peppol/queue | invoice:read |
GET /v1/agent/peppol/queue
X-API-Key: efk_pk_live_...
X-Organization-Id: 0a2c1f3e-…
HTTP/1.1 200
{
"data": {
"scheduled": 5000,
"queued": 0,
"sending": 40,
"sent_today": 12300,
"failed": 3,
"estimated_finish": "19:42",
"safety_cutoff": "19:48",
"deadline": "21:00",
"send_mode": "scheduled",
"send_time": "18:00",
"timezone": "Europe/Bratislava"
}
}estimated_finish and safety_cutoff are estimates for the whole platform (shared Access Point), not just your organization — at high platform-wide volume they can shift during the day. sent_today and failed count the current day in Europe/Bratislava.
An individual invoice's status still comes from GET /v1/agent/peppol/status/{invoiceId}, with a new state value:
| Transition | Description |
|---|---|
scheduled → queued | The hold was released (send_time, batches/send, or the safety cutoff). |
queued → processing (SENDING) | The worker is dispatching via the AP. |
processing → sent (SENT) | The Peppol network accepted it. |
→ error (ERROR) | A failure anywhere along the path — including a failure before it ever reaches the network (e.g. the issue-date gate). error_message carries the reason. |
Safety cutoff & automatic fail-safe
Even in scheduled/manual mode an automatic fail-safe applies: the platform continuously computes safety_cutoff — the instant by which it must release every held send so it can still leave by 21:00, with a 30-minute buffer for retries on transient failures. With 40,000 pending sends and a capacity of ~120/min, the cutoff works out to 14:56. After the cutoff, new sends are processed immediately, even if the organization is in manual mode and the client never called batches/send. A send held from an earlier day is released at once (and will fail the issue-date protection below, if the gate is active).
Issue-date protection
cbc:IssueDate) doesn't match today in Europe/Bratislava — across every mode and path, including the raw-UBL connector, SAPI-SK and SFTP.Per the Slovak Financial Administration's e-Faktúra FAQ (11.9.2026, example 74), for an e-invoice sent through a delivery service provider the issue date is the day it is handed over — and the issue date printed on the invoice must equal that day. Legal basis: § 85o ods. 9, 11 and 12 of Act No. 222/2004 Z. z. on value-added tax (reporting at the moment of issue, fulfilled by handing the document to the delivery service provider; a fine of up to 10,000 €, up to 100,000 € for repeated breaches). The same-day rule is the Financial Administration's interpretation of this provision, not the literal wording of the act; consult a tax advisor for a binding interpretation for your case.
HTTP/1.1 422
{
"error": "INVOICE_ISSUE_DATE_NOT_SEND_DATE",
"message": "INVOICE_ISSUE_DATE_NOT_SEND_DATE: Dátum vyhotovenia faktúry (01.01.2027) sa musí zhodovať s dňom odoslania cez Peppol (03.01.2027). Upravte dátum vyhotovenia na dnešný deň a odošlite faktúru znova."
}POST /send/{invoiceId} returns the error immediately (in this non-standard flat shape, see Error codes); a batch call lists the invoice in skipped; a held send fails it at release; raw-UBL/connector/SAPI/SFTP sends fail with the same message and fire the peppol.document.failedwebhook. Remedy: re-issue the document with today's date, schedule sends so they leave the same day, and never set send_time after 21:00. The gate has no effect before 1.1.2027.
Large volumes
Sending shares one Access Point across the whole platform, so pace is bounded by PEPPOL_SEND_CAPACITY_PER_MINUTE(a conservative estimate, roughly ~120/min) split fairly across organizations — one large batch doesn't block everyone else. Sends that hit a transient Access Point failure are retried automatically for ~30 minutes (6 attempts, exponential from 1 minute). The estimated_finish from GET /queue is intentionally conservative — leave headroom when choosing a send_time.
Error codes
| Code | HTTP / where | Meaning |
|---|---|---|
INVOICE_ISSUE_DATE_NOT_SEND_DATE | 422 (single send) / skipped (batch) / ERROR (status) | The issue date (BT-2) doesn't match today. Active from 1.1.2027. |
VALIDATION_ERROR | 400 | Invalid PUT /send-settings body — see details for field-level errors. |
CONFLICT | 409 | The invoice is already queued, held (scheduled) or sent. |