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

ModeWhen it leavesUse case
immediateRight away (default, existing behavior).Low volume, instant feedback.
scheduledHeld until the configured send_time, then leaves automatically.A regular daily batch export from an accounting system.
manualHeld 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)

MethodPathScope
GET/v1/agent/peppol/send-settingsinvoice:read
PUT/v1/agent/peppol/send-settingsinvoice: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)

MethodPathScope
POST/v1/agent/peppol/batches/sendinvoice: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

MethodPathScope
GET/v1/agent/peppol/queueinvoice: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:

TransitionDescription
scheduled → queuedThe 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

From 1.1.2027 the platform refuses to send an invoice whose issue date (BT-2, 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

CodeHTTP / whereMeaning
INVOICE_ISSUE_DATE_NOT_SEND_DATE422 (single send) / skipped (batch) / ERROR (status)The issue date (BT-2) doesn't match today. Active from 1.1.2027.
VALIDATION_ERROR400Invalid PUT /send-settings body — see details for field-level errors.
CONFLICT409The invoice is already queued, held (scheduled) or sent.