Developers · API reference · OpenAPI 2.0.0
Every endpoint, one contract.
25 endpoints under https://www.invoicenavigator.eu/api. JSON in, JSON out, Bearer key in the header. The table below is generated from openapi.json; the spec is the source of truth.
| Endpoint | Does | Key |
|---|---|---|
| Validation | ||
| POST /v1/validate | Validate an e-invoice | any key |
| POST /v1/validate/batch | Validate multiple invoices | Team |
| POST /v2/validate | Validate an invoice (v2, fixability-enriched) | any key |
| Fixer | ||
| POST /v1/fixer/categorize | Categorize validation errors | any key |
| POST /v1/fixer/fix | Auto-fix invoice errors | any key |
| POST /v1/fixer/fix-with-input | Apply user-provided input fixes | any key |
| GET /v1/fixer/usage | Get fix quota usage | any key |
| GET /v1/fixer/download | Download fixed or original invoice XML | any key |
| Evidence Packs | ||
| POST /v1/evidence-pack | Generate Evidence Pack | Team |
| GET /v1/evidence-packs | List Evidence Packs | any key |
| GET /v1/verify/{id} | Verify an Evidence Pack | no key |
| Conversion | ||
| POST /v1/convert | Convert invoice format | Team |
| Countries | ||
| GET /v1/countries | List all supported countries | any key |
| GET /v1/countries/{code} | Get country details | any key |
| GET /v1/rules/{country} | Get validation rules for a country | any key |
| Regulatory Intelligence | ||
| GET /v1/deadlines | Get compliance deadlines | any key |
| GET /v1/requirements | Get trade lane requirements | any key |
| POST /v1/compliance-score | Calculate compliance readiness score | any key |
| GET /v1/changes | Get regulatory changes | any key |
| Reference Data | ||
| GET /v1/errors | List validation error codes | no key |
| GET /v1/errors/{ruleId} | Get error code details | no key |
| GET /v1/facts/search | Search compliance facts | no key |
| GET /v1/facts/{country} | Get country compliance facts | no key |
| Account | ||
| GET /v1/usage | Current usage of the calling key | any key |
| Remediation | ||
| POST /v2/validate-and-fix | Validate, surgically fix, re-validate — one call | any key |
no key — public. any key — Free or Team. Team — a Free key receives 403 INSUFFICIENT_TIER. https://api.invoicenavigator.eu/api is an alias of the base URL. Download openapi.json or the Postman collection.
POST /v2/validate-and-fix
Validates the XML, patches what is structural, re-validates the patched file against the official validators, and optionally signs an evidence pack. Counts as 2 requests against the monthly quota.
POST /v2/validate-and-fix
Authorization: Bearer sk_live_…
Content-Type: application/json
{
"xml": "<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\">…</Invoice>",
"fileName": "INV-2026-0847.xml",
"autoFix": true,
"generate_evidence_pack": false
}| Body field | Type | Meaning |
|---|---|---|
| xml | string | The invoice XML (UBL or CII). Required. At most 10 MB. |
| fileName | string | Kept in the evidence pack and the flow record. |
| autoFix | boolean | Default true. false validates only. |
| remediation_policy | "safe" | "none" | Same switch, older name. none validates only. |
| generate_evidence_pack | boolean | Inline a signed evidence pack in data.evidencePack. |
| data.* | Type | Meaning |
|---|---|---|
| validationRef | string | Reference of this validation; also in meta. |
| originalValid | boolean | The submitted XML already passed. |
| fixedValid | boolean | The patched XML passes re-validation. Present when patching ran. |
| fixesApplied | integer | Number of structural edits. |
| fixedXml | string | The patched file. Present only when it differs from what you sent. |
| remainingIssues[] | object | code, severity (error · warning · info), title, message. |
| fixSummary | object | null | totalIssues, autoFixable, needsInput, blocked, unknown, canAutoFixAll. |
| metadata | object | Invoice number, issue date, currency, seller, buyer, total — as read from the file. |
| flowId | string | Identifier for follow-up calls. Absent on sk_test_ keys. |
| engine | string | orchestrator, safe-fixer or hybrid. |
| evidencePack | object | The signed pack, when requested: id, data, proof (algorithm, keyId, signature, signedAt, publicKeyUrl), verification URL. |
| _links | object | self; fixWithInput when needsInput > 0 and a flowId exists; evidencePack. |
Every response has the same shape
{
"success": true,
"data": { … },
"meta": {
"validationRef": "VAL-…",
"processingTimeMs": 1234,
"testMode": true // sk_test_ keys only
}
}{
"success": false,
"error": {
"code": "QUOTA_EXCEEDED",
"message": "Monthly quota exceeded. Upgrade your plan for more validations.",
"details": {
"used": 100,
"limit": 100,
"tier": "free",
"upgradeUrl": "/checkout/start?tier=pro"
}
}
}Test success first. error.details is optional and endpoint-specific; on QUOTA_EXCEEDED it carries the counter and the checkout URL.
What a non-2xx means
| Status | Code | When | Retry |
|---|---|---|---|
| 400 | INVALID_JSON | The body is not valid JSON. | no |
| 400 | MISSING_XML | The "xml" field is missing. | no |
| 400 | INVALID_XML | The "xml" field is not a string. | no |
| 400 | XML_TOO_LARGE | The XML is larger than 10 MB. | no |
| 401 | UNAUTHORIZED | No Bearer header, or the key is unknown. | no |
| 401 | KEY_EXPIRED | An instant test key past its hour. | no |
| 402 | QUOTA_EXCEEDED | Monthly quota used up, or the 10 instant-key requests. details.upgradeUrl points to the Team checkout. | no |
| 403 | KEY_INACTIVE | The key was revoked. | no |
| 403 | INSUFFICIENT_TIER | A Team-only endpoint called with a Free key. | no |
| 429 | RATE_LIMITED | Too many requests in the sliding hour. Retry-After is set. | after Retry-After |
| 500 | INTERNAL_ERROR | The engine failed. X-Request-Id identifies the call. | with backoff |
| 503 | SERVICE_UNAVAILABLE | API authentication is not configured on the server. | with backoff |
Validation findings are never HTTP errors: an invoice that fails its rules still returns 200 with success: true and the codes in data. Each code has a page under /errors.
| Header | On | Meaning |
|---|---|---|
| X-Request-Id | every response | Identifier of this call. Log it; quote it when you write to us. |
| X-Processing-Time-Ms | every response | Server time spent on the call, in milliseconds. |
| X-RateLimit-Limit | every authenticated response | Requests allowed per sliding hour for this key. |
| X-RateLimit-Remaining | every authenticated response | Requests left in the current hour. |
| X-RateLimit-Reset | every authenticated response | Unix seconds at which the window resets. |
| Retry-After | 429 only | Seconds to wait before the next attempt. |
| X-Test-Mode | sk_test_ keys only | Set to "true"; the body carries meta.testMode as well. |
| X-Usage-Used | metered live responses | Requests counted this month, after this call. |
| X-Usage-Included | metered live responses | Requests included in the plan for the month. |
| X-Usage-Overage | metered live responses | Requests beyond the included amount (0 while quotas are hard caps). |
| X-Usage-Period-End | metered live responses | Date the month counter resets. |
| Key | Requests / hour | Requests / month | Then |
|---|---|---|---|
| Free · sk_live_ | 60 | 100 | 402 until the month resets, or Team. |
| Team · sk_live_ | 100 | 5,000 | 402 until the month resets. |
| Account test key · sk_test_ | 100 | not metered | 429 with Retry-After. |
| Instant test key · sk_test_ | 100 | 10 in total | 402; the key expires after one hour. |
Hourly limits are a sliding window per key. The month counter is what GET /v1/usage returns and what the dashboard shows; reading it costs nothing. POST /v2/validate-and-fix counts as 2.