Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: W System E Invoice API
description: 'EU e-invoicing and business-data API: VAT/VIES and EORI validation, KYB, sanctions screening, EN 16931 e-invoice validation, Peppol lookup. Pay per call via x402 or use an API key; MCP server available.
**Endpoints:** **EU VAT number validation (VIES)**, **EORI validation (EC EOS)**, **official company-registry lookup**, **sanctions screening (EU, UN, OFAC SDN, UK)**, **one-call KYB**, a **due-diligence report**, and **EU e-invoicing**: validate (EN 16931, XRechnung; UBL, CII, ZUGFeRD/Factur-X PDF), create (JSON -> UBL), ''can I e-invoice this company?'' (VIES + Peppol + mandates), and **SANDBOX send** (verify -> create -> route -> transport -> signed evidence; transport = mock, or a real submission through partner Peppol access-point sandboxes: Recommand playground or e-invoice.be sandbox). Live Peppol sending is not generally available; it opens per company once our access-point partner has activated it.
* **No API key, no signup:** every client IP gets 20 free calls/day across all endpoints (header `X-Free-Remaining`).
* **Beyond the free tier:** pay per call with **x402** (USDC on Base, HTTP 402 flow): $0.01 per single check, $0.10 per batch request, $0.045 per KYB check; e-invoice validate $0.03, parse $0.01, create $0.08, route $0.02; due-diligence report $0.49. Or use an API key.
* **Live Peppol onboarding (API key):** `GET /einvoice/mandate-terms` returns the W System Peppol mandate terms (https://wsystem.dev/legal/peppol-mandate-terms, DPA: https://wsystem.dev/legal/dpa); `POST /einvoice/mandates` records the company''s click-through mandate with a signed receipt.
* **MCP:** the same tools are available to AI agents at `https://api.wsystem.dev/mcp/` (streamable HTTP).
* VIES/EOS are official European Commission services; this API adds retries when a member state is unavailable, caching,
batch endpoints, audit consultation numbers and a stable JSON shape. Docs: https://wsystem.dev/llms.txt'
contact:
name: W System
url: https://wsystem.dev/
license:
name: Proprietary API; MCP server code MIT
url: https://github.com/wsystemdev/eu-business-data-mcp
version: 0.3.61
x-guidance: 'EU business verification for agents. GET /verify?vat=IE6388047V validates an EU VAT number via official VIES (name, address, consultation number as audit proof). GET /eori?eori=SE5560360793 validates an EU EORI number. GET /company?q=552032534&country=FR looks up official business registers. GET /sanctions/screen?name=... screens EU/UN/OFAC/UK lists. POST /kyb/check {"company":"FR40303265045"} returns a pass/review/fail KYB verdict. POST /einvoice/validate (raw UBL/CII XML or ZUGFeRD PDF body) checks EN 16931 + XRechnung rules; POST /einvoice/parse (same body) reads an incoming invoice into JSON (parties, totals, VAT, IBAN, lines; no validation); POST /einvoice/create turns JSON into a validated UBL invoice (example body: GET /einvoice/sample); GET /einvoice/route?id=BE0403170701 says whether/how to e-invoice a company; POST /ddreport returns a full due-diligence report. Batch POST variants take up to 100 items. First 20 calls/day per IP are free; after that pay per call with x402 (USDC on Base), or send an X-API-Key.'
servers:
- url: https://api.wsystem.dev
description: Production
tags:
- name: E-invoice
description: EU e-invoice validation (EN 16931, XRechnung; UBL, CII, ZUGFeRD/Factur-X PDF) and creation (JSON -> UBL)
paths:
/einvoice/mandate-terms:
get:
tags:
- E-invoice
summary: Get the Peppol mandate terms to show the signer
operationId: einvoiceMandateTerms
parameters:
- name: x-api-key
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: X-Api-Key
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/einvoice/mandates:
post:
tags:
- E-invoice
summary: Record a company's Peppol mandate (click-through acceptance)
operationId: createPeppolMandate
parameters:
- name: x-api-key
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: X-Api-Key
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MandateIn'
responses:
'201':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/einvoice/mandates/{mid}:
get:
tags:
- E-invoice
summary: Get one of your Peppol mandate records
operationId: getPeppolMandate
parameters:
- name: mid
in: path
required: true
schema:
type: string
title: Mid
- name: x-api-key
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: X-Api-Key
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/einvoice/mandates/{mid}/revoke:
post:
tags:
- E-invoice
summary: Revoke a Peppol mandate
operationId: revokePeppolMandate
parameters:
- name: mid
in: path
required: true
schema:
type: string
title: Mid
- name: x-api-key
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: X-Api-Key
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/einvoice/validate:
post:
tags:
- E-invoice
summary: Validate an EU e-invoice (EN 16931, XRechnung; UBL, CII, ZUGFeRD/Factur-X PDF)
description: 'Send the invoice as the raw request body (Content-Type application/xml or application/pdf), or JSON {"xml": "..."} / {"base64": ""}. Detects UBL Invoice/CreditNote or UN/CEFACT CII (also the XML embedded in a ZUGFeRD/Factur-X PDF), checks the XML schema and the official CEN EN 16931 Schematron rules, plus the KoSIT XRechnung 3.0 rules when the invoice is an XRechnung (or rules=xrechnung). Returns valid true/false and every error with its official rule ID (e.g. BR-CO-10), plain-English message, XPath location, business terms and a fix hint where known. When the seller is Slovak (UBL), it adds Slovak eFaktúra field checks written from the Financial Administration''s Peppol BIS transposition v1.13 (0245:DIČ endpoints, addresses, IČO, BT-33, BT-7, VATEX), as warnings with ruleset SK-FS, plus the invoice UUIDv5 cross-check in ''slovakia''. Norwegian sellers (UBL) get W System field checks from Norwegian law (org. no. mod-11, MVA suffix, ''Foretaksregisteret'' for AS/ASA/NUF, 0192 endpoints, buyer org. no., VAT rates) as warnings with ruleset NO-LAW and a ''norway'' block; not the EHF/Peppol NO-R schematron. Each error has error_class ''format'' (XML Schema) or ''business_rule'' (Schematron), with format_error_count and business_rule_error_count; for German invoices (seller or buyer DE, XRechnung or ZUGFeRD) ''germany.de_vat_status'' says how the BMF letter of 15 Oct 2026 reads the result (a business-rule error without a format error is in principle still an e-invoice for VAT). For French invoices (seller or buyer FR) ''france'' checks the supplier and client SIREN the 2026 reform requires (BT-30 / BT-47 with scheme 0002), suggests the SIREN from an FR VAT number when it is missing, and lists the French items it does not check (hint only; French XP Z12-012 rules not run). Peppol BIS 3 specific rules are not checked yet. Technical check, not tax advice. Free tier shared with other endpoints, then x402 $0.03.'
operationId: validateEinvoice
parameters:
- name: rules
in: query
required: false
schema:
type: string
description: auto | en16931 | xrechnung
default: auto
title: Rules
description: auto | en16931 | xrechnung
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
'402':
description: 'Payment Required: x402 v2 challenge (PAYMENT-REQUIRED header). Returned when the free tier is used up, or for a bare call without input.'
'429':
description: Free tier used up and x402 disabled
requestBody:
required: true
content:
application/xml:
schema:
type: string
application/pdf:
schema:
type: string
format: binary
application/json:
schema:
type: object
properties:
xml:
type: string
base64:
type: string
x-payment-info:
price:
mode: fixed
currency: USD
amount: '0.030000'
protocols:
- x402:
network: eip155:8453
asset: USDC
scheme: exact
freeTier: 20 calls/day per IP, no key
/einvoice/parse:
post:
tags:
- E-invoice
summary: Read an incoming EU e-invoice (UBL, CII, ZUGFeRD/Factur-X PDF) into JSON
description: 'Same input as /einvoice/validate: the raw invoice as the request body (application/xml or application/pdf), or JSON {"xml": "..."} / {"base64": ""}. Reads UBL Invoice/CreditNote or UN/CEFACT CII (also the XML embedded in a ZUGFeRD/Factur-X PDF) into one JSON shape for both syntaxes: invoice number (BT-1), issue and due dates, type code, currency, buyer reference (BT-10, e.g. Leitweg-ID), order/contract references, seller and buyer (name, VAT ID, tax number, legal registration ID, electronic address, postal address, contact), delivery, totals (BT-106..BT-115), VAT breakdown, payment (means code, IBAN, BIC, remittance information), invoice lines and attachment metadata. Values are returned as written (strings); empty fields are omitted. Reading does not check validity: call POST /einvoice/validate for the EN 16931 / XRechnung rules. Free tier shared with other endpoints, then x402 $0.01.'
operationId: parseEinvoice
requestBody:
content:
application/xml:
schema:
type: string
application/pdf:
schema:
type: string
format: binary
application/json:
schema:
properties:
xml:
type: string
base64:
type: string
type: object
required: true
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'402':
description: 'Payment Required: x402 v2 challenge (PAYMENT-REQUIRED header). Returned when the free tier is used up, or for a bare call without input.'
'429':
description: Free tier used up and x402 disabled
x-payment-info:
price:
mode: fixed
currency: USD
amount: '0.010000'
protocols:
- x402:
network: eip155:8453
asset: USDC
scheme: exact
freeTier: 20 calls/day per IP, no key
/einvoice/create:
post:
tags:
- E-invoice
summary: Create a valid EU e-invoice (UBL 2.1) from simple JSON
description: 'Turns JSON (seller, buyer, lines with VAT category/rate, payment) into a UBL 2.1 invoice or credit note in format en16931 (plain EN 16931), xrechnung (German XRechnung 3.0) or peppol-bis3 (Peppol BIS Billing 3.0 structure; Peppol-specific rules not checked yet). Totals and the VAT breakdown are computed for you; the result is validated before it is returned (valid, errors, xml). Optional: tax_point_date (BT-7), party company_id + company_id_scheme (BT-30/BT-47), seller legal_form (BT-33). Example body: GET /einvoice/sample. Free tier shared, then x402 $0.08.'
operationId: createEinvoice
requestBody:
content:
application/json:
schema:
additionalProperties: true
type: object
title: Body
required: true
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
'402':
description: 'Payment Required: x402 v2 challenge (PAYMENT-REQUIRED header). Returned when the free tier is used up, or for a bare call without input.'
'429':
description: Free tier used up and x402 disabled
x-payment-info:
price:
mode: fixed
currency: USD
amount: '0.080000'
protocols:
- x402:
network: eip155:8453
asset: USDC
scheme: exact
freeTier: 20 calls/day per IP, no key
/einvoice/route:
get:
tags:
- E-invoice
summary: '"Can I e-invoice this company?" VAT + Peppol + country mandate lookup'
description: 'id: an EU VAT number (e.g. BE0403170701) or a Peppol participant id (e.g. 0208:0403170701). Returns the VIES VAT result, whether the company is on Peppol (participant id, BIS 3 invoice/credit note support; Peppol Directory first, then the Peppol SML/SMP lookup Access Points use, so participants without a Directory business card are found too; peppol.source = directory | smp, per-id results in peppol.ids_detail), the country''s B2B e-invoice mandate (dates, format, channel, source link) and the recommended format for POST /einvoice/create. NL, EE and LT companies are usually on Peppol under their registry id (0106 KvK, 0191, 0200), not the VAT number: if the VAT-based ids miss, the lookup also tries the registry id found from the VIES name (exact unique match, then a unique match with the legal form such as B.V./UAB ignored) and reports it in peppol.matched_via. Free tier shared, then x402 $0.02.'
operationId: einvoiceRoute
parameters:
- name: id
in: query
required: true
schema:
type: string
examples:
- BE0403170701
title: Id
- name: requester
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Requester
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
'402':
description: 'Payment Required: x402 v2 challenge (PAYMENT-REQUIRED header). Returned when the free tier is used up, or for a bare call without input.'
'429':
description: Free tier used up and x402 disabled
x-payment-info:
price:
mode: fixed
currency: USD
amount: '0.020000'
protocols:
- x402:
network: eip155:8453
asset: USDC
scheme: exact
freeTier: 20 calls/day per IP, no key
/fr/pa-registry:
get:
tags:
- E-invoice
summary: Is this platform on France's official list of Plateformes Agréées (PA)? (free)
description: 'name: platform or company name (e.g. Pennylane); website: its site (e.g. https://www.acubeapi.com/). Checks the DGFiP lists published on impots.gouv.fr: operators registered as PA (all conditions incl. interoperability tests, with registration date) and operators awaiting interoperability tests. Returns on_official_list, status (approved | awaiting_interop_tests | possible_match | not_found), scored matches, list date and the official source. Use it for supplier due diligence before the French e-invoicing reform (receive from 1 Sep 2026, SMEs issue from 1 Sep 2027). Unofficial copy; the official lists prevail. Free.'
operationId: frPaRegistry
parameters:
- name: name
in: query
required: false
schema:
type: string
examples:
- Pennylane
default: ''
title: Name
- name: website
in: query
required: false
schema:
type: string
default: ''
title: Website
- name: limit
in: query
required: false
schema:
type: integer
maximum: 20
minimum: 1
default: 5
title: Limit
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/einvoice/sample:
get:
tags:
- E-invoice
summary: Example JSON body for POST /einvoice/create (free)
operationId: einvoiceSample
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
/einvoice/send:
post:
tags:
- E-invoice
summary: 'SANDBOX: verify buyer -> create -> validate -> route -> transmit (mock or…'
description: 'One call for the whole e-invoice flow. Body: {"invoice": , "mode": "sandbox", "transport": "mock"}. Steps: VIES check of buyer.vat_id (invalid VAT stops the flow), sanctions screen of the buyer name, EN 16931 UBL creation + validation (invalid stops the flow), route lookup (Peppol Directory, country mandate, France PPF), transmission via a pluggable transport, and an Ed25519-signed evidence receipt (JWS; public key at GET /einvoice/evidence-key). SANDBOX ONLY. transport: ''mock'' (default; transmits nothing), ''recommand'' or ''e-invoice-be'' (the validated Peppol BIS 3 UBL is really submitted to that Peppol access point''s sandbox/playground and the partner document id is returned and signed into the receipt; it is addressed to W System''s own sandbox company, never to the buyer, and does not reach the production Peppol network; transmission.transmitted stays false). Partner transports switch invoice.format to peppol-bis3. mode=live sends over production Peppol via e-invoice.be and needs X-API-Key, an active Peppol mandate for invoice.seller.vat_id recorded with that key, W System KYC approval and a provisioned sending account (403 names what is missing); it returns 501 while live sending is switched off. Free tier shared, then x402 $0.08 (same as create).'
operationId: sendEinvoice
requestBody:
content:
application/json:
schema:
additionalProperties: true
type: object
title: Body
required: true
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
'402':
description: 'Payment Required: x402 v2 challenge (PAYMENT-REQUIRED header). Returned when the free tier is used up, or for a bare call without input.'
'429':
description: Free tier used up and x402 disabled
x-payment-info:
price:
mode: fixed
currency: USD
amount: '0.080000'
protocols:
- x402:
network: eip155:8453
asset: USDC
scheme: exact
freeTier: 20 calls/day per IP, no key
/einvoice/evidence-key:
get:
tags:
- E-invoice
summary: Public key (JWK) for verifying /einvoice/send evidence receipts (free)
operationId: einvoiceEvidenceKey
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
/einvoice/usage:
get:
tags:
- E-invoice
summary: Aggregate e-invoice usage counts for the current UTC month (free; no PII)
description: Day-90 gate helper. live_transmitted counts successful POST /einvoice/send with mode=live and transmission.transmitted=true. Sandbox sends are listed separately and do not count toward the gate. On api.wsystem.dev counts are stored in Postgres and survive redeploys (see the durable field).
operationId: einvoiceUsage
parameters:
- name: period
in: query
required: false
schema:
anyOf:
- type: string
- type: 'null'
description: UTC YYYY-MM; default = current month
title: Period
description: UTC YYYY-MM; default = current month
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
components:
schemas:
ValidationError:
properties:
loc:
items:
anyOf:
- type: string
- type: integer
type: array
title: Location
msg:
type: string
title: Message
type:
type: string
title: Error Type
input:
title: Input
ctx:
type: object
title: Context
type: object
required:
- loc
- msg
- type
title: ValidationError
MandateIn:
properties:
company_name:
type: string
maxLength: 200
minLength: 2
title: Company Name
examples:
- Muster GmbH
company_id:
type: string
maxLength: 40
minLength: 4
title: Company Id
description: EU VAT number or national enterprise number
examples:
- BE0403170701
peppol_id:
anyOf:
- type: string
maxLength: 80
- type: 'null'
title: Peppol Id
description: Optional Peppol participant id, e.g. 0208:0403170701
company_email:
type: string
maxLength: 200
title: Company Email
company_phone:
type: string
maxLength: 40
minLength: 5
title: Company Phone
signer_name:
type: string
maxLength: 120
minLength: 2
title: Signer Name
description: Person granting the mandate
signer_role:
type: string
maxLength: 120
minLength: 2
title: Signer Role
description: Their role, e.g. Managing Director
representative_name:
anyOf:
- type: string
maxLength: 120
- type: 'null'
title: Representative Name
description: Company representative (defaults to signer)
terms_version:
type: string
title: Terms Version
description: Version shown to the signer (GET /einvoice/mandate-terms)
terms_sha256:
type: string
title: Terms Sha256
description: sha256 of the exact terms text shown
accept:
type: boolean
title: Accept
description: 'Must be true: the signer ticked the acceptance box shown with the key terms (section 0)'
authority_confirmed:
type: boolean
title: Authority Confirmed
description: 'Must be true: signer confirms they may bind the company'
type: object
required:
- company_name
- company_id
- company_email
- company_phone
- signer_name
- signer_role
- terms_version
- terms_sha256
- accept
- authority_confirmed
title: MandateIn
HTTPValidationError:
properties:
detail:
items:
$ref: '#/components/schemas/ValidationError'
type: array
title: Detail
type: object
title: HTTPValidationError
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: 'Optional monthly-plan key. Without it: free tier, then x402 pay-per-call.'
externalDocs:
description: Guides, prices and MCP setup
url: https://wsystem.dev/llms-full.txt
x-discovery:
mcp: https://api.wsystem.dev/mcp/
serverCard: https://api.wsystem.dev/server-card
x402: https://api.wsystem.dev/.well-known/x402