Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Jithox REST — checks for a backend Invoice API
version: 1.2.0
summary: EU VAT numbers (VIES), Peppol receivers and IBANs, checked from a backend with a connection credential a person creates.
description: 'A person creates a Jithox connection at https://jithox.com/mcp/account#connection and gives its secret (jxc_live_…) to the backend, which sends it as a Bearer token on every route except POST /api/invoice/review. POST /api/v1/vat/verify checks EU VAT numbers against VIES. Price: 1 credits (EUR 0.01) per row VIES answered (valid or invalid), charged once per delivery from the workspace''s prepaid credits; credits are added at https://jithox.com/plan. New workspaces get 100 free VAT checks against the EU VIES register, once per workspace, no card. They pay for VAT checks on the REST API and on the Jithox MCP at https://jithox.com/api/mcp, not for the E-Invoice server''s tools. Granted when the workspace creates a connection and has had no trial before, within a limit per network and per day. Bought credits are spent first. A company lookup by VAT number on the Jithox MCP uses 2 of the 100. Without a trial, or once it is used up, the normal 402 applies. A row VIES did not answer (unavailable), a malformed or duplicate number, or a number VIES does not cover costs nothing. The answer carries the ledger booking id (billing.receiptRunId), which is not a signed receipt; no signed or hash-bound receipt is returned. With the optional requesterVatId (your own EU VAT number), a valid row also carries the European Commission''s consultation number for that lookup — the Commission''s record that it took place, not a receipt from Jithox. Not legal or tax advice: VIES states whether a number is registered for intra-EU trade at the moment it answered. The other routes are the MCP tools of the same name over plain HTTP, with the same answer: POST /api/v1/peppol/participant (lookup_peppol_participant, free); POST /api/v1/iban/verify (verify_iban, free); POST /api/v1/payment/preflight (preflight_payment, free). POST /api/invoice/review checks one invoice before it is sent or paid; it is free and needs no credential. No route returns a signed or hash-bound payment receipt. With a signing key configured, POST /api/v1/payment/preflight also return `evidence`: a signed statement of the verdict and the checks (Ed25519 compact JWS), verifiable offline against https://jithox.com/.well-known/jwks.json or at https://jithox.com/api/v1/evidence/verify. It proves what Jithox decided, not that the decision is right.'
contact:
url: https://jithox.com/rest-api
servers:
- url: https://jithox.com
tags:
- name: Invoice
paths:
/api/invoice/review:
post:
operationId: reviewInvoice
summary: Check one invoice before it is sent or paid — free, no account
description: 'Checks one invoice and says what to fix: the Peppol field contract, the arithmetic (line totals and the stated total recomputed), the structure and check digits of the payment IBAN, the Peppol BIS rules, and a UBL 2.1 export that must parse. The local checks are free and need no account. A Jithox connection secret is not read by this route. Without a signed-in jithox.com session the EU VIES register is not asked: supplier_vat and customer_vat come back skipped (never pass), verified is false, and hasUnknowns is true whenever the invoice carries a VAT number. With a signed-in session and enough credits the register is asked too, and charged only when it answers. The review_invoice MCP tool on /api/mcp runs the same review with the register included; it needs a token. A PDF, scan or image is refused by name: there is no OCR. Read-only: nothing is sent, filed, paid or signed, and the answer is technical evidence, not a legal or tax opinion.'
security: []
parameters:
- name: x-jithox-idempotency-key
in: header
required: false
description: 'Optional. 8–100 characters of A–Z a–z 0–9 . _ : -. Only matters for a signed-in, charged run: the same key with the same invoice is charged once.'
schema:
type: string
pattern: ^[A-Za-z0-9._:-]{8,100}$
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/InvoiceReviewRequest'
example:
invoice:
invoiceNumber: INV-2026-0042
issueDate: '2026-09-17'
dueDate: '2026-10-17'
currency: EUR
buyerReference: PO-2026-0042
supplier:
name: Jithox BV
countryCode: BE
vatId: BE0203201340
endpointId: '0203201340'
endpointScheme: 0208
street: Kerkstraat 1
city: Gent
postalZone: '9000'
customer:
name: Acme Trading NV
countryCode: BE
vatId: BE0417497106
endpointId: 0417497106
endpointScheme: 0208
street: Havenlaan 12
city: Antwerpen
postalZone: '2000'
lines:
- description: Consultancy, June
quantity: 10
unitPrice: 120
vatPercent: 21
lineTotal: 1200
- description: Hosting, June
quantity: 1
unitPrice: 75
vatPercent: 21
lineTotal: 75
payment:
iban: BE68 5390 0754 7034
responses:
'200':
description: 'The review ran, also when the invoice has blockers. Branch on review.readyToSend and review.hasUnknowns, and read each check''s status: a skipped check did not run.'
content:
application/json:
schema:
$ref: '#/components/schemas/InvoiceReviewResponse'
'400':
description: The body is not JSON, is a string (a document instead of invoice fields), or x-jithox-idempotency-key is malformed. Nothing was checked and nothing was charged.
content:
application/json:
schema:
$ref: '#/components/schemas/InvoiceReviewRefusal'
'413':
description: A body over 262144 characters. Nothing was checked and nothing was charged.
content:
application/json:
schema:
$ref: '#/components/schemas/InvoiceReviewTooLarge'
x-jithox-pricing:
localChecks: free
registerCheckCredits: 8
registerCheckChargedWhen: a signed-in workspace's VIES lookup reached a verdict
source: TOOL_PRICE_CREDITS.review_invoice, the one price book.
tags:
- Invoice
components:
schemas:
InvoiceReviewFinding:
type: object
properties:
code:
type: string
severity:
enum:
- blocker
- warning
- info
description: A blocker stops sending.
field:
type: string
description: Dotted path into the input, when the finding belongs to one field.
what:
type: string
fix:
type: string
rule:
type: string
description: The Peppol / EN 16931 rule id, when the finding comes from that rule set.
required:
- code
- severity
- what
- fix
additionalProperties: false
InvoiceReviewRequest:
description: 'The invoice fields as JSON: wrapped as {"invoice": {...}}, or the bare invoice object.'
anyOf:
- type: object
properties:
invoice:
$ref: '#/components/schemas/InvoiceReviewInvoice'
required:
- invoice
additionalProperties: false
- $ref: '#/components/schemas/InvoiceReviewInvoice'
InvoiceReview:
type: object
properties:
inputFormat:
const: structured_invoice
invoiceNumber:
type:
- string
- 'null'
next_checks:
type: array
items:
type: object
properties:
tool:
const: check_peppol_ready
reason:
type: string
required:
- tool
- reason
additionalProperties: false
description: Suggested receiver check, not executed by this review; present when the invoice has a lookupable receiver address.
checks:
type: array
items:
$ref: '#/components/schemas/InvoiceReviewCheck'
findings:
type: array
items:
$ref: '#/components/schemas/InvoiceReviewFinding'
readyToSend:
type: boolean
description: No blocker, and the Peppol export was built and parses.
hasUnknowns:
type: boolean
description: A check could not reach a verdict, or a VAT number was not checked against the register.
totals:
oneOf:
- $ref: '#/components/schemas/InvoiceReviewTotals'
- type: 'null'
draft:
oneOf:
- type: object
description: A draft message. Nothing has been sent.
properties:
kind:
const: email_draft
to:
type:
- string
- 'null'
subject:
type: string
body:
type: string
required:
- kind
- to
- subject
- body
additionalProperties: false
- type: 'null'
export:
oneOf:
- type: object
properties:
filename:
type: string
mediaType:
const: application/xml
ubl:
type: string
description: UBL 2.1 / Peppol BIS Billing 3.0.
required:
- filename
- mediaType
- ubl
additionalProperties: false
- type: 'null'
required:
- inputFormat
- invoiceNumber
- checks
- findings
- readyToSend
- hasUnknowns
- totals
- draft
- export
additionalProperties: false
InvoiceReviewTotals:
type: object
properties:
currency:
type: string
lineExtensionAmount:
type: string
taxExclusiveAmount:
type: string
taxAmount:
type: string
taxInclusiveAmount:
type: string
payableAmount:
type: string
taxSubtotals:
type: array
items:
type: object
properties:
taxCategory:
type: string
percent:
type: number
taxableAmount:
type: string
taxAmount:
type: string
required:
- taxCategory
- percent
- taxableAmount
- taxAmount
additionalProperties: false
required:
- currency
- lineExtensionAmount
- taxExclusiveAmount
- taxAmount
- taxInclusiveAmount
- payableAmount
- taxSubtotals
additionalProperties: false
InvoiceReviewTooLarge:
type: object
properties:
error:
type: object
properties:
code:
const: invoice_too_large
message:
type: string
required:
- code
- message
additionalProperties: false
required:
- error
additionalProperties: false
InvoiceReviewRefusal:
description: Either a review that refuses the input by name, or an error object.
oneOf:
- type: object
properties:
review:
$ref: '#/components/schemas/InvoiceReview'
verified:
const: false
required:
- review
- verified
additionalProperties: false
- type: object
properties:
error:
type: object
properties:
code:
const: invalid_idempotency_key
message:
type: string
required:
- code
- message
additionalProperties: false
required:
- error
additionalProperties: false
InvoiceReviewResponse:
type: object
properties:
review:
$ref: '#/components/schemas/InvoiceReview'
verified:
type: boolean
description: 'Whether a VAT number was sent to the EU VIES register on this run, whatever it answered. False when nothing was sent: signed out, not enough credits, no VAT number on the invoice, or a number the lookup refused before the register.'
register:
type: object
properties:
ran:
type: boolean
description: 'The same fact as verified: a VAT number was sent to the EU VIES register on this run.'
notRunBecause:
enum:
- signed_out
- insufficient_credits
- nothing_to_look_up
- null
description: 'Why the register was not asked, as a value to branch on; null when it ran. nothing_to_look_up: the invoice has no VAT number the lookup could take (none, or every one refused before the register), so neither signing in nor topping up would get the register asked.'
required:
- ran
- notRunBecause
additionalProperties: false
billing:
type: object
properties:
charged:
type: boolean
credits:
type: integer
minimum: 0
reason:
type: string
receiptRunId:
type: string
description: The id of the credit-ledger booking. A reference, not a signed receipt.
balanceAfter:
type: number
required:
- charged
- credits
- reason
additionalProperties: false
pricing:
type: object
properties:
localChecks:
const: included
registerCheck:
type: string
toolCredits:
type: integer
minimum: 0
note:
type: string
required:
- localChecks
- registerCheck
- toolCredits
- note
additionalProperties: false
required:
- review
- verified
- register
- billing
- pricing
additionalProperties: false
InvoiceReviewInvoice:
type: object
properties:
invoiceNumber:
type: string
minLength: 1
maxLength: 80
description: Human-readable invoice number, e.g. "INV-2026-0001".
issueDate:
type: string
pattern: ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
description: Issue date (YYYY-MM-DD).
dueDate:
description: Optional payment due date (YYYY-MM-DD).
type: string
pattern: ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
currency:
description: ISO 4217 currency code (uppercase). Peppol requires one (BR-05); the review fills nothing in, so an invoice without one fails BR-05.
type: string
enum:
- EUR
- USD
- GBP
- CHF
- DKK
- SEK
- NOK
- PLN
- CZK
- HUF
- RON
- BGN
- ISK
- JPY
- CNY
- INR
- CAD
- AUD
- NZD
- BRL
- MXN
- ZAR
- AED
- SAR
- SGD
- HKD
- KRW
- TRY
- ILS
- KWD
- BHD
- OMR
buyerReference:
description: Buyer reference (BT-10), e.g. a PO or cost-centre code.
type: string
minLength: 1
maxLength: 120
orderReference:
description: Purchase order reference (BT-13). Peppol requires this OR a buyer reference.
type: string
minLength: 1
maxLength: 120
note:
description: Free-text invoice note.
type: string
minLength: 1
maxLength: 1000
supplier:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 200
description: Trading / display name of the party.
countryCode:
type: string
enum:
- AT
- BE
- BG
- HR
- CY
- CZ
- DK
- EE
- FI
- FR
- DE
- GR
- HU
- IE
- IT
- LV
- LT
- LU
- MT
- NL
- PL
- PT
- RO
- SK
- SI
- ES
- SE
- IS
- LI
- 'NO'
- GB
- CH
- US
- CA
- MX
- BR
- AU
- NZ
- JP
- CN
- IN
- KR
- SG
- HK
- AE
- SA
- ZA
- TR
- IL
- UA
- RS
description: ISO 3166-1 alpha-2 country code (uppercase), e.g. BE.
vatId:
description: Legal / VAT registration id, e.g. "BE0123456789".
type: string
minLength: 1
maxLength: 60
registrationName:
description: Legal registration name. Defaults to the trading name.
type: string
minLength: 1
maxLength: 200
endpointId:
description: Peppol participant endpoint identifier, e.g. a GLN.
type: string
minLength: 1
maxLength: 60
endpointScheme:
description: 'Endpoint scheme id (EAS code), e.g. "0208" for a Belgian enterprise number or "0088" for a GLN. Nothing is filled in for the review: an endpointId without a scheme fails PEPPOL-EN16931-CL008. The export writes "0088" when it is omitted.'
type: string
minLength: 1
maxLength: 10
street:
description: Street name and number.
type: string
minLength: 1
maxLength: 200
city:
description: City / town name.
type: string
minLength: 1
maxLength: 100
postalZone:
description: Postal / ZIP code.
type: string
minLength: 1
maxLength: 20
iban:
description: IBAN written on the invoice. Checked for structure and check digits; ownership and existence are not verified.
type: string
maxLength: 100
required:
- name
- countryCode
description: Seller / accounting supplier party, including an optional IBAN for the payment check.
customer:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 200
description: Trading / display name of the party.
countryCode:
type: string
enum:
- AT
- BE
- BG
- HR
- CY
- CZ
- DK
- EE
- FI
- FR
- DE
- GR
- HU
- IE
- IT
- LV
- LT
- LU
- MT
- NL
- PL
- PT
- RO
- SK
- SI
- ES
- SE
- IS
- LI
- 'NO'
- GB
- CH
- US
- CA
- MX
- BR
- AU
- NZ
- JP
- CN
- IN
- KR
- SG
- HK
- AE
- SA
- ZA
- TR
- IL
- UA
- RS
description: ISO 3166-1 alpha-2 country code (uppercase), e.g. BE.
vatId:
description: Legal / VAT registration id, e.g. "BE0123456789".
type: string
minLength: 1
maxLength: 60
registrationName:
description: Legal registration name. Defaults to the trading name.
type: string
minLength: 1
maxLength: 200
endpointId:
description: Peppol participant endpoint identifier, e.g. a GLN.
type: string
minLength: 1
maxLength: 60
endpointScheme:
description: 'Endpoint scheme id (EAS code), e.g. "0208" for a Belgian enterprise number or "0088" for a GLN. Nothing is filled in for the review: an endpointId without a scheme fails PEPPOL-EN16931-CL008. The export writes "0088" when it is omitted.'
type: string
minLength: 1
maxLength: 10
street:
description: Street name and number.
type: string
minLength: 1
maxLength: 200
city:
description: City / town name.
type: string
minLength: 1
maxLength: 100
postalZone:
description: Postal / ZIP code.
type: string
minLength: 1
maxLength: 20
email:
description: Customer e-mail address used only as the recipient of the returned draft; this tool sends nothing.
type: string
maxLength: 320
required:
- name
- countryCode
description: Buyer / accounting customer party, including an optional draft e-mail recipient.
lines:
minItems: 1
maxItems: 500
type: array
items:
type: object
properties:
description:
type: string
minLength: 1
maxLength: 500
description: Description of the goods or service for this line.
quantity:
type: number
exclusiveMinimum: 0
maximum: 1000000
description: Quantity invoiced for this line.
unitPrice:
type: number
minimum: 0
maximum: 100000000
description: Price per unit, excluding VAT.
vatPercent:
description: 'VAT rate as a percentage (0–100). Nothing is filled in for the review: a line without a rate, on an invoice that states a VAT total other than 0, blocks it. The export writes 0 % for a line without one.'
type: number
minimum: 0
maximum: 100
unitCode:
description: UN/ECE Rec 20 unit code, e.g. "HUR". Nothing is filled in for the review; the export writes "EA" (each) when it is omitted.
type: string
minLength: 1
maxLength: 10
taxCategory:
description: Override the derived UNCL5305 VAT category. Omit to derive S (rated) or Z (zero-rated) automatically from vatPercent.
type: string
enum:
- S
- Z
- E
- AE
- K
- G
- O
- L
- M
lineTotal:
description: Caller-stated line total excluding VAT, compared with quantity × unit price by this review.
type: number
lineNetAmount:
description: Caller-stated line total excluding VAT (BT-131), used by the shared Peppol arithmetic rules.
type: number
required:
- description
- quantity
- unitPrice
description: Invoice lines, including optional caller-stated amounts that the review compares.
payment:
description: Payment instruction carried by the invoice, when it names an IBAN.
type: object
properties:
iban:
description: IBAN written on the invoice. Checked for structure and check digits; ownership and existence are not verified.
type: string
maxLength: 100
totalWithoutVat:
description: Caller-stated invoice total excluding VAT (BT-109), used by the arithmetic rule checks.
type: number
totalVat:
description: Caller-stated total VAT (BT-110), used by the arithmetic rule checks.
type: number
totalWithVat:
description: Caller-stated invoice total including VAT (BT-112), used by the arithmetic rule checks.
type: number
required:
- invoiceNumber
- issueDate
- supplier
- customer
- lines
InvoiceReviewCheck:
type: object
properties:
id:
enum:
- structure
- arithmetic
- payment_details
- supplier_vat
- customer_vat
- peppol
- peppol_receiver
label:
type: string
status:
enum:
- pass
- fail
- unknown
- skipped
description: skipped means the check did not run; it is never a pass.
source:
enum:
- local
- eu_vies
- peppol_sml
detail:
type: string
consultationNumber:
type: string
description: The European Commission's own number for this VIES consultation, on a passed VAT check when a requester is configured.
consultationRequester:
type: string
consultationAt:
type: string
required:
- id
- label
- status
- source
- detail
additionalProperties: false
securitySchemes:
jithoxConnection:
type: http
scheme: bearer
description: A Jithox connection secret (jxc_live_…). A person signs in at https://jithox.com/mcp/account#connection, creates a connection and copies the secret (shown once); the same page revokes it. It bills that person's workspace.