jithox-com Vat API

The Vat API from jithox-com — 1 operation(s) for vat.

Operations 1

POST /api/v1/vat/verify Check up to 20 EU VAT numbers against VIES #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/jithox-com:jithox-com-vat-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

jithox-com-vat-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Jithox REST — invoice checks for a backend Vat 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: Vat
paths:
  /api/v1/vat/verify:
    post:
      operationId: verifyVat
      summary: Check up to 20 EU VAT numbers against VIES
      description: Send up to 20 rows; the answer has one row per input row, in order. Branch on rows[].verdict. The whole call is bounded at 40000 ms; rows VIES did not answer in time come back unavailable and are listed in result.retry.indexes. Re-sending the same rows with the same x-jithox-idempotency-key is charged once.
      security:
      - jithoxConnection: []
      parameters:
      - name: x-jithox-idempotency-key
        in: header
        required: false
        description: 'Optional. 8–100 characters of A–Z a–z 0–9 . _ : -. The same key with the same rows is charged once.'
        schema:
          type: string
          pattern: ^[A-Za-z0-9._:-]{8,100}$
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifyRequest'
            example:
              rows:
              - reference: C-001
                vatId: BE0403170701
              requesterVatId: BE0403170701
      responses:
        '200':
          description: The check ran. Branch per row on `verdict`. `billing` says what was charged.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VerifyResponse'
        '400':
          description: The request could not be read (not JSON, no rows, a reference too long, a malformed idempotency key, a requesterVatId VIES would refuse). Nothing ran; nothing was charged.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListRefusal'
        '401':
          description: No credential, or not an active connection (unknown, revoked, expired). Nothing ran; nothing was charged.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
          headers:
            WWW-Authenticate:
              schema:
                type: string
              description: Bearer realm="jithox-connection"
        '402':
          description: The workspace's credits cannot cover the most these rows can cost. VIES was not asked; nothing was charged.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InsufficientCredits'
        '403':
          description: These rows can cost more than the per-call bound the person set on this connection. Nothing ran; nothing was charged.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BudgetExceeded'
        '413':
          description: More than 20 rows, or a body over 65536 bytes. Nothing ran; nothing was charged.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListRefusal'
        '429':
          description: Too many requests for this workspace. Nothing ran; nothing was charged.
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimited'
        '503':
          description: The connection store is not answering, so the credential cannot be checked. Nothing ran; nothing was charged.
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StoreUnavailable'
      x-jithox-pricing:
        tool: check_vat_list
        unit: answered_row
        pricePerUnitCredits: 1
        pricePerUnitEur: EUR 0.01
        maxCreditsPerCall: 20
        source: TOOL_PRICE_CREDITS.check_vat_list — the same price the check_vat_list MCP tool and the website charge.
      tags:
      - Vat
components:
  schemas:
    Billing:
      type: object
      properties:
        charged:
          type: boolean
          description: Whether this request moved credits.
        credits:
          type: integer
          minimum: 0
          description: Credits this delivery cost (1 credit = EUR 0.01).
        units:
          type: integer
          minimum: 0
          description: Rows VIES answered — what `credits` was computed from.
        pricePerUnitCredits:
          type: integer
          minimum: 0
        reason:
          type: string
        receiptRunId:
          type: string
          description: 'The id of the credit-ledger booking for this delivery. A reference, not a signed receipt: this route returns no signed or hash-bound receipt, and /plan lists the booking without this id.'
        balanceAfter:
          type: integer
          description: The workspace's credit balance after this charge (the trial credit left, when funding is trial_credit).
        funding:
          enum:
          - trial_credit
          description: 'Present only when the workspace''s one-time free trial credit paid for this delivery. Absent: the prepaid credits paid.'
      required:
      - charged
      - credits
      - units
      - pricePerUnitCredits
      - reason
      additionalProperties: false
    VatRow:
      type: object
      properties:
        index:
          type: integer
          minimum: 0
          description: Position in the request, from 0. Output row i is input row i.
        reference:
          type:
          - string
          - 'null'
          description: Your own label for the row, echoed.
        input:
          type: string
          description: The number as sent.
        normalized:
          type:
          - string
          - 'null'
          description: Upper case, separators removed; Greek numbers under VIES's prefix EL.
        countryCode:
          type:
          - string
          - 'null'
          description: ISO 3166-1 alpha-2 of the issuing member state.
        local:
          enum:
          - well_formed
          - empty
          - malformed
          - not_covered
          - duplicate
          description: What the free local check found.
        duplicateOf:
          type: integer
          minimum: 0
          description: 'For a duplicate: the index of the earlier row that carries the answer.'
        register:
          enum:
          - valid
          - invalid
          - unknown
          - not_run
          description: What the EU register (VIES) said. `unknown` = no answer; never folded into `invalid`.
        verdict:
          enum:
          - valid
          - invalid
          - unavailable
          - not_checked
          description: 'The one word to branch on. valid / invalid: VIES answered (charged). unavailable: VIES was asked and gave no answer — outage, rate limit, time ran out; free; the row is in result.retry.indexes. not_checked: VIES was not asked for this row (malformed, empty, not covered, duplicate); free.'
        registeredName:
          type: string
          description: 'The name VIES returned. Often absent: several member states never share it.'
        unknownReason:
          enum:
          - rate_limited
          - no_answer
          - not_reached
          - not_authorised
          - requester_rejected
          description: 'Why `unknown`. requester_rejected: the European Commission refused the requesterVatId sent with this call — a refusal about who asked, not about this number; send the row again without requesterVatId.'
        detail:
          type: string
          description: One sentence a bookkeeper can act on.
        checkedAt:
          type: string
          format: date-time
          description: When VIES answered. Only on valid and invalid.
        consultationNumber:
          type: string
          description: The European Commission's own consultation number (requestIdentifier) for this lookup. Only on a `valid` row, and only when a requester reached VIES (requesterVatId on this call). It is the Commission's record that this consultation took place at that moment, on the requester's name — not a signed Jithox receipt, and nothing more about the company.
        consultationRequester:
          type: string
          description: The requester VAT number the Commission recorded this consultation against. Only alongside consultationNumber.
        consultationAt:
          type: string
          format: date-time
          description: The Commission's own requestDate for the consultation, never our clock. Only alongside consultationNumber, and only when VIES gave one.
      required:
      - index
      - reference
      - input
      - normalized
      - countryCode
      - local
      - register
      - verdict
      - detail
      additionalProperties: false
    BudgetExceeded:
      type: object
      properties:
        ok:
          const: false
        error:
          type: object
          properties:
            code:
              const: budget_exceeded
            reason:
              const: per_call_budget_exceeded
            message:
              type: string
            requiredMinorUnits:
              type: integer
              minimum: 0
              description: The most these rows can cost, in euro cents.
            maxMinorUnitsPerCall:
              type: integer
              minimum: 0
              description: The bound the person set on this connection.
            currency:
              const: EUR
            manageAt:
              const: https://jithox.com/mcp/account#connection
          required:
          - code
          - reason
          - message
          - requiredMinorUnits
          - maxMinorUnitsPerCall
          - currency
          - manageAt
          additionalProperties: false
      required:
      - ok
      - error
      additionalProperties: false
    Pricing:
      type: object
      properties:
        localChecks:
          const: included
        registerCheck:
          type: string
        unit:
          const: answered_row
        pricePerUnitCredits:
          type: integer
          minimum: 0
        pricePerUnitEur:
          type: string
        maxCreditsPerCall:
          type: integer
          minimum: 0
        chargedWhen:
          type: string
        neverCharged:
          type: string
      required:
      - localChecks
      - registerCheck
      - unit
      - pricePerUnitCredits
      - pricePerUnitEur
      - maxCreditsPerCall
      - chargedWhen
      - neverCharged
      additionalProperties: false
    ListRefusal:
      type: object
      properties:
        ok:
          const: false
        schema_version:
          const: jx.vat-list-check/v1
        error:
          type: object
          properties:
            code:
              enum:
              - bad_request
              - no_rows
              - too_many_rows
              - reference_too_long
              - request_too_large
              - invalid_idempotency_key
              - requester_invalid
            message:
              type: string
            limit:
              type: object
              properties:
                name:
                  type: string
                max:
                  type: integer
                  minimum: 0
                actual:
                  type:
                  - integer
                  - 'null'
              required:
              - name
              - max
              - actual
              additionalProperties: false
            issues:
              type: array
              items:
                type: string
              description: 'For requester_invalid: what is wrong with requesterVatId.'
          required:
          - code
          - message
          additionalProperties: false
        limits:
          $ref: '#/components/schemas/Limits'
      required:
      - ok
      - schema_version
      - error
      additionalProperties: false
    Consultation:
      type: object
      description: Said once per answer, so an absent consultationNumber is never left to be guessed at. The number is the Commission's record of the lookup, not a signed receipt.
      properties:
        available:
          type: boolean
          description: Whether a `valid` row CAN carry a consultationNumber on this call.
        reason:
          enum:
          - not_requested
          - requester_rejected
          - malformed
          - not_a_requester_state
          description: 'Why not, when not; absent when available. not_requested: no requesterVatId was sent (and none is configured). requester_rejected: the European Commission refused the requesterVatId sent with this call. malformed / not_a_requester_state: the deployment''s configured fallback requester cannot be sent.'
        note:
          type: string
          description: One sentence saying exactly what the consultation number is and is not.
      required:
      - available
      - note
      additionalProperties: false
    VatTotals:
      type: object
      properties:
        rows:
          type: integer
          minimum: 0
        wellFormed:
          type: integer
          minimum: 0
        empty:
          type: integer
          minimum: 0
        malformed:
          type: integer
          minimum: 0
        notCovered:
          type: integer
          minimum: 0
        duplicate:
          type: integer
          minimum: 0
        valid:
          type: integer
          minimum: 0
        invalid:
          type: integer
          minimum: 0
        unknown:
          type: integer
          minimum: 0
        notRun:
          type: integer
          minimum: 0
      required:
      - rows
      - wellFormed
      - empty
      - malformed
      - notCovered
      - duplicate
      - valid
      - invalid
      - unknown
      - notRun
      additionalProperties: false
    VerifyRequest:
      type: object
      properties:
        rows:
          type: array
          minItems: 1
          maxItems: 20
          items:
            type: object
            properties:
              reference:
                type:
                - string
                - 'null'
                maxLength: 80
                description: Your own label, echoed back.
              vatId:
                type: string
                description: The VAT number as written, with its country prefix. Spaces, dots and dashes are fine.
            required:
            - vatId
            additionalProperties: false
        requesterVatId:
          type: string
          maxLength: 20
          description: Optional. YOUR OWN EU VAT number, with its country prefix (Greece as EL; XI cannot be a requester). A `valid` row then carries the European Commission's consultationNumber for that lookup, registered to you. Not a signed receipt. A value VIES would refuse is a 400 before anything runs or is charged; rows VIES refuses for this requester come back unknown (requester_rejected), never invalid, and cost nothing. Used for this call only, stored nowhere.
      required:
      - rows
      additionalProperties: false
    StoreUnavailable:
      type: object
      properties:
        ok:
          const: false
        error:
          type: object
          properties:
            code:
              const: connection_store_unavailable
            message:
              type: string
          required:
          - code
          - message
          additionalProperties: false
      required:
      - ok
      - error
      additionalProperties: false
    InsufficientCredits:
      type: object
      properties:
        ok:
          const: false
        error:
          type: object
          properties:
            code:
              const: insufficient_credits
            message:
              type: string
            requiredCredits:
              type: integer
              minimum: 0
              description: 'The most these rows can cost: price × well-formed rows.'
            pricePerAnsweredRowCredits:
              type: integer
              minimum: 0
            topUpUrl:
              const: https://jithox.com/plan
              description: Where a person adds credits to this workspace.
          required:
          - code
          - message
          - requiredCredits
          - pricePerAnsweredRowCredits
          - topUpUrl
          additionalProperties: false
      required:
      - ok
      - error
      additionalProperties: false
    VerifyResponse:
      type: object
      properties:
        ok:
          const: true
        result:
          type: object
          properties:
            ok:
              const: true
            schema_version:
              const: jx.vat-list-check/v1
            registerTier:
              type: boolean
              description: Whether VIES was asked for this request. False when no row was well-formed.
            rows:
              type: array
              items:
                $ref: '#/components/schemas/VatRow'
            totals:
              $ref: '#/components/schemas/VatTotals'
            answeredRows:
              type: integer
              minimum: 0
              description: 'valid + invalid: the rows VIES answered. This is what is billed.'
            retry:
              type: object
              description: The rows worth sending again (VIES gave no answer).
              properties:
                indexes:
                  type: array
                  items:
                    type: integer
                    minimum: 0
                advice:
                  type: string
              required:
              - indexes
              - advice
              additionalProperties: false
          required:
          - ok
          - schema_version
          - registerTier
          - rows
          - totals
          - answeredRows
          - retry
          additionalProperties: false
        source:
          type: object
          properties:
            register:
              const: EU VIES
          required:
          - register
          additionalProperties: false
        consultation:
          $ref: '#/components/schemas/Consultation'
        billing:
          $ref: '#/components/schemas/Billing'
        pricing:
          $ref: '#/components/schemas/Pricing'
        limits:
          $ref: '#/components/schemas/Limits'
      required:
      - ok
      - result
      - source
      - consultation
      - billing
      - pricing
      - limits
      additionalProperties: false
    Unauthorized:
      type: object
      properties:
        ok:
          const: false
        error:
          type: object
          properties:
            code:
              const: unauthorized
            reason:
              enum:
              - missing_credential
              - invalid_credential
            message:
              type: string
          required:
          - code
          - reason
          - message
          additionalProperties: false
        authorization:
          type: object
          properties:
            scheme:
              const: Bearer
            credentialPrefix:
              const: jxc_live_
            createAt:
              const: https://jithox.com/mcp/account#connection
              description: Where a person creates (and revokes) the credential.
            howToCreate:
              type: string
          required:
          - scheme
          - credentialPrefix
          - createAt
          - howToCreate
          additionalProperties: false
      required:
      - ok
      - error
      - authorization
      additionalProperties: false
    RateLimited:
      type: object
      description: The shared rate limiter's answer. See the Retry-After header.
      properties:
        error:
          const: rate_limited
        retryAfterSeconds:
          type: integer
          minimum: 0
      required:
      - error
      - retryAfterSeconds
      additionalProperties: false
    Limits:
      type: object
      description: The limits every answer repeats.
      properties:
        maxRowsPerCall:
          type: integer
          minimum: 0
        maxReferenceChars:
          type: integer
          minimum: 0
        maxVatIdChars:
          type: integer
          minimum: 0
        deadlineMs:
          type: integer
          minimum: 0
      required:
      - maxRowsPerCall
      - maxReferenceChars
      - maxVatIdChars
      - deadlineMs
      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.