OpenAPI-first developer guide
Irish eInvoice validation API documentation
The browser checker and external clients use the same API. No account or API key is currently required. The base URL is https://invoiceready.ie/api/v1.
Quick start: XML
curl https://invoiceready.ie/api/v1/validate \
-H 'Content-Type: application/xml' \
--data-binary @invoice.xmlQuick start: canonical JSON
curl https://invoiceready.ie/api/v1/validate \
-H 'Content-Type: application/json' \
--data-binary @invoice.jsonPDF extraction and OCR
The recommended flow extracts a reviewable canonical draft without persisting it:
curl https://invoiceready.ie/api/v1/extract \
-H 'Content-Type: application/pdf' \
--data-binary @invoice.pdfReview and correct draft, then submit it as canonical JSON. For an explicit one-step readiness check:
curl https://invoiceready.ie/api/v1/validate \
-H 'Content-Type: application/pdf' \
-H 'X-Validation-Profile: auto' \
--data-binary @invoice.pdfPDF responses report extraction method, page count, confidence and warnings. They assess the extracted canonical interpretation, not EN 16931 conformance of the PDF. The PDF limit is 5 MiB, 10 pages and 10 extractions per source per hour.
Browser JavaScript
const response = await fetch('https://invoiceready.ie/api/v1/validate', {
method: 'POST',
headers: {'Content-Type': 'application/xml'},
body: xml
});
const report = await response.json();
if (!response.ok) throw new Error(report.error.message);PHP
<?php
$ch = curl_init('https://invoiceready.ie/api/v1/validate');
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_HTTPHEADER => ['Content-Type: application/xml'], CURLOPT_POSTFIELDS => file_get_contents('invoice.xml'), CURLOPT_RETURNTRANSFER => true]);
$report = json_decode(curl_exec($ch), true, flags: JSON_THROW_ON_ERROR);Endpoints
POST /extract— extract a non-persistent canonical draft from one PDF.POST /validate— validate XML, canonical JSON or an extracted PDF interpretation.GET /results/{uuid}— retrieve a result during retention.GET /samplesand/samples/{id}— discover fictitious test documents.GET /rulesets,/capabilities,/health— integration metadata.GET /phase1/requirementsandPOST /phase1/assess— non-persistent capability assessment.
Response and HTTP behaviour
A completed validation returns 200, including an invoice with rule errors. Request errors use 400, 413, 415, 422 or 429 and the stable shape {"error":{"code":"…","message":"…","request_id":"…"}}. Unexpected or unavailable services use 500/503.
Limits, CORS and privacy
Structured validation is limited to 60 requests per source per hour and 2.0 MiB per document. PDF extraction has a separate 10 per-hour limit. Public v1 endpoints support cross-origin browser use and OPTIONS preflight. Invoice bodies, PDFs, OCR text and values are never persisted or logged; direct-validation metadata and findings are retained for 90 days.
Test with a published sample
curl https://invoiceready.ie/api/v1/samples
curl https://invoiceready.ie/api/v1/samples/json-arithmeticPhase 1 and Phase 2 readiness API
curl https://invoiceready.ie/api/v1/readiness/requirements
curl -X POST https://invoiceready.ie/api/v1/readiness/assess \
-H 'Content-Type: application/json' \
-d '{"subject":"business","phase":"both","answers":{"P1-SCOPE-01":"yes","P2-SCOPE-02":"partial"}}'The legacy Phase 1 endpoints remain available. Readiness answers and reports are never persisted.
The OpenAPI 3.1 contract is authoritative for API requests and responses. Canonical JSON inputs follow the published JSON Schema 2020-12 document. Also review coverage boundaries.
Passing checks and field diagnostics
Fresh validation responses include reportable issues and a transient checks collection containing passing and not-applicable native rules. Retained results do not recreate passing checks because invoice contents are discarded. Canonical-schema errors may add content-free field paths and explanations in error.details.
Exact decimal input and arithmetic results
Canonical JSON accepts JSON numbers for v1 compatibility, but decimal strings such as "100.00" are recommended because they preserve the sender’s exact value. Arithmetic ruleset 1.2.0 reports independent MATH-001 to MATH-011 findings for lines, allowances, charges, VAT breakdowns, document totals, prepayments, rounding and amount due. The readiness tolerance is 0.01 monetary units.
{
"lines": [{
"quantity": "2", "unitPrice": "50.00",
"allowances": [{"amount": "10.00", "baseAmount": "100.00", "percentage": "10"}],
"netAmount": "90.00", "vatCategory": "S", "vatRate": "23"
}],
"totals": {"lineNetTotal": "90.00", "amountDue": "110.70"}
}See the complete field definitions in the canonical JSON Schema, inspect an arithmetic rule, or load json-adjustments and json-multiple-arithmetic-errors from the samples API.
Invoice Response and SBDH workflow XML
Check a UBL ApplicationResponse or a Peppol SBDH envelope without transmitting it or retaining its contents:
curl https://invoiceready.ie/api/v1/workflow/validate \
-H 'Content-Type: application/xml' \
--data-binary @invoice-response.xmlThe response reports Invoice Response identifiers, status/reference requirements, clarification requirements, and SBDH sender/receiver matching. Network registration and delivery are outside this endpoint.
EN 16931 and Peppol profiles
Technical profile selection is independent of the Irish full/simplified VAT profile. The default auto mode detects Peppol Billing identifiers in UBL. Force a candidate through Peppol document checks—even when its identifiers are wrong—with:
curl https://invoiceready.ie/api/v1/validate \
-H 'Content-Type: application/xml' \
-H 'X-Validation-Profile: peppol-bis' \
--data-binary @invoice.xmlUse X-Validation-Profile: en16931 to suppress Peppol checks. Peppol transport, participant registration and invoice delivery are not provided.
Multipart upload
curl https://invoiceready.ie/api/v1/validate \
-F 'invoice=@invoice.xml;type=application/xml' \
-F 'invoice_profile=full' \
-F 'validation_profile=auto'
Reading a validation response
{
"validation_id": "6f8d…",
"api_version": "1",
"input": {"format":"xml","syntax":"ubl-invoice","size":18422,"invoice_profile":"full"},
"rulesets": [{"name":"code-lists","version":"2026.08.3"}],
"summary": {"status":"needs_attention","score":82,"score_basis":"implemented_published_checks","passed":37,"warnings":2,"errors":3,"info":0,"undetermined":0},
"issues": [{"rule":"CODE-001","ruleset":"code-lists","severity":"error","title":"Currency codes","message":"Unrecognised code value(s): ZZZ.","field":"invoice.currency/invoice.taxCurrency","rule_url":"/rules/CODE-001"}]
}Use summary.status for the broad outcome and inspect every item in issues. Rule errors are document findings, so this response still uses HTTP 200. Store validation_id if you want to retrieve the content-free result during retention.
Errors, throttling and CORS
| Status | Meaning |
|---|---|
| 400 | Malformed API request |
| 413 | Document exceeds the configured limit |
| 415 | Unsupported media type |
| 422 | Recognised input that cannot be interpreted as a supported invoice |
| 429 | Hourly validation limit reached; honour Retry-After |
| 500/503 | Unexpected failure or temporary dependency outage |
Validation responses expose X-Request-ID for support correlation and RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds until reset). A throttled response also includes Retry-After. These headers are exposed to cross-origin browser clients.
curl -i -X OPTIONS https://invoiceready.ie/api/v1/validate \
-H 'Origin: https://client.example' \
-H 'Access-Control-Request-Method: POST'
Stable error codes are enumerated in the OpenAPI contract. Clients should branch on error.code, retain request_id for troubleshooting, and treat the message as explanatory text.
Discover rules and retained results
curl 'https://invoiceready.ie/api/v1/rules?ruleset=code-lists&page=1&per_page=20'
curl https://invoiceready.ie/api/v1/rules/CODE-001
curl https://invoiceready.ie/api/v1/results/YOUR_VALIDATION_UUID
curl https://invoiceready.ie/api/v1/rulesets/changelog
curl -X POST https://invoiceready.ie/api/v1/results/compare \
-H 'Content-Type: application/json' \
-d '{"before_validation_id":"EARLIER_UUID","after_validation_id":"NEWER_UUID"}'Comparison uses retained rule findings only. It reports resolved, introduced and unchanged findings without retaining or reconstructing invoice contents.
Standards status and test packs
curl https://invoiceready.ie/api/v1/standards
curl https://invoiceready.ie/api/v1/test-packs
curl https://invoiceready.ie/api/v1/test-packs/core-2026.08The standards response separates the EN 16931 edition from deployed artefact and Peppol versions. Test-pack metadata provides a downloadable ZIP and a manifest of fictitious scenarios with expected broad outcomes.
VAT number verification (VIES)
This optional endpoint performs one explicit European Commission VIES lookup. It is separate from invoice validation and does not affect the readiness score. Submitted numbers and returned details are not persisted or logged.
curl https://invoiceready.ie/api/v1/vat/verify \
-H 'Content-Type: application/json' \
-d '{"vat_number":"IE1234567A"}'
curl https://invoiceready.ie/api/v1/vat/verify \
-H 'Content-Type: application/json' \
-d '{"vat_number":"IE1234567A","requester_vat_number":"IE7654321B"}'
curl https://invoiceready.ie/api/v1/vat/statusA completed lookup returns HTTP 200 with result.status set to valid, invalid or undetermined. VIES validity is point-in-time evidence and does not prove the underlying transaction. The separate default limit is 30 lookups per source per hour.