API Documentation

Learn how to integrate InvoiceHub validation into your application.

Authentication

All API requests require an API key. Include it in the Authorization header:

Authorization: Bearer ih_live_xxxxxxxxxxxxxxxxxxxxxx

Get your API key from the dashboard.

Validate Invoice

POST /api/v1/validate

Validate a UBL 2.1 invoice against the official CEN EN 16931 Schematron (v1.3.16). Returns structured errors and warnings mapped to the official BR-* rule identifiers.

No API key yet? Try POST /api/v1/playground (unauthenticated, rate-limited) or the live playground on the home page.

Request Headers

Content-Type: application/xml
Authorization: Bearer <api_key>

Request Body

Raw XML invoice document

<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
  <cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>
  <cbc:ID>INV-001</cbc:ID>
  <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
  <!-- ... -->
</Invoice>

Response (200 OK - Valid)

{
  "timestamp": "2026-06-17T10:30:00Z",
  "requestId": "0f3c…",
  "performance": { "duration_ms": 5 },
  "report": {
    "valid": true,
    "format": "UBL_2.1",
    "profile": "Peppol BIS Billing 3.0",
    "rulesEvaluated": 13,
    "errors": [],
    "warnings": [],
    "metadata": {
      "invoiceNumber": "INV-2026-001",
      "currency": "EUR",
      "payableAmount": 180.6
    }
  }
}

Response (422 Unprocessable Entity - Invalid)

{
  "timestamp": "2026-06-17T10:30:00Z",
  "requestId": "0f3c…",
  "performance": { "duration_ms": 4 },
  "report": {
    "valid": false,
    "format": "UBL_2.1",
    "rulesEvaluated": 13,
    "errors": [
      {
        "ruleId": "BR-CO-15",
        "severity": "CRITICAL",
        "message": "Invoice total amount with VAT must equal total without VAT + total VAT.",
        "path": "Invoice.cac:LegalMonetaryTotal.cbc:TaxInclusiveAmount"
      }
    ],
    "warnings": []
  }
}

Generate Invoice

POST /api/v1/generate

Build an EN 16931-conformant UBL 2.1 invoice from structured JSON. Every monetary total is computed for you, and the generated document is validated against the official Schematron before it is returned — if it would not pass, you get the validation report (HTTP 422) instead of an invalid document. We never hand back XML we have not checked.

Request Body (application/json)

{
  "invoiceNumber": "INV-2026-001",
  "issueDate": "2026-06-19",
  "dueDate": "2026-07-19",
  "currency": "EUR",
  "seller": {
    "name": "Acme Trading GmbH",
    "vatId": "DE123456789",
    "address": { "street": "Hauptstraße 1", "city": "Berlin", "postalZone": "10115", "country": "DE" }
  },
  "buyer": {
    "name": "Buyer Industries SARL",
    "address": { "city": "Paris", "postalZone": "75001", "country": "FR" }
  },
  "lines": [
    { "description": "Consulting services", "quantity": 10, "unitPrice": 100, "vatRate": 19, "unitCode": "HUR" }
  ],
  "payment": { "iban": "DE89370400440532013000" }
}

Response (200 OK)

{
  "requestId": "0f3c…",
  "performance": { "duration_ms": 6 },
  "xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Invoice …>…</Invoice>",
  "report": { "valid": true, "format": "UBL_2.1", "rulesEvaluated": 54, "errors": [], "warnings": [] }
}

Standard-rated lines (VAT category S) require avatRate and the seller vatId (BR-S-2). Exempt and reverse-charge categories require an exemptionReason.

Supported Formats & Roadmap

Query GET /api/v1/formats for the live list. Current status:

FormatStatus
UBL 2.1 (Invoice & CreditNote)Generally available
Official CEN EN 16931 Schematron (v1.3.16)Generally available
UN/CEFACT CIIPlanned
XRechnung (DE)Planned
Factur-X / ZUGFeRD (hybrid PDF)Planned
Peppol BIS Billing 3.0Planned

UBL 2.1 is validated with the official CEN EN 16931 Schematron artifacts (v1.3.16). XSD schema validation and additional syntaxes are in progress.

MCP endpoint (for AI agents)

InvoiceHub ships a Model Context Protocol endpoint so AI agents can validate and generate EU e-invoices directly. It speaks JSON-RPC 2.0 over Streamable HTTP at POST https://api.invoicehub.dev/mcp and exposes three tools:validate_invoice,generate_invoice andlist_supported_formats.

curl -X POST https://api.invoicehub.dev/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
       "params":{"name":"validate_invoice","arguments":{"xml":"<Invoice …>…</Invoice>"}}}'

OpenAPI & SDKs

The full API is described by an OpenAPI 3.1 document. Import it into Postman or Insomnia, or generate a typed client in your language with tools likeopenapi-generator,Speakeasy orFern.

npx @openapitools/openapi-generator-cli generate \
  -i https://api.invoicehub.dev/api/v1/openapi.json \
  -g typescript-fetch -o ./invoicehub-client

Code Examples

cURL

curl -X POST https://api.invoicehub.dev/api/v1/validate \
  -H "Authorization: Bearer ih_live_xxx" \
  -H "Content-Type: application/xml" \
  -d @invoice.xml

JavaScript

const response = await fetch('https://api.invoicehub.dev/api/v1/validate', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ih_live_xxx',
    'Content-Type': 'application/xml'
  },
  body: xmlContent
});

const result = await response.json();
console.log(result.report);

Python

import requests

response = requests.post(
  'https://api.invoicehub.dev/api/v1/validate',
  headers={
    'Authorization': 'Bearer ih_live_xxx',
    'Content-Type': 'application/xml'
  },
  data=xml_content
)

result = response.json()
print(result['report'])

Rate Limits

PlanHourly LimitDaily Limit
Free60600
Pro10,000100,000
EnterpriseUnlimitedUnlimited

Rate limit headers are included in every response:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 2026-06-17T11:00:00Z

Error Handling

401 Unauthorized

Invalid or missing API key. Check your authentication header.

422 Unprocessable Entity

Invoice validation failed. Check the errors array in the response.

429 Too Many Requests

Rate limit exceeded. Check the Retry-After header for when to retry.

500 Internal Server Error

Unexpected error. Contact support if this persists.

Need help?

Check our pricing page for support options.

Contact us and we'll get back to you.