# e-Factura Validator (Romania) – also Peppol BIS 3.0 and EN 16931 > Check a Romanian e-Factura (UBL 2.1, CIUS-RO 1.0.9) before uploading it to ANAF SPV, and get the exact fix for every error: plain-English explanation, the official Romanian rule text, the UBL path of the field and, for amount errors, the correct value computed from the invoice (chained, so following the report gives a consistent invoice). Also validates Peppol BIS Billing 3.0 and EN 16931. No account: $0.01 per invoice via x402, plus a small free tier. Base URL: https://einvoice.alexhub.uk OpenAPI: https://einvoice.alexhub.uk/openapi.json · MCP: https://einvoice.alexhub.uk/mcp · Short version: https://einvoice.alexhub.uk/llms.txt ## Prices and free quotas | What | HTTP | MCP tool | Price | |---|---|---|---| | Validate an invoice (e-Factura / Peppol / EN 16931) | POST /v1/validate | validate_invoice | $0.01 | | Validate an invoice, free | POST /v1/validate/free | validate_invoice_free | free, 3/day per IP | | Auto-fix an invoice (corrected XML) | POST /v1/fix | fix_invoice | $0.05, only if something was fixed | | Generate an e-Factura from JSON | POST /v1/generate | generate_invoice | $0.05 | | Check a SAF-T D406 file | POST /v1/saft/validate | validate_saft | $0.50 | | Check a SAF-T D406 file, free | POST /v1/saft/validate/free | validate_saft_free | free, 1/day per IP, first 10 findings | | Romanian company by CUI (ANAF) | GET /v1/company/{cui} | lookup_company | free, 100/day per IP | | BNR exchange rate | GET /v1/fx/{currency}?date= | fx_rate | free | | Holidays, working days, tax deadlines | GET /v1/calendar/… | ro_holidays, ro_business_day, ro_tax_deadlines | free | | IBAN check + Romanian bank | GET /v1/iban/{iban} | validate_iban | free | | Explain a rule (BR-RO-…, BR-CO-…, PEPPOL-…) | GET /en/rules/{rule} (HTML) | explain_rule | free | Paid calls: x402 (exact scheme), USDC on eip155:8453. No account, no API key, no gas for the payer. Nothing is charged for input that is not a UBL Invoice/CreditNote (or not a D406 file): HTTP 422, no payment. Free quotas reset at 00:00 UTC. All free calls together are also capped per day; when that cap is hit the free endpoints answer 429 and point to the paid one. ## When to call - An agent or program generated UBL invoice XML: validate before sending it to ANAF SPV / a Peppol access point. - ANAF rejected an invoice: validate it, every finding says what to change; or let /v1/fix change it. - You have invoice data but no XML: /v1/generate builds a validated e-Factura (parties filled from ANAF by CUI). - Before filing SAF-T (D406): ANAF's own validator plus the accounting consistency checks ANAF runs later. ## Validate an invoice Free (no wallet): ``` curl -X POST https://einvoice.alexhub.uk/v1/validate/free -H "Content-Type: application/xml" --data-binary @invoice.xml ``` Or JSON: `{"xml": "…", "profile": "auto"}` with Content-Type application/json. Profiles: auto (reads CustomizationID), ro (Romania e-Factura CIUS-RO 1.0.9), peppol (Peppol BIS Billing 3.0), en16931. Invoice and CreditNote, up to 2 MB. Response (same on the paid endpoint): ```json { "valid": false, "profile": "ro", "document_type": "Invoice", "errors": 1, "warnings": 0, "findings": [ { "rule": "BR-CO-15", "severity": "error", "title": "Total with VAT is wrong", "fix": "Set it to: total without VAT + total VAT.", "ubl": "cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount", "fields": [ "BT-112" ], "expected": { "field": "BT-112", "value": "1210.00", "found": "1190.00", "currency": "RON" } } ] } ``` - valid, errors, warnings: the verdict. Warnings do not make ANAF reject the invoice. - findings[]: rule, severity (error | warning), title, fix (what to change, in words), ubl (path of the field), fields (EN 16931 business terms), expected (the correct value for amount errors, computed from the invoice; chained, so applying all of them gives a consistent invoice), message (the official rule text). - autofix: present when /v1/fix can repair the errors for you. - Rule pages: https://einvoice.alexhub.uk/en/rules/ (EN), https://einvoice.alexhub.uk/ro/erori/ (RO). ## Pay with x402 (paid endpoints) 1. Call the paid endpoint as usual. Without payment you get HTTP 402: the PAYMENT-REQUIRED header (base64 JSON) holds the requirements (scheme exact, USDC on eip155:8453, amount, payTo); the JSON body repeats them and adds what to do without a wallet. 2. Sign an EIP-3009 transferWithAuthorization for that amount with your wallet (no gas, no transaction by you). 3. Repeat the same request with the PAYMENT-SIGNATURE header. On success the PAYMENT-RESPONSE header carries the settlement (transaction hash on Base). Client libraries do all three steps: npm `@x402/fetch` (wrap fetch), pip `x402` (httpx/requests clients). Payment is settled only when the response is billable (a real invoice / D406 was processed); 4xx/5xx are not charged. Over MCP, the paid tools take the x402 payment in the request `_meta` (x402 MCP transport); a call without it returns the payment requirements as a tool error, the same as the HTTP 402. ## Auto-fix POST https://einvoice.alexhub.uk/v1/fix, same body as validate. Repairs county/sector/country/currency/unit codes, dates, VAT-id prefixes, decimals, totals and VAT recomputed from the lines. Returns the corrected XML, every change (field, old, new) and the new validation report. Not charged if nothing was fixed. ## Generate an e-Factura POST https://einvoice.alexhub.uk/v1/generate: ```json {"number": "FCT-1", "issue_date": "2026-10-30", "seller": {"cui": "RO…"}, "buyer": {"cui": "…"}, "lines": [{"name": "Consulting", "quantity": 2, "unit": "buc", "price": 100, "vat_rate": 21}], "payment": {"iban": "RO…"}} ``` Names, addresses, county codes, Bucharest sectors and VAT status come from ANAF; any field you pass overrides them. Totals and VAT are computed and the XML is validated before it is returned. Other currencies: "currency": "EUR" (optionally "exchange_rate"; default = the BNR rate for the issue date); the VAT is also stated in RON (BR-RO-030). ## SAF-T (D406) ``` curl -X POST https://einvoice.alexhub.uk/v1/saft/validate/free -H "Content-Type: application/xml" --data-binary @D406.xml ``` Up to 100 MB over HTTP, 25 MB as text through MCP. Monthly/quarterly (L, T, NL, NT), annual assets (A) and on-demand stocks (C); year and month are read from the Header. Runs ANAF's official validator (DUKIntegrator) for the reporting period and the consistency checks it does not do offline: balanced entries, GL totals, opening + movements = closing per account, trial balance, partner balances, invoice totals, VAT = base x rate, VAT codes valid for the period, CUI/IBAN check digits, chart of accounts, Amount = CurrencyAmount x ExchangeRate, periods. Response: valid, errors, warnings, anaf{ok, errors}, consistency{errors}, period, summary, findings[]: layer (anaf | consistency), rule, severity, location, title/title_ro, fix/fix_ro, expected{value, found}. The free call returns the first 10 findings and the totals. Web page: https://einvoice.alexhub.uk/saft ## Free helpers ``` curl https://einvoice.alexhub.uk/v1/company/RO14399840 # ANAF data in e-Factura form: county RO-XX, SECTORn, VAT id, inactive curl "https://einvoice.alexhub.uk/v1/fx/EUR?date=2026-10-30" # official BNR rate, RON per unit; /v1/fx = all currencies curl "https://einvoice.alexhub.uk/v1/calendar/holidays?year=2026" curl "https://einvoice.alexhub.uk/v1/calendar/business-day?date=2026-12-24&add=3" curl "https://einvoice.alexhub.uk/v1/calendar/deadlines?period=2026-10" # monthly filing deadlines (D300, D406, D394, …) curl https://einvoice.alexhub.uk/v1/iban/RO49AAAA1B31007593840000 ``` ## MCP Streamable HTTP at https://einvoice.alexhub.uk/mcp, stateless, no authentication (the OAuth discovery paths answer 404 on purpose: no metadata = no auth). 13 tools, all read-only and non-destructive: validate_invoice_free, validate_invoice, fix_invoice, generate_invoice, validate_saft_free, validate_saft, lookup_company, explain_rule, fx_rate, ro_holidays, ro_business_day, ro_tax_deadlines, validate_iban. Claude Code: ``` claude mcp add --transport http einvoice https://einvoice.alexhub.uk/mcp ``` Claude Desktop (Settings > Connectors > Add custom connector, URL https://einvoice.alexhub.uk/mcp), or in claude_desktop_config.json: ```json {"mcpServers": {"einvoice": {"command": "npx", "args": ["-y", "mcp-remote", "https://einvoice.alexhub.uk/mcp"]}}} ``` Cursor (~/.cursor/mcp.json): ```json {"mcpServers": {"einvoice": {"url": "https://einvoice.alexhub.uk/mcp"}}} ``` VS Code (.vscode/mcp.json): ```json {"servers": {"einvoice": {"type": "http", "url": "https://einvoice.alexhub.uk/mcp"}}} ``` Also in the official MCP registry as uk.alexhub/einvoice-validator (server card: https://einvoice.alexhub.uk/.well-known/mcp.json). ## Errors | HTTP | Meaning | Charged | |---|---|---| | 200 | Report returned (also when the invoice has errors: valid=false) | yes, on paid endpoints | | 400 | Bad request: empty body, invalid JSON, unknown profile, bad CUI | no | | 402 | Payment required (paid endpoint without PAYMENT-SIGNATURE, or the payment was refused: see `error`) | no | | 404 | Unknown company / rule / page | no | | 413 | Body too large (2 MB invoices, 100 MB SAF-T) | no | | 422 | Not a UBL Invoice/CreditNote (or not a D406 file); /v1/fix: nothing to fix; /v1/generate: input gives an invalid invoice | no | | 429 | Free quota used up for today; the body names the paid endpoint | no | | 502 | ANAF or BNR did not answer (company lookup, generate, fx) | no | | 503 | Busy or starting; retry in a few seconds | no | MCP tools return the same status and body inside an error result: `{"status": 429, "error": "…"}`.