E-Invoicing
The E-Invoicing API submits, clears, and tracks B2B invoices across 37 countries, directly with tax authorities or over the Peppol network (two are receive-only) — SDI, KSeF, ANAF, myDATA, XRechnung, Peppol, and more. One JSON payload in; the correct country format, authority submission, and clearance tracking handled for you.
https://api.clearvo.io/v1) and the same csk_live_* / csk_test_* key system as every other Clearvo product — see Authentication. No separate credentials needed. Plain HTTP requests are automatically redirected to HTTPS (307 Temporary Redirect).New to Clearvo? See the docs home for Tax Calculations, Tax Number Validation, Compliance Radar, and Real-Time Reporting.
How it works
You send one JSON payload to POST /send. Clearvo transforms it into the correct country format (FatturaPA, FA(3), XRechnung, etc.), submits it to the relevant authority, and returns a referenceId. You then poll GET /status or receive a webhook when the clearance status changes.
Send a POST /send request with your invoice data. Receive a referenceId and initial clearanceStatus.
Call GET /status on a schedule, or configure a webhook to receive push notifications on every status transition.
A terminal status (ACCEPTED, REJECTED, DUPLICATE) ends the lifecycle. Non-terminal statuses require continued polling.
Quickstart
Submit your first invoice in under two minutes. This example sends an Italian B2B invoice to the SDI.
curl https://api.clearvo.io/v1/send \
-X POST \
-H "x-api-key: csk_live_••••••••••••" \
-H "x-idempotency-key: a3f9c2d1-e847-4b6a-9c12-d3f0e1a2b7c8" \
-H "Content-Type: application/json" \
-d '{
"documentType": "invoice",
"invoiceNumber": "INV-2024-001",
"issueDate": "2024-01-15",
"currency": "EUR",
"country": "IT",
"supplier": {
"name": "Acme SRL",
"taxId": "01234567890",
"establishmentCountry": "IT",
"address": { "street": "Via Roma 1", "city": "Milano", "postalCode": "20121", "country": "IT" }
},
"customer": {
"name": "Cliente SpA",
"taxId": "09876543210",
"establishmentCountry": "IT",
"address": { "street": "Via Veneto 10", "city": "Roma", "postalCode": "00187", "country": "IT" }
},
"lines": [
{ "description": "Software licence Q1", "quantity": 1, "unitPrice": 1000.00, "taxRate": 22 },
{ "description": "Support hours", "quantity": 8, "unitPrice": 125.00, "taxRate": 22 }
]
}'
A successful response returns:
{
"ok": true,
"country": "IT",
"referenceId": "IT-20240115-INV-001",
"clearanceStatus": "PENDING",
"terminal": false,
"submittedAt": "2024-01-15T10:30:00Z",
"nextPollAfter": "2024-01-15T10:35:00Z"
}
Store the referenceId — you'll use it to poll for the final clearance decision.
POST /send
Submit a new invoice for clearance. Clearvo validates the payload, generates the country-specific XML format, and forwards it to the relevant tax authority.
POST https://api.clearvo.io/v1/sendNode.js example
const response = await fetch('https://api.clearvo.io/v1/send', {
method: 'POST',
headers: {
'x-api-key': process.env.CLEARVO_API_KEY,
'x-idempotency-key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
documentType: 'invoice',
invoiceNumber: 'INV-2024-001',
issueDate: '2024-01-15',
currency: 'EUR',
country: 'IT',
supplier: {
name: 'Acme SRL',
taxId: '01234567890',
establishmentCountry: 'IT',
address: { street: 'Via Roma 1', city: 'Milano', postalCode: '20121', country: 'IT' },
},
customer: {
name: 'Cliente SpA',
taxId: '09876543210',
establishmentCountry: 'IT',
address: { street: 'Via Veneto 10', city: 'Roma', postalCode: '00187', country: 'IT' },
},
lines: [
{ description: 'Software licence Q1', quantity: 1, unitPrice: 1000.00, taxRate: 22 },
{ description: 'Support hours', quantity: 8, unitPrice: 125.00, taxRate: 22 },
],
}),
});
const invoice = await response.json();
console.log(invoice.referenceId); // "IT-20240115-INV-001"
Response fields
| Field | Type | Description |
|---|---|---|
| ok | boolean | Always true on 2xx. |
| country | string | ISO country code the invoice was routed to. |
| referenceId | string | Clearvo-assigned identifier for this invoice submission. Use with GET /status. |
| clearanceStatus | string | Initial status — always PENDING for async countries; ACCEPTED immediately for synchronous flows (DE B2B). |
| terminal | boolean | true when the status will not change again. Stop polling when true. |
| submittedAt | string (ISO 8601) | UTC timestamp of submission. |
| nextPollAfter | string (ISO 8601) | Earliest time to poll for an update. Respect this to avoid rate limiting. |
GET /status
Retrieve the current clearance status and full event history for a submitted invoice.
GET https://api.clearvo.io/v1/status?country=IT&id=<referenceId>Query parameters
| Parameter | Type | Description |
|---|---|---|
| country | string | ISO 3166-1 alpha-2 country code. Required |
| id | string | The referenceId returned by POST /send. Required |
Polling loop (JavaScript)
async function waitForClearance(referenceId, country) {
const MAX_POLLS = 48; // 4 hours at 5-min cadence
let polls = 0;
while (polls++ < MAX_POLLS) {
const res = await fetch(
`https://api.clearvo.io/v1/status?country=${country}&id=${referenceId}`,
{ headers: { 'x-api-key': process.env.CLEARVO_API_KEY } }
);
const data = await res.json();
if (data.terminal) {
return data; // ACCEPTED | REJECTED | DUPLICATE
}
// Honour nextPollAfter — don't hammer the API
const wait = new Date(data.nextPollAfter) - Date.now();
if (wait > 0) await new Promise(r => setTimeout(r, wait));
}
throw new Error('Max polls reached — check Italy UNDELIVERED / mcDeadline');
}
Status response fields
| Field | Type | Description |
|---|---|---|
| clearanceStatus | string | Current status. See clearance status values below. |
| terminal | boolean | Stop polling when true. |
| events | array | Ordered array of status transitions. Each entry has at (ISO 8601), event (the status or step name) and detail (free-text description). |
| clearedAt | string? | Timestamp of clearance. Present when ACCEPTED or DELIVERED. |
| rejectedAt | string? | Timestamp of rejection. Present only when REJECTED. |
| error | object? | Authority rejection detail. Present only when REJECTED. Shape: { code, message, retryable, upstreamCode, upstreamMessage } — code is a Clearvo error code (or CLEARANCE_REJECTED), message is the suggested action or a plain-language summary, retryable is always false for an authority rejection, and upstreamCode / upstreamMessage carry the authority's own code and text (or null). |
| errorCode | string? | Structured error code, present whenever the invoice failed with a mapped reason (pre-submission validation failures as well as authority rejections). |
| suggestedAction | string? | What to do next, in plain language. Present with errorCode. |
| isMerchantResolvable | boolean? | true when you can fix the cause yourself (for example, missing data); false when it needs Clearvo or the authority. Present with errorCode. |
| fixUrl | string? | Link to the dashboard page where the problem can be fixed, when there is one. |
| mcDeadline | string? | Italy only. The SDI 10-day delivery deadline in ISO 8601. Present only when UNDELIVERED. |
| nextPollAfter | string? | Earliest recommended next poll time. Absent when terminal. |
Clearance status values
| Status | Terminal? | Description |
|---|---|---|
| PENDING | No | Submitted to the authority; awaiting response. Continue polling. |
| DELIVERED | Yes | Peppol only. Invoice delivered to the customer's Access Point via AS4. clearedAt is set. |
| ACCEPTED | Yes | Cleared by the tax authority (IT/SDI, PL/KSeF, AR/AFIP, RO/ANAF, HU/NAV, GR/myDATA, ES/VeriFactu, PT/AT). clearedAt is set. |
| UNROUTABLE | No | Peppol only. Customer not found on the Peppol network, or their endpoint cannot be derived from the VAT number. UBL XML is stored. Retry delivery via POST /v1/invoices/{id}/deliver once the customer registers, or supply an explicit customer.electronicAddress. |
| REJECTED | Yes | Authority rejected the invoice. Check the error block for reason codes. |
| DUPLICATE | Yes | Authority already has this invoice number. No action needed if intentional. |
| UNDELIVERED | No | Italy (SDI) only. SDI cannot reach the recipient's inbox. SDI retries for 10 days. After that deadline the invoice may still be legally valid — see the Italy guide. |
GET /participants/lookup
Check whether a customer is registered on the Peppol network and retrieve their AS4 endpoint. Results are served from cache when available. Pass forceRefresh=true to re-query the SML live.
GET https://api.clearvo.io/v1/participants/lookup?country=BE&vatNumber=BE0420429272Query parameters
| Parameter | Type | Description |
|---|---|---|
| country | string | ISO country code. Required when using vatNumber. Optional with electronicAddress |
| vatNumber | string | Customer VAT number. Clearvo derives the Peppol participant ID automatically. Optional if electronicAddress provided |
| electronicAddress | string | Explicit Peppol identifier (e.g. 0420429272). Requires electronicAddressSchemeId or country. Optional if vatNumber provided |
| electronicAddressSchemeId | string | EAS code (e.g. 0208). Used with explicit electronicAddress. Optional |
| documentType | string | invoice or credit_note. Determines which document type ID to look up in SMP. Default: invoice. Optional |
| forceRefresh | boolean | Set to true to bypass cache and re-query the SML live. Optional |
Response
| Field | Type | Description |
|---|---|---|
| registered | boolean | true if the customer is registered on Peppol and has a reachable endpoint. |
| participantId | string? | Canonical Peppol participant ID, e.g. iso6523-actorid-upis::0208:0420429272. |
| endpointUrl | string? | The customer's AS4 endpoint URL. Present when registered: true. |
| derivedFrom | string? | "vatNumber" or "electronicAddress" — how the participant ID was resolved. |
| cached | boolean? | true if the result was served from cache; false if a live SML lookup was performed. |
| checkedAt | string? | ISO 8601 timestamp of the last SML lookup. |
POST /invoices/{id}/deliver
Retry Peppol AS4 delivery for an invoice that is UNROUTABLE. Clearvo re-queries the SML (bypassing cache), and re-attempts delivery. On success the invoice moves to DELIVERED. On continued failure it stays UNROUTABLE and can be retried again.
POST https://api.clearvo.io/v1/invoices/{id}/deliverPath parameter
| Parameter | Type | Description |
|---|---|---|
| id | string | Invoice id or referenceId returned by POST /send. Required |
Request body (optional)
| Field | Type | Description |
|---|---|---|
| electronicAddress.value | string | Override the customer's Peppol endpoint identifier. Use this once the customer has registered, or to correct a wrong value. Optional |
| electronicAddress.schemeId | string | EAS code for the override electronicAddress.value. Optional |
Response
| Field | Type | Description |
|---|---|---|
| ok | boolean | true on delivery success, false if still unroutable. |
| clearanceStatus | string | DELIVERED on success; UNROUTABLE on failure. |
| nrr | boolean? | Present on success. true if the receiver's AP returned a Non-Repudiation Receipt. |
| deliveryError | object? | Present on failure. { code, message, retryable }. |
Error responses
| HTTP | Meaning |
|---|---|
| 404 | No record found for the given id. |
| 409 | Invoice is not in UNROUTABLE state (already DELIVERED, ACCEPTED, etc.). |
| 422 | No stored XML or customer endpoint cannot be determined; provide electronicAddress in the body. |
Supported Countries
Pass the two-letter ISO code in the country field. Clearvo generates the correct country format, then submits it, reports it or delivers it over the Peppol network, depending on the model below. Mandate dates are the legal dates for the country, not Clearvo availability, and can change. Check the authority before relying on a date for a compliance decision. Call GET /v1/requirements?country=XX for the exact fields a country needs.
| Country | Authority / network | Format | Model | Mandate |
|---|---|---|---|---|
| Clearance — the authority validates the invoice before it is issued | ||||
| IT | SDI (Agenzia delle Entrate) | FatturaPA 1.2 | Clearance | Mandatory since Jan 2019 |
| PL | KSeF (Ministry of Finance) | FA(3) XML | Clearance | Large taxpayers from 1 Feb 2026; all other VAT payers from 1 Apr 2026; penalties from 1 Jan 2027 |
| RO | ANAF e-Factura | CIUS-RO (UBL) | Clearance | B2B mandatory since 1 Jan 2024 |
| AR | AFIP | Factura Electrónica (CAE) | Clearance | Mandatory |
| SA | ZATCA (Fatoora) | UBL 2.1 | Clearance (B2B/B2G); reporting within 24h (B2C) | Mandatory, phased by taxpayer wave |
| EG | ETA | ETA e-invoice | Clearance | Mandatory |
| JO | ISTD JoFotara | UBL 2.1 | Clearance | Mandatory |
| Real-time and periodic reporting — the invoice is issued directly, data is reported to the authority | ||||
| HU | NAV Online Számla | Online Számla v3.0 XML | Real-time reporting | Since Jul 2018; all invoices (including zero VAT) since Jan 2021 |
| GR | AADE myDATA | myDATA XML | Real-time reporting | Mandatory since Nov 2021 |
| ES (SII) | AEAT — Suministro Inmediato de Información | SII XML | Real-time reporting (VAT ledger) | Mandatory for large taxpayers, VAT groups and REDEME since Jul 2017; voluntary for others |
| ES (VeriFactu) | AEAT | VeriFactu XML (hash-chained records) | Certified billing records | Postponed (announced Oct 2026) to October 2028, aligned with Spain's B2B e-invoicing mandate (businesses over €8m turnover from 6 Oct 2027, everyone else from 6 Oct 2028). Confirm exact dates against the BOE |
| PT | AT (Autoridade Tributária) | SAF-T (PT) + ATCUD + QR code | Certified invoicing + invoice-data communication | Certified software required today |
| FR | DGFiP — via an accredited platform (PA) | Factur-X (EN16931) | Network delivery + e-reporting | Receiving: all businesses from 1 Sep 2026. Issuing: large and mid-size from 1 Sep 2026; small and micro from 1 Sep 2027 |
| Structured invoice generation and download (optionally delivered over Peppol) | ||||
| DE | No central authority | XRechnung 3.0 (UBL), ZUGFeRD (CII, EN16931 profile) or Peppol BIS 3.0 | Generate, or deliver over Peppol | Receiving: all businesses since 1 Jan 2025. Issuing: turnover above €800k from 1 Jan 2027; all others from 1 Jan 2028 |
| Peppol BIS Billing 3.0 — Europe | ||||
| BE | OpenPeppol | Peppol BIS 3.0 UBL | Network delivery | B2B mandatory from 1 Jan 2026 (penalties from 1 Apr 2026) |
| NL | OpenPeppol / Digipoort | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| AT | OpenPeppol / eRechnung.gv.at | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| HR | OpenPeppol / FINA | Peppol BIS 3.0 UBL | Network delivery | Mandatory from 2026 |
| SK | OpenPeppol / Financial Administration | Peppol BIS 3.0 UBL (+ Tax Data Document) | Network delivery + tax data reporting | B2B mandatory from 1 Jan 2027 |
| IE | OpenPeppol / OGP | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| NO | OpenPeppol / DFØ | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| SE | OpenPeppol / Skatteverket | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| DK | OpenPeppol / NemHandel | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| FI | OpenPeppol / Vero | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| LT | OpenPeppol / VMI | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| LV | OpenPeppol / VID | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| EE | OpenPeppol / MTA | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| LU | OpenPeppol | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| SI | OpenPeppol / FURS | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| IS | OpenPeppol / RSK | Peppol BIS 3.0 UBL | Network delivery | B2G mandatory |
| CH | OpenPeppol / SIX | Peppol BIS 3.0 UBL | Network delivery | No mandate; B2B via Peppol network |
| Peppol PINT — Asia-Pacific & Gulf | ||||
| AU | ATO / OpenPeppol | Peppol PINT A-NZ | Network delivery | B2G mandatory |
| NZ | NZ Peppol Authority | Peppol PINT A-NZ | Network delivery | B2G mandatory |
| JP | Digital Agency / OpenPeppol | Peppol JP PINT | Network delivery | Voluntary; B2G adoption |
| SG | IMDA / IRAS (InvoiceNow) | Peppol SG PINT | Network delivery | GST InvoiceNow phased in from 2025 to 2031 by registrant type |
| AE | Ministry of Finance / FTA | Peppol UAE PINT | Network delivery | Pilot from 1 Jul 2026; large businesses from 1 Jan 2027 |
| Receive-only — Clearvo ingests, validates and stores invoices your suppliers issue | ||||
| MX | SAT | CFDI 4.0 | Receiving | Mandatory (issued by suppliers through their PAC) |
| BR | SEFAZ | NF-e / NFS-e | Receiving | Mandatory (issued by suppliers) |
Authority credentials. Clearvo handles authority sessions, signing and polling. For Poland (KSeF token), Hungary (NAV technical user), Romania (ANAF token), Greece (myDATA user and key), Argentina (AFIP certificate), Portugal (AT series) and Saudi Arabia (ZATCA onboarding), you connect your own credentials once per entity, in the dashboard or through the credentials endpoints. Spain, Germany, France and the Peppol countries need no authority credentials from you. See the country guides below.
country and the buyer's Peppol endpoint differ. Delivery uses Clearvo's certified Peppol Access Point (PIE001162). For Netherlands (KvK), Austria, Slovakia (IČO), Iceland, Switzerland, New Zealand and the UAE you must supply the buyer's endpointId; for the other countries it is derived from the tax number.Request body
Send a JSON object to POST /v1/send. This table is generated from the API contract (openapi.json) and lists every accepted field.
| Field | Type | Description |
|---|---|---|
| documentType | enum | Credit and debit notes need originalInvoiceRef or correctsInvoiceId. Over Peppol, credit notes and debit notes are supported in Belgium, the Netherlands, Austria, Croatia, Slovakia, Ireland, Norway, Sweden, Denmark, Finland, Lithuania, Latvia, Estonia, Luxembourg, Slovenia, Iceland, Switzerland, Germany (when the Peppol format is used), Australia and New Zealand. A credit note reverses a previously accepted invoice in full; partial credit notes over Peppol are not supported yet (only France and Spain support partial credit notes). A debit note is sent as an invoice marked as a debit note (UNTDID 1001 type code 383), because Peppol has no separate debit-note document. Singapore, Japan and the UAE do not yet support credit or debit notes over Peppol: the request returns 422 CREDIT_NOTE_PEPPOL_UNSUPPORTED; send a corrected invoice instead or contact support. One of: invoice, credit_note, debit_note. Required |
| invoiceNumber | string | Seller-assigned invoice number, unique per seller. The invoice number (with documentType and country, and for a purchase the supplier tax ID and issue date) is what identifies the document: it builds the system identity key that deduplicates, so a changed re-send of the same number is refused 409 IDEMPOTENT_BODY_MISMATCH. A document missing one of those fields is refused 422 MISSING_IDENTITY_FIELD. Required |
| issueDate | string | Required |
| taxPointDate | string | VAT point / tax point date (EN16931 BT-7), when it differs from issueDate. The tax point drives all reporting-side date logic: Compliance Mandate effective-date matching and reporting-period membership both use taxPointDate first, falling back to issueDate. Omit when the two are the same. Optional |
| dueDate | string | Optional |
| currency | string | Required |
| taxReportingCurrency | string | ISO 4217 currency this invoice must be VAT-reported in, when it differs from currency (EN16931 BT-6 — e.g. a EUR invoice for a transaction whose jurisdiction reports in RON). Omit to let it resolve automatically from the transaction's own tax jurisdiction; only set it to override that. When the resolved reporting currency differs from currency, you must also supply exchangeRate or taxReporting, or the call fails with 422 TAX_REPORTING_CONVERSION_MISSING — Clearvo never fetches or computes an exchange rate itself. Optional |
| exchangeRate | number | currency -> taxReportingCurrency rate, applied uniformly to every total (subtotal, tax-exclusive amount, tax total, grand total). Mutually exclusive with taxReporting — 422 EXCHANGE_RATE_AND_TAX_REPORTING_BOTH_SUPPLIED if both are sent. Optional |
| taxReporting | object | Authoritative tax-exclusive amount, tax total and total in taxReportingCurrency, taken as-is rather than back-derived from a single collapsed figure or exchange rate — your own rounding of net+tax often isn't identical to rounding the gross directly, and the tax amount specifically usually needs to reconcile exactly with your own books. Mutually exclusive with exchangeRate. Optional |
| country | string | Target clearance country — ISO 3166-1 alpha-2 (determines the authority and XML format). This is also the tax jurisdiction the line resolution reports against; for an outgoing invoice the supplier tax ID is taken from the entity's registration in this country (see supplier.taxId), so an entity registered here but based elsewhere can omit supplier details. Required |
| taxIncluded | boolean | When true, all line unitPrices are gross (VAT-inclusive) by default. Can be overridden per line. Optional |
| supplier | object | Seller details. Optional — when omitted the API derives the supplier from the entity's master data (name, tax ID, and address). Provide explicitly to override name/address. supplier.taxId is optional either way — see the Party schema: when omitted the entity's registered tax ID for the resolved mandate's country is applied; when supplied it must match that registration (422 SUPPLIER_TAX_ID_MISMATCH). For Spain SII / VeriFactu a missing or lapsed Spanish registration as of the document date holds the submission as NEEDS_INFO with errorCode MISSING_SUPPLIER_REGISTRATION (200, non-terminal, fixUrl to the Registrations page) — add or renew the ES registration, then resubmit with correctsInvoiceId set to the held invoice's id. Returns 422 MISSING_SUPPLIER_DATA if omitted and the entity's own profile is missing a name, country, or city. For Peppol-routed countries, supplier.electronicAddress is never read from this object even if provided — see the Party schema's own field descriptions. On a self-billed invoice (countrySpecific.peppol.selfBilling: true), supplier identifies the real third-party seller instead — required (never auto-derived from the entity's own profile; omitting it with no resolvable supplierRef returns 422 MISSING_SELF_BILLING_SUPPLIER), its taxId is compared/derived against nothing (SUPPLIER_TAX_ID_MISMATCH does not apply — see customer below), and its electronicAddress IS read from this object (the real seller's own Peppol identity), unlike the ordinary-sale case. Optional |
| customer | object | Counterparty details. On the default transactionDirection: 'sale' this is the customer, and required. On transactionDirection: 'purchase' (Spain SII received book only) customer is the entity's OWN identity, not the vendor (the vendor is supplier) — optional, and when omitted it's auto-derived from the entity's master data the same way supplier is auto-derived on a sale, resolving the entity's registration for the document's own reporting country (not necessarily its home country). A supplied customer.taxId on a purchase must match that registration (422 CUSTOMER_TAX_ID_MISMATCH); omit it to have the registered value applied automatically. An incomplete entity profile (missing name/country/city) no longer rejects immediately when customer is omitted on a purchase or self-billed invoice — the request proceeds through mandate resolution, and is rejected only afterward (422 MISSING_CUSTOMER_NAME / MISSING_CUSTOMER_ADDRESS_CITY) if the resolved regime actually requires customer identity; a regime that doesn't (e.g. France's e-reporting) accepts it as submitted. On a transactionDirection: 'purchase' Spain SII received-book document, a missing or lapsed Spanish registration for this entity (as of the document date) holds the submission as NEEDS_INFO with errorCode MISSING_CUSTOMER_REGISTRATION (the purchase-direction counterpart of supplier's MISSING_SUPPLIER_REGISTRATION) rather than rejecting it — add or renew the ES registration, then resubmit with correctsInvoiceId set to the held invoice's id. A request that still carries the old buyer field name is rejected with 422 { "error": "Invoice validation failed", "details": [{ "field": "<path>", "code": "UNKNOWN_FIELD_BUYER_RENAMED", "message": "..." }] }, naming customer — there is no silent alias. A self-billed invoice (countrySpecific.peppol.selfBilling: true) shares this same purchase-direction shape even on the default transactionDirection: 'sale': customer is still the entity's OWN identity (the buyer being self-billed for), auto-derived and tax-ID-compared/derived exactly as described above for purchase, and its electronicAddress (BT-49) is backfilled from the entity's own confirmed Peppol Participant ID when omitted. Required |
| customerType | enum | Optional customer classification, business (B2B) vs. consumer (B2C), for the whole invoice. Additive: omit it entirely and nothing changes. When provided, it feeds a single WARNING-only cross-check (CUSTOMER_TYPE_TAX_ID_MISMATCH) against customer.taxId's presence/format — never blocks submission. Can be overridden per line via lines[].customerType. One of: B2B, B2C. Optional |
| lines | LineItem[] | Required |
| allowances | AllowanceCharge[] | Document-level allowances (discounts applied to the invoice total): BG-20. Optional |
| charges | AllowanceCharge[] | Document-level charges (surcharges applied to the invoice total): BG-21. Optional |
| shipping | Shipping | Optional |
| payment | Payment | Optional |
| clientTaxCode | string | RECOMMENDED. Your own ERP tax code (e.g. a SAP two-digit code), configured in advance via POST /tax/client-codes, applied for the WHOLE invoice — the header-level counterpart to lines[].clientTaxCode. Resolved onto every line that supplies neither its own taxRate/taxTreatment nor its own lines[].clientTaxCode; a line's own value always wins over this header one. Real ERPs typically assign one tax code per invoice/document rather than per line, so this field lets an integrator send that single code once instead of repeating it on every line. An unrecognised code for this entity does not reject the invoice — it is accepted and held (clearanceStatus: HELD_UNMAPPED_TAX_CODE) with a machine-readable reason, same as an unrecognised lines[].clientTaxCode. Optional |
| dryRun | boolean | Preview the resolved per-line tax decision without creating a record, generating XML, or enqueueing anything to an authority. The response echoes dryRun: true plus lines[] (see InvoiceResponse) showing exactly how each line would resolve — including a would-be HELD_UNMAPPED_TAX_CODE outcome — so an integrator can validate a client tax code / taxTreatment setup before really submitting. Never persists an einvoicing_records row. For a German invoice that resolves to the PEPPOL format, dryRun: true also runs the real enrichment, the German Peppol content rules (MISSING_DE_PEPPOL_*), the generated-document validation and the customer reachability check, and returns the same errors[] / warnings[] (or PEPPOL_CUSTOMER_UNREACHABLE) a real send would, plus the delivery block — still without storing a record or queueing anything. Optional |
| sandboxSimulateOutcome | enum | Sandbox only (csk_test_* keys) — ignored for a live key. Forces the submission through the same rejection-handling path a genuine authority rejection would take, using a country-representative rejection code so the shape (fieldPath, message, suggestedAction) matches what a real merchant would see: IT '00404' (customer.taxId not registered with SDI), PL 'NIP_MISMATCH' (seller NIP mismatch), RO 'INVALID_COUNTY_CODE' (missing ISO 3166-2:RO county code), HU 'INVALID_TAX_NUMBER' (customer tax number rejected by NAV), or 'SANDBOX_SIMULATED_REJECTION' for every other country (ES/PT/GR/AR/Peppol and any generate-only country, none of which reject synchronously in real life either). Lets an integration test its own rejection-handling code path without waiting for or provoking a real authority rejection. One of: REJECTED. Optional |
| prepaidAmount | number | Amount already paid (deposit, down-payment, advance invoice, BT-113). Without statedPayableAmount, payableAmount = total − prepaidAmount. Defaults to 0. Optional |
| statedPayableAmount | number | Optional: the amount due for payment your own system (ERP/POS) computed. It is authoritative: it is stored as the invoice's payable amount (BT-115) exactly as stated, and the difference from the total of the lines less prepaidAmount is stored as the rounding amount (BT-114), whatever its size. A difference of more than one minor unit of currency raises the warning ROUNDING_RESIDUAL_OVER_TOLERANCE and no longer returns a 422 or blocks the invoice. A format that cannot carry the stated figure consistently (EN 16931 BR-CO-16) holds the invoice at generation with 422 PAYABLE_AMOUNT_BR_CO_16 instead of changing it. Omit the field and the payable amount is the total less prepaidAmount. The v1 invoice view always carries totals.payableAmount; credit and debit notes use positive magnitudes. Optional |
| originalInvoiceRef | object | Required for documentType credit_note/debit_note when correctsInvoiceId is not used — reference to the original invoice by its own seller-assigned number. Optional |
| correctsInvoiceId | string | Clearvo's own id (the id returned by a prior /v1/send call) of the invoice this submission corrects — either a fiscal credit_note/debit_note reversing it, or a plain invoice resubmission re-attempting it. Must belong to the same entity and country. Prefer this over originalInvoiceRef when you have Clearvo's own id — it's an exact match rather than a best-effort invoice-number lookup. Optional |
| customerReference | string | Internal back-office reference (e.g. SAP BELNR). Stored but never sent to the authority. Optional |
| countrySpecific | object | Optional country-level extensions. Fields vary by country. peppol.selfBilling (boolean, default false) marks this as a self-billing document (customer issues on the seller's behalf), switching to a self-billing CustomizationID/ProfileID and UNTDID 1001 type codes (389 for invoices, 261 for credit notes) instead of the regular billing ones. AU and NZ use their own PINT-AUNZ self-billing profile; every Peppol country except SG and JP uses the generic EU BIS Self-Billing 3.0 profile. Silently ignored for SG and JP, whose self-billing document-type registration is not yet supported. Company-law disclosure facts (DE Handelsregister details and managing directors, FR Code de commerce Art. R123-237 capital/RCS city, IT Codice Civile Art. 2250 Registro Imprese/REA/capital/sole-shareholder notice, PT Código das Sociedades Comerciais Art. 171 registry office/capital, ES Código de Comercio Art. 16/19-21 Registro Mercantil tomo/folio/hoja/capital/liquidation notice) are entity-level facts, normally set once — legalForm via PATCH /entities/{id}'s entityFacts (see GET /entities/fact-definitions), the country-specific ones on the entity's registration extraFields — and rendered automatically (BT-30 legalRegistrationId, BT-33 additionalLegalInfo) on every invoice the entity issues, keyed on the entity's own established country rather than which country's clearance rules a given invoice itself resolves to. A value sent for the same field in the matching countrySpecific.<cc> block overrides the stored one for that invoice only (this includes de.legalForm; for IT, ES, PT and FR the legal form comes from entityFacts only). es.duaNumber (Spain SII block 3): NumeroDUA (Documento Único Administrativo) — required, and only meaningful, when a transactionDirection: 'purchase' line's tipoFactura resolves to F5 (import). Missing on an import produces NEEDS_INFO naming countrySpecific.es.duaNumber. Spain VeriFactu and SII (es): es.tipoFactura (explicit F1/F2/R1-R5 override; under VeriFactu an invoice with no buyer identification, an original document and a total up to EUR 400 is issued as F2 automatically, a credit note against an F2 as R5), es.claveRegimen (optional override, derived per line by default; must be valid for the line's own tax), es.customerNif, es.verifactuMode, es.calificacionOperacion (S1/S2/N1/N2), es.tipoRectificativa ('S'/'I'), es.facturasRectificadas, es.importeRectificacion, es.issuedByThirdParty, and the VeriFactu buyer and simplified-invoice fields: es.customerIdType ('passport', 'residence_document', 'residence_certificate', 'other' or 'not_registered' - what kind of document customer.taxId is when it is not a Spanish NIF or EU VAT number; send the buyer's country in customer.establishmentCountry; an unrecognised identifier without it holds the invoice as NEEDS_INFO with errorCode MANDATE_INCOMPLETE_DATA, and missingFields names customerIdType), es.noRecipientIdentification (boolean - your declaration that the invoice is lawfully issued without identifying the recipient, RD 1619/2012 art. 6.1.d; simplified invoices only, never inferred, AEAT 1185), and es.numRegistroAcuerdoFacturacion (billing agreement number, at most 15 characters). A simplified invoice above EUR 3,000 needs one of the last two or it is held as NEEDS_INFO (AEAT 1150). customer.name is optional on an F2/R5 invoice. Canary Islands: Clearvo registers your Canary Islands invoices with the AEAT VeriFactu system under the same Spanish tax number, reporting IGIC as Impuesto 03 in the same record chain as VAT. Set the es_tax_territory field (mainland, canary_islands or both) on your Spanish registration (PATCH /v1/tax/registrations/{id} extraFields; see GET /v1/tax/registrations/field-definitions) - an IGIC line without it returns VERIFACTU_TAX_TERRITORY_REQUIRED. Clearvo does not file your IGIC returns or the Canary SII with the Agencia Tributaria Canaria, and does not support IPSI (VERIFACTU_IPSI_UNSUPPORTED); sales between the Canary Islands and the mainland return VERIFACTU_CROSS_TERRITORY_UNSUPPORTED, and so does a credit note whose tax (IVA or IGIC) differs from the invoice it rectifies. An exempt line reports the exemption cause stated on its client tax code (E1 to E6; E1 to E8 for IGIC), defaulting to E1 on a mainland exempt line when none is stated; an IGIC exempt line with no stated cause is held. A credit note is sent with positive amounts and reported to AEAT with negative ones (rectificativa por diferencias). VeriFactu applies from 2027-01-01 for corporate-tax payers and 2027-07-01 for everyone else; Clearvo registers every Spanish invoice dated on or after 2027-01-01, and sandbox invoices must carry such a date (the sandbox never contacts the AEAT). Codes: VERIFACTU_CUSTOMER_ID_UNRESOLVED, VERIFACTU_CUSTOMER_NAME_MISSING, VERIFACTU_TAX_TERRITORY_REQUIRED, VERIFACTU_CROSS_TERRITORY_UNSUPPORTED, VERIFACTU_IPSI_UNSUPPORTED, VERIFACTU_DESGLOSE_UNMAPPED_DECISION, VERIFACTU_EXEMPTION_CODE_INVALID, VERIFACTU_CLAVE_REGIMEN_INVALID, VERIFACTU_DESGLOSE_TOO_MANY_LINES, VERIFACTU_NUM_SERIE_INVALID, VERIFACTU_TIPO_FACTURA_MISMATCH (422: countrySpecific.es.tipoFactura must be R1-R5 on a credit note and F1-F3 on an invoice), VERIFACTU_CURRENCY_UNSUPPORTED (422: a Spanish VeriFactu invoice must be in EUR; AEAT records amounts in euros with no currency field), 422 UNKNOWN_ES_CUSTOMER_ID_TYPE, INVALID_ES_NO_RECIPIENT_IDENTIFICATION, INVALID_ES_NUM_REGISTRO_ACUERDO_FACTURACION, and the mandate validation rules ES_VERIFACTU_S1_CUOTA, ES_VERIFACTU_S2_NOT_SIMPLIFIED, ES_VERIFACTU_CLAVE_01_NO_E2_E3, ES_VERIFACTU_ART61D_ONLY_SIMPLIFIED, ES_VERIFACTU_IDOTRO_CODIGO_PAIS, ES_VERIFACTU_IVA_RATE_SET and the warning ES_VERIFACTU_IGIC_RATE_REFERENCE (an IGIC rate outside the usual set; the invoice is still sent as provided). de.invoiceFormat ('ZUGFERD', 'XRECHNUNG' or 'PEPPOL', highest-precedence override — see the top-level documentFormat/formatResolvedFrom response fields and PATCH /customers/{id}'s own countrySpecific.de.invoiceFormat for the per-customer default) and de.leitwegId (BT-10 — XRECHNUNG only, falls back to the request's own top-level buyerReference, then to the LEITWEG_ID reference stored on the customer) let a single POST /send choose Germany's invoice format explicitly. 'PEPPOL' sends the invoice to the customer over the Peppol network as a Peppol BIS Billing 3.0 invoice (documentFormat UBL_PEPPOL_BIS): it needs the entity's confirmed Peppol Participant ID (422 MISSING_SELLER_PEPPOL_ID otherwise) and an explicit Peppol ID for the customer (customer.electronicAddress with schemeId + value, or the stored customer's human-confirmed PEPPOL_PARTICIPANT_ID reference) — a German customer's Peppol ID is never derived from a VAT number. For a German XRECHNUNG or PEPPOL document the customer's electronic address (BT-49) is the first available of: the explicit customer.electronicAddress (value + schemeId), the stored confirmed Peppol participant ID, the Leitweg-ID (scheme 0204; it must pass the Leitweg-ID check-digit validation, so a free-text buyerReference or purchase-order number is ignored), the customer's contact email (scheme EM), the customer's German VAT ID (scheme 9930, DE plus 9 digits). The supplier's electronic address (BT-34) is the first of: the entity's confirmed Peppol participant ID, its contact email (EM), its German VAT ID (9930). When none exists the send is blocked before any XML is generated with ERROR MISSING_CUSTOMER_ELECTRONIC_ADDRESS or MISSING_SUPPLIER_ELECTRONIC_ADDRESS. A customer that cannot be reached returns 422 PEPPOL_CUSTOMER_UNREACHABLE (see PeppolCustomerUnreachableResponse), never a silent fallback to another format. Credit and debit notes cannot be sent over Peppol for Germany yet (422 CREDIT_NOTE_PEPPOL_UNSUPPORTED), and neither can a self-billed document (peppol.selfBilling): requesting PEPPOL on one is a 400 DE_SELF_BILLED_PEPPOL_NOT_SUPPORTED, and a stored customer/entity default of PEPPOL on a self-billed document is a 422 DE_SELF_BILLED_FORMAT_CHOICE_REQUIRED (pick ZUGFERD or XRECHNUNG). Use dryRun: true to check all of this without storing anything. ar.condicionIVAReceptorId (ARCA's real FEParamGetCondicionIvaReceptor code, RG (ARCA) 5616/2024 — see the Customer schema's own countrySpecific.ar.condicionIVAReceptorId for the full code list; default 5, Consumidor Final) and ar.cbteTipo (override for the computed comprobante type, normally derived from condicionIVAReceptorId) — a foreign-customer condicionIVAReceptorId (8 Proveedor del Exterior / 9 Cliente del Exterior) with no explicit ar.cbteTipo override is a 422 AR_FOREIGN_CUSTOMER_UNSUPPORTED naming countrySpecific.ar.condicionIVAReceptorId (Factura E, comprobante 19, isn't generated automatically yet). it.esigibilitaIva ('I' default / 'D' / 'S' — DatiRiepilogo/EsigibilitaIVA), it.withholding (boolean) + it.withholdingDetails ({ type: 'RT01'..'RT06', rate, amount, paymentReason }, required once withholding is true or a 422 IT_WITHHOLDING_DETAILS_MISSING; a supplied-but-malformed type/rate/amount/paymentReason is a 422 IT_WITHHOLDING_DETAILS_INVALID naming the specific offending sub-field), it.stampDuty (boolean, emits DatiBollo), it.cigCode/it.cupCode (DatiOrdineAcquisto CIG/CUP, require the request's own orderReference or a 422 IT_CIG_CUP_MISSING_ORDER_REFERENCE). hu.invoiceCategory ('NORMAL' — the only supported value today) and hu.cashAccountingIndicator (boolean, pénzforgalmi cash-basis VAT flag). pl.gtuCodes (invoice-level GTU fallback — prefer lines[].gtuCode), pl.cashAccountingIndicator (boolean, Adnotacje P_16 metoda kasowa), pl.exemptionLegalBasisType ('national_act' | 'eu_directive' | 'other', required whenever any line is exempt or a 422 PL_EXEMPTION_LEGAL_BASIS_MISSING). pt.stampDutyAmount (Imposto do Selo, caller-supplied, emits AT QR field M and folds into field N, and into the monthly SAF-T file's TaxPayable/GrossTotal too). ro.supplierTaxRegistered/ro.customerTaxRegistered (boolean; whether that party genuinely holds an active VAT registration (a CUI, "RO" prefix) rather than a bare fiscal identifier (CIF) — omit to default to whether the party's taxId carried the "RO" prefix; an unresolved supplier is a 422 RO_SUPPLIER_TAX_REGISTRATION_STATUS_UNKNOWN, an unresolved B2B (or untyped) customer a 422 RO_CUSTOMER_TAX_REGISTRATION_STATUS_UNKNOWN, and a customerType: 'B2C' customer defaults to unregistered). ro.customerSector/ro.supplierSector ('SECTOR1'..'SECTOR6', required whenever the corresponding party's address.countyCode resolves to 'RO-B' Bucharest, or a 422 RO_BUCHAREST_SECTOR_REQUIRED); a Romanian documentType: 'debit_note' with no originalInvoiceRef is a 422 RO_DEBIT_NOTE_MISSING_ORIGINAL_REF. A Jordanian documentType: 'credit_note' with no originalInvoiceRef.invoiceNumber is a 422 MISSING_JO_CREDIT_NOTE_REFERENCE. Malaysia requires supplier.taxId (422 MY_SUPPLIER_TIN_REQUIRED if absent) and, for a B2B customer.taxId (422 MY_CUSTOMER_TIN_REQUIRED if absent and not self-billing/B2C) — see MyInvois's general-TIN placeholder codes for the B2C/self-billed exceptions. An Egyptian line whose taxCategory can't resolve to a known ETA VAT subtype is a 422 EG_TAX_SUBTYPE_UNRESOLVED naming lines[].taxCategory. Greece additionally holds when a line's optional lineType ('product', 'service', 'digital_service', 'transport' or 'other') is explicitly set and genuinely disagrees with the tax code's own resolved goods/service classification (422 GR_LINE_TYPE_SUPPLY_TYPE_MISMATCH naming lines[{i}].lineType — an OMITTED lineType never triggers this, only one you explicitly set and that conflicts), when a mixed-kind invoice has no single header-level invoiceType to describe it (422 GR_MIXED_LINE_TYPE), or when an exempt/zero-rated/reverse-charge line has no resolvable vatExemptionCategory (422 GR_EXEMPTION_CATEGORY_MISSING naming lines[{i}].taxCategory, with a /tax-codes fixUrl). Across every EN16931-shaped country generator (IT/PL/RO/GR/Peppol), an internally inconsistent (tax category, rate) pair on a line or VAT-breakdown entry — never reachable via the documented /v1/send request/response fields alone, since resolveInvoiceTaxCodes already holds this upstream — is the shared defense-in-depth 422 TAX_LINE_INCONSISTENT. Optional |
| notifyCustomer | boolean | Only meaningful for countries where no authority network delivers the invoice to the customer (DE always; ES only when this entity's Spanish invoices report under VeriFactu rather than SII — SII is a background report to AEAT decoupled from customer delivery, so this is silently ignored while SII is the active regime; IT only when the customer has no Italian SDI routing code; PL only when the customer has no Polish NIP — KSeF is pull-only and pull access requires the customer's own registered NIP). When the customer's email is set via customer.contact.email, Clearvo emails them a link to a hosted page to view/download the invoice. Omit to defer to the entity's own default (see PATCH /v1/entities/{id} notifyCustomerByDefault); true/false here overrides that default for this invoice only. Silently ignored (see customerNotification in the response) for countries Clearvo already delivers electronically (Peppol, IT B2B/B2G, PL when the customer has a NIP, RO, HU, GR, AR, FR — France delivers through an accredited third-party platform), or that are a pure background report to the tax authority with no customer-delivery role of their own (PT, and ES while its SII regime is active). Optional |
| rejectInsteadOfAutoCorrect | boolean | Per-request opt-out from silent auto-correction. Defaults to false — an ADJUSTMENT rule match (see GET /v1/validations for the live catalogue of autoCorrectable checks) is silently applied and reported in the response's adjustments[]. Set to true and a would-be correction is never applied — it surfaces instead as a blocking entry in the 422 response's errors[], so an integrator who wants to see and fix raw values themselves (rather than have Clearvo silently normalize them) can require that. Optional |
| ossDeclared | boolean | Explicit declaration that this transaction is (true) or is not (false) reported through the seller's OSS (One Stop Shop) return — an input to Compliance Mandate resolution, not a tax treatment. Omit it and the platform derives OSS-ness itself: an active OSS registration (Union or non-Union scheme) whose window covers the transaction's tax point date, combined with a qualifying intra-EU B2C distance sale (a client tax code that resolves to a distance-sale scheme also counts as an explicit signal). Supply it and the explicit value always wins over derivation. A non-boolean value returns 422 INVALID_OSS_DECLARED. Optional |
| transactionDirection | enum | Spain SII block 3 (received book / LFR). 'sale' (default) — this entity's own outbound/issued document. 'purchase' — a vendor's document the entity is recording on its own received side — Spain SII (received book) and France e-reporting (a purchase from a vendor not established in France is declared by you as the receiving party, at invoice level, in its own Received batch) only; every other live country's purchase-direction submission currently resolves to no reporting mandate at all (mandate: NONE). supplier is still the VENDOR/counterparty on a purchase (required — the entity's own Spanish registration for customer/Titular purposes is applied automatically, same derivation as the sale-side supplier.taxId rule). One of: sale, purchase. Optional |
| shipFrom | object | France e-reporting, own-goods stock transfers only (a client tax code with movement own_goods_movement). Where the goods leave: for an outbound transfer (sale) the French origin; for an inbound transfer (purchase) the origin member state. Used to find your own VAT registration in the other member state. Optional and ignored for every other transaction; omitting it never parks a row. Optional |
| shipTo | object | France e-reporting, own-goods stock transfers only. Where the goods arrive. Needed only for an outbound transfer (shipFrom in France) to name the destination member state; ignored otherwise. Optional |
| accountingDate | string | PURCHASE documents only (transactionDirection='purchase'), Spain SII. The accounting-entry date (FechaRegContable, art. 69 bis.1.b) RIVA) — anchors both the Compliance Mandate effective-date gate and the received-book (LFR) submission deadline. Optional even for a purchase (falls back to taxPointDate ?? issueDate when omitted) — but the vendor's own issueDate is legally the wrong date for this gate, so a caller that books on receipt should always supply it. Optional |
| deductibleTaxAmount | number | CuotaDeducible — PURCHASE documents only, Spain SII. The deductible portion of input VAT on this purchase, always taken as given and never derived from the lines' own charged amounts (prorrata and non-deductible purchases exist; the platform must not invent this figure). An explicit 0 is a valid, distinct declaration (an exempt/non-deductible purchase) — NOT the same as omitting the field, which instead produces NEEDS_INFO naming this field. Optional |
| deductionPeriod | object | Received book only, Spain SII. The VAT declaration period this deduction is actually taken in, when it differs from accountingDate's own month (AEAT FAQ 4.9 Example 2: one invoice, two valid deadlines depending on the period the deduction is claimed in). Optional — omitted, the liquidation period defaults to accountingDate's own month. Optional |
Party object
Used for both supplier and customer.
| Field | Type | Description |
|---|---|---|
| name | string | Required |
| taxId | string | Tax/VAT identifier. On supplier it is OPTIONAL: omit it and the platform applies the entity's own current tax registration for the resolved mandate's country (an entity can hold registrations in several countries — the right one is derived per invoice from the mandate that actually resolves, never assumed from the entity's home country). If you do supply it, it must equal that registered number (a leading country prefix is stripped before comparing, e.g. ESB72756737 and B72756737 are the same NIF) or the request is refused with 422 SUPPLIER_TAX_ID_MISMATCH — the registered value is never silently substituted for a different asserted one. On customer it is strongly recommended for B2B (reverse-charge treatment, SII counterparty identification). Optional |
| address | Address | Required |
| establishmentCountry | string | ISO 3166-1 alpha-2 country of the tax registration that issued taxId. Optional — derived from the taxId prefix when omitted. Spain VeriFactu: required together with a passport, residence or other identifier (countrySpecific.es.customerIdType). Optional |
| electronicAddress | object | Peppol electronic address (BT-34 seller, BT-49 buyer): send value and schemeId together. Meaningful on customer only (required when auto-derivation is not supported for the customer's country) — ignored on supplier, which always uses the entity's own confirmed Peppol Participant ID (set once under the dashboard's Settings → Account → Peppol Network Identity section) rather than a per-request value, so a caller can never claim a different sender identity than the one the entity has confirmed. Returns 422 MISSING_SELLER_PEPPOL_ID if the entity has none confirmed. Optional |
| contact | object | Optional |
| customerRef | string | Customer only (ignored on supplier). Your own reference for a previously-saved customer record — when provided, Clearvo looks it up and fills in any of name/taxId/address you omit from this customer object. If the stored customer has a human-confirmed PEPPOL_PARTICIPANT_ID reference, it also fills in customer.electronicAddress, and a stored LEITWEG_ID reference fills in countrySpecific.de.leitwegId; each fills in only when the request supplies neither the explicit value (the electronicAddress pair; countrySpecific.de.leitwegId or a non-empty buyerReference), and an explicit value always wins. See GET /v1/customer-reference-types. For an Italy (IT) invoice, it also fills in countrySpecific.it.codiceDestinatario/pecDestinatario from the stored customer when present. Fields you do supply directly always take precedence over the stored ones. Manage customers via GET/POST /v1/customers and GET/PATCH/DELETE /v1/customers/{id}, or from the dashboard's Customers page — every successfully-issued invoice also auto-captures/refreshes a customer record from its customer details, whether or not customerRef was supplied. Optional |
| supplierRef | string | Supplier only (ignored on customer). Your own reference for a previously-saved supplier record — when provided, Clearvo looks it up and fills in any of name/taxId/address you omit from this supplier object. Fields you do supply directly always take precedence over the stored ones. Primarily used on a self-billed invoice (countrySpecific.peppol.selfBilling), where supplier identifies the real third-party seller rather than the entity itself. Manage suppliers via GET/POST /v1/suppliers and GET/PATCH/DELETE /v1/suppliers/{id}, or PUT /v1/suppliers/by-ref/{ref}. Optional |
| legalRegistrationId | string | Legal registration ID, e.g. a Companies House number or SIRET (BT-30). Optional |
| identifiers | object[] | Additional party identifiers — BT-29 (seller) / BT-46 (buyer) — distinct from legalRegistrationId and taxId. For Saudi Arabia (ZATCA) the scheme is one of CRN, MOM, MLS, 700, SAG, NAT, GCC, IQA, PAS, OTH. Optional |
{
"name": "Acme SRL",
"taxId": "01234567890",
"establishmentCountry": "IT",
"address": {
"street": "Via Roma 1",
"city": "Milano",
"postalCode": "20121",
"country": "IT"
}
}
Line items
Each entry in the lines array describes one invoiced item. Amounts are net (excluding tax). Every line carries its own taxRate as a percentage; when taxAmount is omitted Clearvo derives it as round(lineTotal × taxRate / 100). The EN16931 tax category is resolved from your clientTaxCode or taxTreatment together with the rate — a line never carries a taxCode field (one is rejected with 400 UNSUPPORTED_FIELD), and the retired vatRate/vatAmount names are rejected with 422 UNKNOWN_FIELD_VAT_RENAMED.
| Field | Type | Description |
|---|---|---|
| description | string | Required |
| quantity | number | Required |
| unitPrice | number | Unit price excluding tax (net). When taxIncluded is true it is the gross price and the net is back-computed as unitPrice / (1 + taxRate / 100). Required |
| taxRate | number | Tax rate as a percentage (e.g. 22 for 22%, 0 for a reverse-charge line). Required on EVERY line — even one whose treatment resolves from clientTaxCode still carries its own observed rate; it is never computed for you (a missing rate, or one outside 0–100, is a 400 payload error naming lines[i].taxRate). A POSITIVE rate with no clientTaxCode/taxTreatment is reported as a domestic taxable supply at that rate — your rate is authoritative and is never rejected as an unrecognised rate. A 0% line with no clientTaxCode/taxTreatment is rejected (400 ZERO_RATE_NEEDS_TAX_TREATMENT) — a bare 0% rate alone does not state why it is zero, so supply taxTreatment (exempt / zero_rated / reverse_charge / out_of_scope, or the relevant cross-border movement via a client tax code); the platform never guesses. The retired vatRate name is rejected with 422 UNKNOWN_FIELD_VAT_RENAMED naming taxRate — there is no alias. A line taxCode is never accepted (400 UNSUPPORTED_FIELD): the EN16931 category is always a resolved OUTPUT — see taxResolution on the response. Required |
| taxAmount | number | Tax amount for this line in the invoice currency. Optional — when omitted it is computed as round(lineTotal × taxRate / 100); supply it explicitly to control rounding precisely. The retired vatAmount name is rejected with 422 UNKNOWN_FIELD_VAT_RENAMED naming taxAmount. Optional |
| clientTaxCode | string | RECOMMENDED. Your own ERP tax code (e.g. a SAP two-digit code), configured in advance via POST /tax/client-codes — lets you send the code your own system already knows rather than reasoning about tax categories at all. Mutually exclusive with taxTreatment — set at most one of the two on a single line (a line with neither is resolved from its stated facts — taxRate plus any taxTreatment — mapped as given, never inferred from the customer/seller country pair). An unrecognised code for THIS entity is never rejected outright: the invoice is accepted and the record is held (clearanceStatus: HELD_UNMAPPED_TAX_CODE) with a machine-readable reason and a deep link to configure the code — see the ClearanceStatus and UnmappedTaxCodeReason schemas — since an unconfigured code is a setup gap, not a malformed request. Optional |
| taxTreatment | object | The AUTHORITATIVE tax treatment for this line, used only when clientTaxCode is omitted. The stated treatment (exempt / out_of_scope / zero_rated / reverse_charge) is mapped as-is — the platform does not infer or override the movement from the customer/seller countries. Required whenever this line's taxRate is 0: a 0% line with no clientTaxCode/taxTreatment is rejected (400 ZERO_RATE_NEEDS_TAX_TREATMENT) rather than guessed. Mutually exclusive with clientTaxCode. An unrecognized value is a 400 naming this field. Optional |
| customerType | enum | Per-line override of the invoice-level customerType — business vs. consumer — consulted only when this line has no clientTaxCode. Defaults to the invoice-level customerType, then to whether customer.taxId is present. One of: B2B, B2C. Optional |
| supplyType | enum | Supply type consulted only when this line has no clientTaxCode — affects reverse-charge/place-of-supply treatment for cross-border B2B services. One of: goods, digital_service, general_service. Optional |
| discountPercent | number | Discount on this line as a percentage (0–100). Mutually exclusive with discountAmount — supplying both is a 422 LINE_DISCOUNT_CONFLICT. Optional |
| discountAmount | number | Discount on this line as a fixed amount in the invoice currency (>= 0). Mutually exclusive with discountPercent. Optional |
| unitOfMeasure | string | UN/ECE Recommendation 20 unit code: EA (each), HUR (hour), DAY, KGM (kilogram), MTR (metre), C62 (unit). Optional |
| lineNumber | integer | 1-based line position. Auto-assigned sequentially when omitted; must be a positive integer when supplied. Optional |
| sellerItemId | string | Your own product/item identifier for this line (EN16931 BT-155). Optional |
| gtuCode | enum | Poland (PL) FA(3)/KSeF only — this line's GTU goods/service classification. At most one code per line (the FA(3) schema's GTU element is single-valued). countrySpecific.pl.gtuCodes (invoice-level) is a fallback ONLY when it carries exactly one code and no line sets its own gtuCode; several invoice-level codes with no line assignment is a 422 PL_GTU_LINE_ASSIGNMENT_REQUIRED. One of: GTU_01, GTU_02, GTU_03, GTU_04, GTU_05, GTU_06, GTU_07, GTU_08, GTU_09, GTU_10, GTU_11, GTU_12, GTU_13. Optional |
| lineType | enum | Type of line item — used for tax treatment in some jurisdictions (e.g. digital services; Greece checks it against the resolved goods/service classification). One of: product, service, digital_service, transport, other. Optional |
| taxIncluded | boolean | Per-line override for tax-inclusive pricing. When true, unitPrice is gross and taxRate must be set; the net price is back-computed as unitPrice / (1 + taxRate / 100). Inherits the invoice-level taxIncluded when omitted. Optional |
| gtin | string | GTIN barcode (BT-157). Optional |
| itemClassificationCode | string | Product classification code, e.g. UNSPSC or CPV (BT-158). Poland also accepts PKWiU or CN. Requires itemClassificationScheme. Optional |
| itemClassificationScheme | string | Classification scheme, e.g. UNSPSC, CPV or STI (GTIN). Required with itemClassificationCode. Optional |
| orderLineReference | string | Purchase-order line reference (BT-132). Optional |
| period | object | Billing/service period for this line (BT-134/135). Optional |
| note | string | Line-level note (BT-127). Optional |
| metadata | object | Per-line metadata — stored internally, never sent to the authority. Optional |
| allowances | AllowanceCharge[] | Line-level allowances (further discounts applied to the line total). Optional |
| charges | AllowanceCharge[] | Line-level charges (surcharges applied to the line total). Optional |
| sourceSystem | string | Which connector/ERP the line's clientTaxCode was read from (e.g. sap). Diagnostic only: echoed as source_system in a HELD_UNMAPPED_TAX_CODE reason; never changes which code resolves. Optional |
| sourceSystemCode | object | A connector's own raw tax-code value (e.g. Xero's TaxType OUTPUT2), resolved through the connector's system vocabulary. Mutually exclusive with clientTaxCode and taxTreatment. Optional |
| clientTaxCodeSource | enum | Who chose this line's clientTaxCode. Omitted (read as caller) for any code you typed; 'default' is set only by the platform's own bulk CSV pipeline when a blank tax_code was replaced with a default. Diagnostic only. One of: caller, default. Optional |
Tax codes
Tax codes follow the EN16931 tax category framework. They are an output: Clearvo resolves each line's category from your clientTaxCode or taxTreatment plus its taxRate, writes the correct authority-specific code into the generated XML, and reports the decision back in each line's taxResolution.category. You never send a code directly — state the legal reason for a 0% rate through taxTreatment (or a mapped client tax code), not just the rate percentage.
| Code | Category | Rates (by country) |
|---|---|---|
| S | Standard rate | IT 22% · PL 23% · DE 19% · FR 20% · ES 21% |
| AA | Reduced rate | IT 10% · PL 8% · DE 7% |
| AB | Second reduced rate | IT 5% · PL 5% |
| AC | Super-reduced rate | IT 4% (essential goods) |
| AE | Reverse charge | Cross-border B2B services under Art. 196 VAT Directive. Customer accounts for VAT. |
| K | Intra-EU zero rate | Goods dispatched to VAT-registered customer in another EU member state (Art. 138). |
| G | Export / zero rate | Goods or services exported outside the EU. |
| E | Exempt | Legally exempt from VAT. Include exemptionReason in line item where required by country. |
| O | Out of scope | Outside the scope of VAT entirely (e.g. statutory transfers). |
| Z | Zero rated (domestic) | Domestic zero-rated supplies (distinct from intra-EU zero rate). |
AE (reverse charge) requires both parties to have a valid taxId. Clearvo validates this and returns HTTP 422 if the customer taxId is missing on cross-border reverse-charge invoices.Payment object
Optional payment details embedded in the invoice. Included in the generated XML where the authority format supports it (FatturaPA, UBL, XRechnung).
| Field | Type | Description |
|---|---|---|
| means[] | array | Payment instructions (BG-16), one entry per way of paying. Each entry takes method (bank_transfer | direct_debit | credit_card | cash | check | other), iban (IBAN of the payee account, no spaces), bic (BIC/SWIFT code; forbidden on a German XRechnung invoice), reference (payment reference, BT-83) and, for SEPA direct debit, mandateReference (BT-89, max 35 characters), creditorId (BT-90) and debitedIban (BT-91). Optional |
| terms.text | string | Free-text payment terms, for example "Net 30" (BT-20). Optional |
| terms.earlyPayment | object | Early-payment discount: days, percent and an optional baseAmount (defaults to the tax-exclusive amount). Optional |
| installments[] | array | Installment schedule: dueDate, amount and an optional description per installment. Optional |
The earlier flat shape is refused with 422 UNKNOWN_FIELD_RENAMED, naming the replacement: payment.iban is now payment.means[].iban (likewise method, bic, reference, mandateReference, creditorId, debitedIban), a string payment.terms is now payment.terms.text, payment.skonto.days|percentOff|baseAmount is now payment.terms.earlyPayment.days|percent|baseAmount, and payment.dueDate is removed (use the top-level dueDate).
The optional top-level statedPayableAmount is the amount due your own system computed. It is stored exactly as stated; any difference from the lines total less prepaidAmount is recorded as the rounding amount (BT-114). A difference of more than one minor unit raises the warning ROUNDING_RESIDUAL_OVER_TOLERANCE and does not block the invoice. If the target format cannot carry the stated figure consistently (EN 16931 BR-CO-16) the invoice is held with PAYABLE_AMOUNT_BR_CO_16.
Country-specific fields
Some countries require additional fields that have no EN16931 equivalent. These are passed as a countryData object alongside the standard payload.
Italy
| Field | Type | Description |
|---|---|---|
| countryData.it.codiceFiscale | string | Customer's Italian fiscal code (for individuals). Optional |
| countryData.it.codiceDestinatario | string | SDI recipient code (7-char). Provide if known; Clearvo looks it up via SMP if omitted. Optional |
| countryData.it.pecDestinatario | string | Customer PEC email address (fallback if no codice). Optional |
Germany
| Field | Type | Description |
|---|---|---|
| countrySpecific.de.invoiceFormat | string | ZUGFERD, XRECHNUNG or PEPPOL. Overrides the per-customer and per-entity defaults (the platform default is ZUGFERD). PEPPOL sends the invoice over the Peppol network as a Peppol BIS Billing 3.0 invoice and needs a confirmed Peppol ID for your entity and an explicit Peppol ID for the customer. Optional |
| countrySpecific.de.leitwegId | string | Leitweg-ID (required for all public-sector B2G invoices; XRECHNUNG only, falls back to the request's own top-level buyerReference, then to the Leitweg-ID stored on the customer, if omitted). Corresponds to EN16931 BT-10 "Buyer reference" — the standard's own name, deliberately not renamed. Optional for B2B |
Poland
Poland requires a per-entity KSeF API token registered once via POST https://api.clearvo.io/v1/pl/credentials (or the setup page). See the Poland guide for full details.
| Field | Type | Description |
|---|---|---|
| countrySpecific.pl.sellerNip | string | Override supplier NIP (10 digits). Auto-derived from supplier.taxId when prefixed with PL. Optional |
| countrySpecific.pl.customerNip | string | Override customer NIP (10 digits). Auto-derived from customer.taxId. Optional |
| countrySpecific.pl.splitPayment | boolean | Enable MPP (Mechanizm Podzielonej Płatności). Required for Annex 15 transactions > PLN 15,000. Optional |
| countrySpecific.pl.gtuCodes | string[] | GTU_01–GTU_13 classification codes for Annex 15 goods/services. E.g. ["GTU_12"]. Optional |
| countrySpecific.pl.rodzajFaktury | string | FA(3) document type: VAT (invoice) or KOR (correction). Auto-derived from documentType. Optional |
Clearance errors
These are not HTTP errors — the initial POST /send returns 200, but a subsequent status poll may reveal that the authority rejected the invoice. Check clearanceStatus === "REJECTED" and inspect the error block (code, message, retryable, upstreamCode, upstreamMessage) and the top-level errorCode / suggestedAction / isMerchantResolvable / fixUrl fields. For the generic HTTP status codes and the error object shape shared across every Clearvo product, see Errors & status codes.
Common authority rejection reasons by country:
Italy (SDI)
- 00001 — Invalid file structure (XML schema violation).
- 00002 — Duplicate invoice number from the same sender.
- 00102 — Supplier Partita IVA not found in Revenue Agency registry.
- 00201 — Customer Codice Destinatario or PEC not found or inactive.
Poland (KSeF)
- InvalidNip — NIP number checksum invalid.
- DuplicateInvoice — Invoice FA number already submitted in this session.
- SchemaValidationError — FA(3) schema violation; check
error.detailfor XPath.
Germany (XRechnung, ZUGFeRD, Peppol)
Germany has no central clearance authority for B2B. XRechnung and ZUGFeRD invoices are accepted immediately on valid XML. A Peppol send stays PENDING until the recipient's Access Point confirms, then moves to DELIVERED; a rejection from that Access Point appears as REJECTED with error.source: "PEPPOL_AP".
Italy — SDI lifecycle
Italy's Sistema di Interscambio (SDI) is an asynchronous clearance system. Invoices are accepted or rejected typically within minutes, but the SDI can take up to 5 days for a final decision in exceptional cases.
Status lifecycle
UNDELIVERED and mcDeadline
The UNDELIVERED status means the SDI successfully received your invoice but could not deliver it to the customer's inbox (invalid Codice Destinatario, full mailbox, etc.). The SDI continues retrying for 10 days. This window is exposed as mcDeadline in the status response.
After the 10-day window expires:
- If the customer eventually received it — the invoice is legally valid.
- If it was truly undeliverable — the invoice is still legally valid under Italian law (D.Lgs. 127/2015), but you should notify the customer by other means and keep proof of the SDI notification.
UNDELIVERED invoice unless you are certain the original was never received. Duplicate invoice numbers are rejected by the SDI.Polling cadence
Poll every 5 minutes while PENDING. Clearvo returns a nextPollAfter timestamp — always honour this rather than hardcoding intervals. Polling more frequently will not speed up SDI processing and may trigger rate limiting.
Poland — KSeF
KSeF (Krajowy System e-Faktur) is Poland's national e-invoicing platform, operated by the Ministerstwo Finansów. Mandatory for large taxpayers (>PLN 200M revenue) from 1 February 2026; all other Polish VAT registrants from 1 April 2026. Format: FA(3) XML, schema namespace http://crd.gov.pl/wzor/2025/06/25/13775/.
Step 1 — Register your KSeF token (one-time setup)
KSeF requires a per-entity API token that you generate in the KSeF Taxpayer Portal. Clearvo submits invoices and polls your inbox under your company NIP using this token.
Log into ksef.mf.gov.pl → Zarządzanie tokenami → Wygeneruj token. Enable both Wysyłka faktur (sending) and Dostęp do faktur (inbox access) permissions. Copy the token — it is shown only once.
Use the setup page or the API:
POST https://api.clearvo.io/v1/pl/credentials
x-api-key: csk_live_••••••••
Content-Type: application/json
{
"nip": "1234567890",
"token": "<token from ksef.mf.gov.pl>",
"environment": "production"
}
Step 2 — Submit an invoice
Use the standard POST https://api.clearvo.io/v1/send endpoint. Set customerCountry: "PL" and include NIP numbers in supplier.taxId / customer.taxId with the PL prefix (e.g. PL1234567890).
supplier.taxId must match the NIP in your registered credentials. A mismatch returns 422 NIP_MISMATCH before any KSeF call is made.Step 3 — Poll for KSeF number
KSeF processes invoices asynchronously — typically within 5–30 seconds. Poll GET https://api.clearvo.io/v1/status?country=PL&id=<submissionId> until terminal: true. On acceptance:
{
"clearanceStatus": "ACCEPTED",
"terminal": true,
"ksefNumber": "7010830304-20260619-7269D0000000-DF",
"upoAvailable": true,
"clearedAt": "2026-06-19T10:23:45.000Z"
}
The KSeF number (ksefNumber) must appear on the invoice PDF — your customer needs it to claim input VAT deduction. Store it permanently against the invoice record.
UPO — official Ministry receipt
After acceptance, Clearvo automatically fetches the UPO (Urzędowe Poświadczenie Odbioru) — the Ministry of Finance-signed XML receipt. upoAvailable: true in the status response confirms it has been stored. The UPO must be retained for 10 years per Polish VAT law.
Status lifecycle
Inbound — receiving invoices
KSeF maintains a customer inbox per NIP, but KSeF itself has no push mechanism — an invoice a supplier issues to your NIP only becomes visible to Clearvo once POST /pl/inbound/poll is called. There is no automatic background schedule today, so call it on whatever cadence fits your integration (e.g. a cron job every few minutes, or on-demand before you need the latest invoices). Each poll fires an invoice.received webhook for every newly received invoice. Each inbound invoice also includes a White List check (Biała Lista) on the supplier's registered bank accounts — the result appears in invoiceData.whiteList. Paying to an account not on the White List risks losing input VAT deduction rights (Art. 108a uVAT).
The token registered via set_pl_credentials / POST /pl/credentials must carry the dostęp do faktur (invoice access) permission to read the inbox — a token generated with only wysyłka faktur (send) will fail. If your suppliers already send through Clearvo under their own NIP, that is a separate token from the one your own NIP needs to receive.
Poll the inbox:
POST https://api.clearvo.io/v1/pl/inbound/poll
x-api-key: csk_live_••••••••
Then list what you've received, separately from anything you've submitted:
GET https://api.clearvo.io/v1/invoices?direction=inbound&country=PL
x-api-key: csk_live_••••••••
There is no MCP tool for Polish inbox polling. Trigger the poll with the HTTP endpoint above, then read the received invoices with GET /invoices?direction=inbound&country=PL.
Correction invoices
Use documentType: "credit_note" with an originalInvoiceRef block. Clearvo sets RodzajFaktury: KOR automatically.
{
"documentType": "credit_note",
"invoiceNumber": "FV-KOR/2026/06/00001",
"issueDate": "2026-06-20",
"originalInvoiceRef": {
"invoiceNumber": "FV/2026/06/00001",
"issueDate": "2026-06-19",
"reason": "Incorrect unit price"
}
}
422 immediately. A NIP that doesn't match your registered credentials returns 422 NIP_MISMATCH.Germany — XRechnung, ZUGFeRD and Peppol
Germany currently has no central B2B invoice clearance authority. Clearvo generates a valid XRechnung 3.0 document or a ZUGFeRD 2.3 hybrid PDF, or sends a Peppol BIS Billing 3.0 invoice over the Peppol network, depending on the format you choose. XRechnung and ZUGFeRD return ACCEPTED immediately on successful validation.
No asynchronous clearance
Unlike Italy or Poland, German B2B invoices do not go through a tax authority clearance step. For XRechnung and ZUGFeRD, Clearvo validates your payload against the XRechnung 3.0 Schematron rules, generates the document, and marks the invoice ACCEPTED as soon as it passes validation. The terminal flag is true on the initial response — no polling required. A Peppol send is the exception: it returns PENDING and moves to DELIVERED once the receiving Access Point confirms.
Choosing the format
The format is resolved most-specific-wins: countrySpecific.de.invoiceFormat on the request, then the customer's stored default, then the entity's defaultDeInvoiceFormat (set with PATCH /entities/{id}), then the platform default ZUGFERD. Each accepts ZUGFERD, XRECHNUNG or PEPPOL. The response reports the result in documentFormat (CII_ZUGFERD, UBL_XRECHNUNG or UBL_PEPPOL_BIS) and where it came from in formatResolvedFrom.
BuyerReference (Leitweg-ID)
For public sector (B2G) invoices, the Leitweg-ID is mandatory — send it as countrySpecific.de.leitwegId (XRECHNUNG only), or the request's own top-level buyerReference, which countrySpecific.de.leitwegId falls back to when omitted. If the request supplies neither, the LEITWEG_ID reference stored on the customer is used (see Customer references). The Leitweg-ID is assigned by the contracting authority and identifies the recipient routing within German public administration (EN16931 BT-10 "Buyer reference" — the standard's own name, deliberately not renamed).
For B2B invoices, top-level buyerReference is optional but recommended when the customer requests it for internal purchase-order matching.
Electronic addresses
An XRechnung or Peppol invoice must say where the customer and the supplier can be reached electronically. Clearvo uses the first of these that exists.
Customer:
- The customer's own endpoint:
electronicAddress(valuewithschemeId), as you send them. - The customer's stored Peppol participant ID, once confirmed.
- The Leitweg-ID, with scheme
0204(Leitweg-ID). It must pass the Leitweg-ID check digits; a free-textbuyerReferencesuch as a purchase order number is ignored here. - The customer's contact email, with scheme
EM(email). - The customer's German VAT ID (
DEand 9 digits), with scheme9930(Germany VAT number).
Supplier (your entity):
- The entity's confirmed Peppol participant ID.
- The entity's contact email, with scheme
EM. - The entity's German VAT ID, with scheme
9930.
If there is none, the invoice is blocked with the error rule MISSING_CUSTOMER_ELECTRONIC_ADDRESS or MISSING_SUPPLIER_ELECTRONIC_ADDRESS before any XML is generated. Add one of them to the request, the customer record or your entity and send again.
Customer references
A customer record can carry references: identifiers that are not tax numbers. Tax and VAT numbers stay in taxId and taxIds. GET /v1/customer-reference-types?country=DE lists the types, with a label, help text, an example, the countries each applies to and how the value is checked. Today there are two:
PEPPOL_PARTICIPANT_ID— the customer's Peppol ID written asscheme:value, for example0204:04011000-1234512345-06or9930:DE123456789. A value you send through the API counts as confirmed.LEITWEG_ID— Germany only, one per customer, for example04011000-1234512345-06. The check digits are verified.
Write them with a references list (at most 20 items) on POST /v1/customers, PATCH /v1/customers/{id} or PUT /v1/customers/by-ref/{customerRef}:
{ "references": [ { "type": "LEITWEG_ID", "value": "04011000-1234512345-06" } ] }
When present, the list replaces the customer's whole list. On PATCH and PUT, leaving references out keeps what is stored; null or [] clears it. Customer responses return references as [{ type, value, confirmed }]; a Peppol participant ID also carries reachable and checkedAt. This replaces the former top-level peppol object and the peppolParticipantId request field.
If an item fails validation, the request returns 422 INVALID_REFERENCES and nothing is written. error.references lists every failing item with its index, type, message and a code of INVALID_REFERENCE, UNKNOWN_REFERENCE_TYPE, REFERENCE_TYPE_NOT_APPLICABLE or DUPLICATE_REFERENCE_TYPE.
On POST /v1/send with customer.customerRef, the stored confirmed Peppol participant ID and the stored Leitweg-ID fill in only when the request supplies neither the explicit value (the electronicAddress pair; countrySpecific.de.leitwegId or a non-empty buyerReference). A value in the request always wins.
Sending over Peppol
Set countrySpecific.de.invoiceFormat to PEPPOL (or make it the customer or entity default) to send the invoice over the Peppol network. Two things must be in place:
- Your entity needs a confirmed Peppol Participant ID. Without one the request returns
422 MISSING_SELLER_PEPPOL_ID. - The customer needs an explicit Peppol ID, sent as
customer.electronicAddress.schemeIdandcustomer.electronicAddress.value(for example0204and a Leitweg-ID, or9930and a German VAT ID) or stored on the customer as a confirmedPEPPOL_PARTICIPANT_IDreference. A German customer's Peppol ID is never derived from a VAT number.
If the customer has no Peppol ID, or the Peppol network does not know the one supplied, the request returns 422 PEPPOL_CUSTOMER_UNREACHABLE with a reason (NO_CUSTOMER_PEPPOL_ID or NOT_REGISTERED_ON_PEPPOL) and an alternatives[] list. There is no silent fallback to another format: the invoice is stored as NEEDS_INFO, and each alternative carries a resend fragment to re-send it as ZUGFeRD or XRechnung. Send dryRun: true to run the German content rules, validation and the reachability check without storing anything or queueing a delivery.
A successful Peppol send returns clearanceStatus: PENDING and a delivery block (channel: NETWORK and the customer's address in receiver). If the generated invoice fails schema or EN 16931 validation, it is held as NEEDS_INFO with errorCode: PEPPOL_SCHEMATRON_VALIDATION_FAILED and a validationReport; correct the data and resubmit with correctsInvoiceId to reuse the invoice number. If validation is temporarily unavailable the request returns 503 VALIDATION_UNAVAILABLE; retry with the same idempotency key.
Credit and debit notes over Peppol work for Germany too (see Credit notes and debit notes over Peppol), as they do with ZUGFeRD and XRechnung. Not yet supported over Peppol for Germany: self-billed documents (400 DE_SELF_BILLED_PEPPOL_NOT_SUPPORTED when requested on the invoice, 422 DE_SELF_BILLED_FORMAT_CHOICE_REQUIRED when a stored default is PEPPOL).
Receiving German invoices over Peppol
Invoices your entity receives over the Peppol network are checked on arrival and appear in GET /invoices?direction=inbound and as an invoice.received webhook, alongside documents received by API, dashboard upload, bulk upload or email. Each received record carries:
intakeChannelandreceivedAt— how and when the document arrived (PEPPOL_AS4for the Peppol network).validation— what was checked and found: the rule set and version, error and warning counts, and onGET /invoices/{id}the individual findings. It states what was checked; it does not declare a document valid or compliant.validationOutcomeaddsBUSINESS_RULE_ERROR(well formed but failing business rules) andNOT_VALIDATED(the checks could not run).attachments— the supplier's own supporting documents, listed only. The bytes are never returned.rendition— howGET /documents/{id}?format=pdfanswers.
A Peppol invoice arrives as XML, so there is no supplier PDF. GET /documents/{id}?format=pdf returns a labelled PDF reader copy rendered from the structured data for any received Peppol invoice (rendition: generated, with the response header x-clearvo-rendition: generated). It is a readable copy, not the invoice itself; format=xml returns the document as received. When the supplier did send a PDF, format=pdf returns that archived original unchanged (rendition: original). A record that cannot be drawn returns 422 with PDF_NOT_RENDERABLE, PDF_SCRIPT_UNSUPPORTED or PDF_TOO_LARGE and a hint, never a server error.
events[].peppolDelivered to confirm network delivery.Credit notes and debit notes over Peppol
You can send credit notes and debit notes over the Peppol network in Belgium, the Netherlands, Austria, Croatia, Slovakia, Ireland, Norway, Sweden, Denmark, Finland, Lithuania, Latvia, Estonia, Luxembourg, Slovenia, Iceland, Switzerland, Germany (when the Peppol format is used), Australia and New Zealand.
- Credit notes use
documentType: "credit_note". A credit note reverses a previously accepted invoice in full. Partial credit notes over Peppol are not supported yet (France and Spain support partial credit notes). - Debit notes use
documentType: "debit_note". Peppol has no separate debit-note document, so a debit note is sent as an invoice marked as a debit note (UNTDID 1001 type code383). - Referencing the original invoice: pass either
correctsInvoiceId(theidClearvo returned when you sent the original invoice, an exact match) or anoriginalInvoiceRefblock with the originalinvoiceNumberandissueDate. The credit or debit note needs its own newinvoiceNumber.
{
"documentType": "credit_note",
"invoiceNumber": "CN-2026-0001",
"originalInvoiceRef": {
"invoiceNumber": "INV-2026-0001",
"issueDate": "2026-06-19"
}
}
The example shows only the fields specific to a credit note; send the rest of the invoice (supplier, customer, lines, totals) as you would for an invoice.
In Germany, ZUGFeRD, XRechnung and Peppol all support credit and debit notes. Credit and debit notes you receive over Peppol appear in your inbox with the right label, and the "received" email says "credit note" or "debit note".
Not yet supported: Singapore, Japan and the UAE
Credit notes and debit notes are not yet supported over Peppol for Singapore, Japan and the UAE. A request returns 422 with code CREDIT_NOTE_PEPPOL_UNSUPPORTED. Send a corrected invoice instead, or contact support.
France — Factur-X and the PDP framework
France is implementing a mandatory B2B e-invoicing and e-reporting system under the réforme de la facturation électronique. The rollout is phased:
- September 2026 — Large enterprises (>250 employees or >50M€ turnover) must receive e-invoices; obligation to send follows shortly after.
- January 2027 — Mid-sized businesses.
- January 2028 — Small businesses and microenterprises.
What Clearvo generates today
Clearvo generates Factur-X EN16931 — the hybrid PDF+XML format that embeds a CII (Cross Industry Invoice) XML document inside a PDF/A-3. This is the format that French PDPs accept for domestic B2B invoices. The generated XML is structurally valid and can be validated against the EN16931 Schematron.
For B2G invoices, Chorus Pro is the existing mandatory channel. Clearvo does not currently submit to Chorus Pro — that integration is on the roadmap for 2026.
What is a PA (Plateforme Agréée)?
A PA (Plateforme Agréée) — formerly called PDP (Plateforme de Dématérialisation Partenaire) — is a DGFiP-accredited intermediary that receives invoices, validates them, forwards them to the customer's platform, and reports transaction data to the DGFiP's Portail Public de Facturation (PPF). There are approximately 137 platforms in the process of accreditation as of June 2026.
Clearvo has applied for PA (Plateforme Agréée) accreditation in its own right. While the application is processed, Factur-X invoices are delivered through an accredited third-party platform, so you are covered both before and after the September 2026 mandate. Once Clearvo's own accreditation is granted, invoices route directly through Clearvo as the PA — your integration does not change.
Current status — what you need to know
If you are building an integration today: submit invoices to Clearvo with country: "FR". Clearvo generates the Factur-X document, marks the invoice ACCEPTED, stores the XML for download and delivers it through the accredited platform. When Clearvo's own PA accreditation is granted, the same API call routes directly through Clearvo — your integration does not change.
Status lifecycle
Portugal — ATCUD, QR code and AT communication
Portugal does not clear invoices before delivery. Instead, every document must be issued by AT-certified invoicing software (Autoridade Tributária e Aduaneira), carry an ATCUD code and a QR code (Portaria 195/2020), have its data communicated to AT by the 5th of the following month (Decreto-Lei 198/2012), and be included in the SAF-T (PT) 1.04_01 billing file — produced monthly and available to AT on request.
What Clearvo does
- Certified issuance — Clearvo is AT-certified invoicing software. Every invoice, credit note and debit note is issued with the AT hash chain, a sequential number within its series, the ATCUD and the QR code.
- Series registration — Clearvo registers your FT (invoice), NC (credit note) and ND (debit note) series with AT and stores the validation codes, or uses the series and codes you already hold.
- Communication to AT — enable the
pt_efaturareporting obligation for the entity (PATCH /v1/tax/reporting-obligations) and Clearvo communicates each document's data to AT automatically. Follow the outcome viaptReportingDetailonGET /v1/invoices/{id}, or subscribe to theinvoice.reportedandinvoice.report_rejectedwebhooks. - Monthly SAF-T (PT) — download the billing file for any month with
GET /v1/pt/saft?period=YYYY-MM. Addformat=summaryfor a JSON manifest (per-document list, file hash, XSD outcome) instead of the XML itself.
Step 1 — Register your AT details (one-time setup)
Call POST /v1/pt/credentials once per entity with your nif plus one of the two options below. With an organisation-scoped API key, pass the entity in the x-entity-id header.
In Portal das Finanças, create a webservice sub-user (Gestão de Utilizadores) with the WFA (invoice-data communication) and WSE (series communication) permissions. Send the sub-user in the form NIF/n together with its password. Clearvo registers one series each for FT, NC and ND with AT and stores the validation codes AT returns. The password is encrypted at rest and never returned.
POST /v1/pt/credentials
x-api-key: csk_live_••••••••
x-entity-id: ent_•••• (organisation keys only)
Content-Type: application/json
{
"nif": "500000000",
"subUser": "500000000/1",
"password": "••••••••"
}
Send each series and the ATCUD validation code AT issued for it (Portal das Finanças → Faturação → Séries). Each document type you issue needs its own series — add creditNoteSeries / creditNoteValidationCode and debitNoteSeries / debitNoteValidationCode as needed.
POST /v1/pt/credentials
x-api-key: csk_live_••••••••
Content-Type: application/json
{
"nif": "500000000",
"invoiceSeries": "A2026",
"invoiceValidationCode": "AAJFJ7X5",
"creditNoteSeries": "NC2026",
"creditNoteValidationCode": "BBKGK8Y6"
}
GET /v1/pt/credentials returns the stored series and validation codes (they print on every document); the password is never returned. DELETE /v1/pt/credentials removes them.
Step 2 — Submit documents
Use the standard POST /v1/send endpoint with country: "PT" and the Portuguese NIF in supplier.taxId / customer.taxId. Set documentType to invoice, credit_note or debit_note — Clearvo issues the document in the matching FT / NC / ND series. The response carries clearanceStatus: ACCEPTED, terminal: true and the document's ATCUD in referenceId; print the ATCUD and QR code on the PDF you give your customer.
Step 3 — Follow the communication to AT
ptReportingDetail.communicatedAt is set.ptReportingDetail carries AT's response code and message; the issued document itself is unaffected.Monthly SAF-T (PT)
GET /v1/pt/saft?period=2026-08 returns SAFT-PT_<NIF>_2026-08.xml — every FT / NC / ND document issued for the entity in that month, in one AuditFile validated against the 1.04_01 schema before it is returned. A month with no Portuguese documents returns a valid, empty file. Use format=summary for the JSON manifest.
csk_test_* key. Sandbox issuance uses AT's sandbox series placeholder and makes no calls to AT.Peppol countries
Clearvo supports 22 Peppol BIS Billing 3.0 countries (BE, NL, AT, HR, SK, DK, IE, NO, SE, FI, LT, LV, EE, LU, SI, IS, CH) and 5 PINT countries (AU, NZ, SG, JP, AE). Your API payload uses the same CustomerInvoiceInput schema for all — only country changes. Clearvo handles format selection, EAS scheme resolution, SMP lookup, and AS4 delivery automatically.
How Peppol delivery works
Peppol is a network of certified Access Points (APs) that exchange business documents using the AS4 messaging protocol. When you submit an invoice for a Peppol country, Clearvo:
Your CustomerInvoiceInput payload is transformed into a fully compliant UBL 2.1 invoice with the correct CustomizationID, ProfileID, and country-specific endpoint scheme IDs.
Clearvo queries the Peppol SMP (Service Metadata Publisher) to discover the customer's Access Point endpoint and supported document types. If the customer is not registered on the Peppol network, the submission is held and you are notified.
The invoice is delivered via AS4 to the customer's Access Point. Clearvo's own Access Point is a certified Peppol Access Point (PIE001162). Delivery confirmation sets status to DELIVERED.
Customer endpoint resolution
Clearvo resolves the customer's Peppol endpoint in this order:
- Explicit —
customer.electronicAddress(value+schemeId) in the payload. Required for NL, SK, AT, IS, NZ, AE, and CH where VAT-to-Peppol derivation is not reliable. - Auto-derived — Clearvo derives the Peppol identifier directly from
customer.taxIdfor countries where this is unambiguous: BE, DK, NO, FI, SE, HR, IE, LU, SI, EE, LV, LT, AU, SG, JP. - SMP cache — Resolved endpoints are cached indefinitely. Cache is refreshed automatically on delivery failure.
If no endpoint can be determined or the customer is not registered on Peppol, the invoice transitions to UNROUTABLE (non-terminal). The UBL XML is stored. Retry delivery later via POST /v1/invoices/{id}/deliver.
Use GET /v1/participants/lookup to check whether a customer is registered before submitting an invoice.
Country-specific EAS endpoint schemes
Countries marked Auto derive the Peppol ID from customer.taxId — no extra fields needed. Countries marked Explicit require customer.electronicAddress (value and schemeId) in the payload.
| Country | EAS Scheme ID | Identifier format | Example | Resolution |
|---|---|---|---|---|
| BE | 0208 | KBO/BCE company number | 0208:0420429272 | Auto |
| DK | 0184 | CVR number (with DK prefix) | 0184:DK12345678 | Auto |
| NO | 0192 | Organisation number | 0192:123456789 | Auto |
| FI | 0216 | OVT code (0037 followed by the 8-digit business ID) | 0216:003712345678 | Auto |
| SE | 0007 | Organisation number | 0007:1234567890 | Auto |
| HR | 9934 | Croatian VAT number (HR prefix plus 11-digit OIB) | 9934:HR12345678901 | Auto |
| IE | 9935 | VAT number (with IE prefix) | 9935:IE1234567A | Auto |
| LU | 9938 | VAT number (with LU prefix) | 9938:LU12345678 | Auto |
| SI | 9949 | VAT number (with SI prefix) | 9949:SI12345678 | Auto |
| EE | 0191 | Registrikood | 0191:12345678 | Auto |
| LV | 0218 | Unified registration number | 0218:12345678901 | Auto |
| LT | 0200 | LIS company code | 0200:123456789 | Auto |
| AU | 0151 | ABN | 0151:51824753556 | Auto |
| JP | 0221 | IIN | 0221:T1234567890123 | Auto |
| SG | 0195 | UEN | 0195:200000177W | Auto |
| NL | 0106 | KvK number (without NL prefix) | 0106:37340183 | Explicit |
| SK | 9950 | Slovakia VAT number (the official list also has 0245 for the DIČ tax ID) | — | Explicit |
| AT | 9914 / 9915 | 9914: Austrian VAT number (UID). 9915: public-administration identifier (Verwaltungskennzeichen) | 9914:ATU12345678 | Explicit |
| IS | 0196 | Kennitala | 0196:5503760649 | Explicit |
| NZ | 0088 | NZBN | 0088:9429041866977 | Explicit |
| AE | 0235 | UAE Tax Identification Number (TIN) | 0235:100123456789003 | Explicit |
| CH | 0183 | UID (without CHE prefix) | 0183:123456789 | Explicit |
For NL, SK, AT, IS, NZ, AE, and CH, always provide customer.electronicAddress (value and schemeId) explicitly — VAT-to-Peppol derivation is not reliable for these countries. For all other Peppol countries, Clearvo derives the endpoint automatically from customer.taxId.
Format and validation
All BIS Billing 3.0 invoices are validated against:
- UBL 2.1 schema (structural)
- EN16931 Schematron (business rules)
- Peppol BIS 3.0 Schematron (BIS-specific rules, e.g. mandatory
CustomizationID)
Belgium — Hermes/Mercurius
Belgium's public sector uses the Mercurius platform (operated by BOSA). B2G invoices for Belgian federal entities must be delivered to Mercurius via Peppol. Clearvo routes B2G invoices automatically via the Peppol network — no separate integration is required from your side.
The Belgian B2B mandate (all businesses) is effective from 2026. Customers who are not yet on Peppol can also receive invoices via the Hermes portal.
Croatia — FINA
Croatia's e-invoicing infrastructure is managed by FINA (Financijska agencija — Croatian Financial Agency). FINA operates a Peppol Access Point. The 2026 mandate covers B2B and B2G transactions.
Greece — myDATA
myDATA (My Digital Accounting and Tax Application) is Greece's real-time digital transaction reporting system operated by AADE (Ανεξάρτητη Αρχή Δημοσίων Εσόδων — the Independent Authority for Public Revenue). All businesses must report invoices to AADE in real-time.
How it works
Unlike pre-clearance countries (Italy, Poland), Greece uses a post-issuance reporting model. You issue the invoice to your customer normally, then separately report the transaction data to AADE via the myDATA API. The invoice is not "approved" by AADE before delivery — it is registered after the fact.
POST your invoice to Clearvo with country: "GR". Clearvo generates the myDATA XML (InvoicesDoc) with the correct invoice type (1.1 for sales, 5.1 for credit notes) and VAT category codes.
Clearvo POSTs to myDATA/SendInvoices. On success, AADE returns a mark (registration number), a UID, and an authentication code. These are returned in the Clearvo response.
The AADE mark must be printed or included on the invoice you send to your customer. Clearvo surfaces the mark as referenceId in the response.
VAT category mapping
| VAT rate | Tax code | myDATA vatCategory |
|---|---|---|
| 24% | S (standard) | 1 |
| 13% | AA (reduced) | 2 |
| 6% | AB (super-reduced) | 3 |
| 0% exempt | E | 4 |
| 0% zero-rated | Z | 5 |
| 0% reverse charge | AE | 7 |
Status lifecycle
PENDING. The submission is retried automatically. Configure the aade_user_id and aade_subscription_key in your Clearvo account settings to enable live submission.Mexico — CFDI receiving
Clearvo's Mexico support is receive-only: there is no CFDI issuing/stamping through Clearvo (that requires a PAC — Proveedor Autorizado de Certificación — accreditation, which is out of scope). What Clearvo does is ingest, validate, and store CFDI 4.0 documents your suppliers' own PACs have already stamped, so your accounts-payable data lands in the same place as every other country's invoices.
Two ingestion modes
Choose per entity via PATCH https://api.clearvo.io/v1/entities/{id}'s mxIngestionMode field:
| Mode | How it works | Credential needed |
|---|---|---|
sat_pull (default) | Clearvo polls SAT's own Descarga Masiva (bulk download) service on your behalf, using a rolling lookback window to tolerate SAT's own multi-day backend publishing lag. | Your entity's e.firma / CSD (certificate + key + password) |
client_push | Your own AP/ERP system already receives the CFDI XML — push it directly to Clearvo as it arrives. | None |
Both modes converge on the same validation, storage, and invoice.received webhook — switching modes later doesn't change how received documents look once stored.
sat_pull — register your e.firma
Requires a Mexico tax registration (RFC) on file for the entity first. The e.firma's own certificate RFC is cross-checked against it — Clearvo never writes the RFC for you.
POST https://api.clearvo.io/v1/mx/credentials
x-api-key: csk_live_••••••••
Content-Type: application/json
{
"certificateBase64": "<base64 .cer, issued by SAT>",
"keyBase64": "<base64 .key, PKCS#8>",
"password": "<e.firma password>"
}
SAT has no push mechanism, so Clearvo polls it on an hourly background schedule automatically. You can also trigger a poll on demand for your own entity (rate-limited to once per 15 minutes):
POST https://api.clearvo.io/v1/mx/inbound/poll
x-api-key: csk_live_••••••••
Check the poller's own health per entity any time — this is a pure database read, it never calls SAT itself:
GET https://api.clearvo.io/v1/mx/sync-status
x-api-key: csk_live_••••••••
client_push — send us the XML directly
No credential needed. Accepted regardless of mxIngestionMode — the mode only controls whether the SAT poller also sweeps this entity. Idempotent on the CFDI's own Folio Fiscal (UUID): retrying a push for a document already stored returns 200 with duplicate: true, never a conflict.
POST https://api.clearvo.io/v1/mx/inbound/cfdi
x-api-key: csk_live_••••••••
Content-Type: application/xml
<cfdi:Comprobante ...>...</cfdi:Comprobante>
What Clearvo checks on every CFDI
Every received CFDI — either ingestion path — goes through the same pipeline: CFDI 4.0 / Anexo 20 schema validation, digital seal (sello digital) verification against the issuer's certificate chain, and a live check against SAT's own ConsultarEstatusCFDI service (Vigente / Cancelado / No Encontrado — the primary source of truth for clearanceStatus). A separate advisory check compares the document's UsoCFDI / RegimenFiscalReceptor against your entity's own registered tax regime and surfaces a flag (not a rejection) on a mismatch, since it can affect your own deduction eligibility. Carta Porte and Complemento de Recepción de Pagos complements are tolerated (never cause a rejection) but their specific fields are not individually extracted yet.
Status lifecycle
invoice.received fires immediately — there is no internal review/approval step to wait on.invoice.received never fires for this outcome.