Skip to content

REST API Labs

Check EU VAT numbers from your backend, over plain HTTP

One route: POST /api/v1/vat/verify. Send up to 20 VAT numbers; each row comes back valid, invalid or unavailable from the EU VIES register. Two more checks have a route, listed below; everything else is MCP.

Labs. The route is tested in our suite; it has not yet run against the real register on this website, and nobody has been charged through it.

  1. 1 · A person creates the key

    Sign in, open Account → Connection, create a connection and copy its secret (jxc_live_…, shown once). The same page revokes it.

  2. 2 · Your backend calls

    Send it as Authorization: Bearer. No browser, no MCP client. The person approves; the backend or agent runs.

  3. 3 · You pay per answer

    1 credits (EUR 0.01) for each row VIES answered. A row VIES did not answer (down, busy, timed out) costs 0 and is listed for a retry.

    New workspaces get 100 free VAT checks against the EU VIES register, once per workspace, no card.

curl

# requesterVatId: YOUR OWN EU VAT number (optional) — a valid row then carries the EU's consultation number, on your name
curl -s -X POST https://jithox.com/api/v1/vat/verify \
  -H "authorization: Bearer $JITHOX_CONNECTION_SECRET" \
  -H 'content-type: application/json' \
  -H 'x-jithox-idempotency-key: invoice-2026-0917-C-001' \
  -d '{"rows":[{"reference":"C-001","vatId":"BE0403170701"}],"requesterVatId":"BE0417497106"}'
C# (.NET 8, HttpClient)
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;

// The connection secret (jxc_live_…) that a person created at https://jithox.com/mcp/account#connection
var secret = Environment.GetEnvironmentVariable("JITHOX_CONNECTION_SECRET")
             ?? throw new InvalidOperationException("Set JITHOX_CONNECTION_SECRET");

using var http = new HttpClient { BaseAddress = new Uri("https://jithox.com"), Timeout = TimeSpan.FromSeconds(60) };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", secret);

using var request = new HttpRequestMessage(HttpMethod.Post, "/api/v1/vat/verify")
{
    Content = JsonContent.Create(new
    {
        rows = new[] { new { reference = "C-001", vatId = "BE0403170701" } },
        // Optional: YOUR OWN VAT number with its country prefix (e.g. BE0417497106). Every valid row then carries the
        // European Commission's VIES consultation number, in your name. Empty or null = no number.
        requesterVatId = Environment.GetEnvironmentVariable("JITHOX_REQUESTER_VAT_ID"),
    }),
};
// Optional: the same key with the same rows is charged once.
request.Headers.Add("x-jithox-idempotency-key", "invoice-2026-0917-C-001");

using var response = await http.SendAsync(request);
using var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
var root = doc.RootElement;

switch ((int)response.StatusCode)
{
    case 200:
        foreach (var row in root.GetProperty("result").GetProperty("rows").EnumerateArray())
        {
            var verdict = row.GetProperty("verdict").GetString(); // valid | invalid | unavailable | not_checked
            Console.WriteLine($"{row.GetProperty("input").GetString()}: {verdict} — {row.GetProperty("detail").GetString()}");
            // "unavailable" is a VIES outage, not a verdict on the number: send it again later, it cost nothing.
            if (row.TryGetProperty("consultationNumber", out var nr)) // only on valid, only with requesterVatId
                Console.WriteLine($"  VIES consultation number {nr.GetString()} in the name of {row.GetProperty("consultationRequester").GetString()}");
        }
        var consultation = root.GetProperty("consultation");
        if (!consultation.GetProperty("available").GetBoolean())
            Console.WriteLine(consultation.GetProperty("note").GetString()); // e.g. not_requested: no requesterVatId was sent
        var billing = root.GetProperty("billing");
        Console.WriteLine($"credits: {billing.GetProperty("credits").GetInt32()} (ledger ref, not a receipt: " +
                          $"{(billing.TryGetProperty("receiptRunId", out var r) ? r.GetString() : "-")})");
        break;
    case 400: // e.g. requester_invalid: requesterVatId is not a valid EU VAT number — nothing ran, nothing was charged
        Console.WriteLine(root.GetProperty("error").GetProperty("message").GetString());
        break;
    case 401: // missing or invalid secret — a person creates one at authorization.createAt
        Console.WriteLine(root.GetProperty("authorization").GetProperty("createAt").GetString());
        break;
    case 402: // not enough credits — a person tops up at error.topUpUrl
        Console.WriteLine(root.GetProperty("error").GetProperty("topUpUrl").GetString());
        break;
    case 403: // per-call limit on this connection — send fewer rows or raise the limit
    case 429: // rate limit — wait Retry-After seconds
    case 503: // the connection store does not answer — wait Retry-After seconds
    default:
        Console.WriteLine($"{(int)response.StatusCode} {root}");
        break;
}

Credits are prepaid on the account (1 credit = 1 euro cent). Without enough, the call answers 402 with the top-up link and VIES is not asked. Every status code and field: openapi.json.

Same key, two more checks

Each answers exactly what the MCP tool of the same name answers. The request body is the tool's arguments.

  • POST /api/v1/peppol/participant · Free · MCP tool lookup_peppol_participant

    Can this customer receive a Peppol e-invoice today, and if the send still fails, whose problem is it?

  • POST /api/v1/iban/verify · Free · MCP tool verify_iban

    Check an IBAN's structure and check digits (ISO 13616, ISO 7064), offline

  • POST /api/v1/payment/preflight · Free · MCP tool preflight_payment

    Before a payment: compare what the person approved with what is about to be paid, and run the rail's checks

Building an AI agent instead?

Use MCP: https://jithox.com/api/mcp. The tool check_vat_list runs the same check at the same price. Connect your AI

What it is not

  • Not a Peppol Access Point. It sends no invoices.
  • No tax advice: it reports what VIES says.
  • No signed receipt; the answer carries a ledger reference only.