Bulk sending from CSV
Bulk ingest via POST /v1/agent/peppol/csv. You upload a canonical CSV, each invoice is assembled into Peppol BIS 3.0 UBL and run through preflight; in send mode, every ready invoice is checked for credit and sent. Bad rows and per-invoice failures are reported in the response: never silently dropped.
X-API-Key and X-Organization-Id headers, scope invoice:send. The supplier is always the sending organization (never taken from the CSV).Endpoint
| Method | Path | Scope | Headers |
|---|---|---|---|
| POST | /v1/agent/peppol/csv | invoice:send | X-API-Key, X-Organization-Id |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
csvBase64 | string (base64) | Yes | Base64-encoded canonical CSV (UTF-8, BOM tolerated; separator , or ;). |
mode | preflight | send | Yes | preflight = validation only (doesn't reserve credit or send); send = validation + credit reservation + sending for every ready invoice. |
autoRepair | boolean | No | When true, normalization changes are applied and the invoice is sent; when false (default), an invoice that needs changes is rejected as needs_repair (send mode only). |
POST /v1/agent/peppol/csv
X-API-Key: efk_pk_test_...
X-Organization-Id: 0a2c1f3e-…
Content-Type: application/json
{
"csvBase64": "aW52b2ljZV9udW1iZXIsaXNzdWVfZGF0ZSxjdXJyZW5jeSwuLi4=",
"mode": "preflight"
}Canonical CSV
One row = one invoice line. Rows are grouped into invoices by invoice_number: an invoice with multiple lines has multiple rows with the same number (header fields repeat on every row of the group). Dates use the YYYY-MM-DD format, decimal numbers use a decimal point (e.g. 12.50).
| Column | Required | Description |
|---|---|---|
invoice_number | Yes | Invoice number; rows with the same number are grouped into one invoice. |
issue_date | Yes | Issue date (YYYY-MM-DD). |
due_date | No | Due date (YYYY-MM-DD). |
tax_point_date | No | Delivery date / tax point (YYYY-MM-DD). |
currency | Yes | Document currency (e.g. EUR). |
payment_iban | No | IBAN for payment. |
payment_vs | No | Variable symbol. |
buyer_name | Yes | Customer name. |
buyer_ico | No | Customer IČO. |
buyer_ic_dph | No | Customer VAT ID. |
buyer_peppol_id | No | Customer Peppol ID (e.g. 0245:DIČ); when provided, an SMP lookup also runs. |
buyer_street | No | Customer street. |
buyer_city | No | Customer city. |
buyer_zip | No | Customer postal code. |
buyer_country | No | Country code (e.g. SK). |
line_description | Yes | Line item description. |
line_quantity | Yes | Quantity (decimal with a point). |
line_unit | No | Unit of measure (e.g. ks, l, hod). |
line_unit_price | Yes | Unit price (decimal with a point). |
line_vat_rate | Yes | VAT rate in % (e.g. 23). |
line_discount | No | Line discount. |
CSV example
Invoice OF2026001 with two line items = two rows with the same invoice_number (header fields repeat):
invoice_number,issue_date,due_date,currency,payment_iban,payment_vs,buyer_name,buyer_ico,buyer_ic_dph,buyer_peppol_id,buyer_street,buyer_city,buyer_zip,buyer_country,line_description,line_quantity,line_unit,line_unit_price,line_vat_rate,line_discount
OF2026001,2026-06-22,2026-07-06,EUR,SK3112000000198742637541,2026001,Firma ABC s.r.o.,12345678,SK2012345678,0245:2012345678,Hlavná 1,Bratislava,81101,SK,Oil change,1,ks,45.00,23,0
OF2026001,2026-06-22,2026-07-06,EUR,SK3112000000198742637541,2026001,Firma ABC s.r.o.,12345678,SK2012345678,0245:2012345678,Hlavná 1,Bratislava,81101,SK,Engine oil 5W-30,4,l,12.50,23,0Response
The response is 200 and contains summary (counts), invoices (per-invoice result), and row_errors (CSV row-level errors).
{
"data": {
"summary": { "total": 2, "ready_or_queued": 1, "failed": 1 },
"invoices": [
{
"invoice_number": "OF2026001",
"send_ready": true,
"status": "queued",
"invoice_id": "b1f0d7a2-…",
"validation": { "ran": true, "valid": true, "error_count": 0, "warning_count": 0 },
"repair": []
},
{
"invoice_number": "OF2026002",
"send_ready": false,
"status": "rejected",
"reason": "validation",
"validation": { "ran": true, "valid": false, "error_count": 1, "warning_count": 0 },
"repair": [
{
"code": "BR-CO-15",
"message": "Invoice total with VAT must equal total without VAT plus the VAT amount.",
"severity": "error"
}
]
}
],
"row_errors": [
{ "row": 5, "column": "line_vat_rate", "message": "Invalid number (VAT rate)." }
]
}
}| Field | Type | Description |
|---|---|---|
summary | object | total = number of assembled invoices; ready_or_queued = ready (preflight) or queued (send); failed = failed. |
invoices | array of objects | Per-invoice result: see the table below. |
row_errors | array of objects | CSV row-level errors: row (1-based), column (optional), message. |
Invoice object
| Field | Type | Description |
|---|---|---|
invoice_number | string | Invoice number from the CSV. |
send_ready | boolean | null | Preflight verdict; null when the validator wasn't available. |
status | string | Send mode only: queued | rejected | needs_repair | failed. |
reason | string | Rejection / failure reason: validation | needs_repair | credit | validator_unavailable | build. |
invoice_id | string | null | ID of the created invoice (only for queued). |
validation | object | Run summary: ran, valid, error_count, warning_count. |
repair | array of objects | Validation findings: field, code, message, severity. |
recipient | object | null | SMP lookup result, if the CSV contained buyer_peppol_id; otherwise null. |
message | string | Human-readable message (e.g. reason for a build / credit failure). |
send mode, credit is reserved only for invoices that are send_ready: true (and don't need changes, unless autoRepair: true). An invoice without enough credit is rejected with reason: credit. Other invoices in the batch are processed independently. Test your batch in preflight mode first.Related
To send a single document from a finished UBL/CII, use Connector. Track delivery status after sending via Receiving and statuses and Delivery evidence.