Jsonpage ยท SIREN and SIRET API

API to check the SIREN and VAT numbers on your e-invoices

A French e-invoice carries the customer's SIREN and, depending on the case, the SIRET and the VAT number of both parties. A wrong number or a closed company is found too late, when the invoice is rejected.

01 / WHY

Why check the numbers before the invoice

This page shows how to check these numbers with an API call before issuing an invoice or booking a supplier's, with examples in curl, JavaScript, Python, PHP and Ruby.

E-invoicing is being introduced in France in stages: every company must be able to receive electronic invoices from September 2026, and issuing extends to SMEs and micro-businesses from September 2027. The official calendar is explained on impots.gouv.fr (in French). The customer's SIREN becomes an item on the invoice: see what e-invoicing changes for the SIREN and the list of mandatory items.

Two moments lend themselves to an automatic check. When issuing, you check the buyer: the number exists, the company is active, the SIRET and the VAT number point to the same company. When receiving, you check the seller before booking and paying, which also lowers the risk of a fake invoice.

What the API checksThe identification numbers and the company they point to. It does not check the invoice itself: its file format and content are a matter for your invoicing software or your platform.
02 / CALL

One call for the SIRET and the VAT number

The GET /v2/validate route takes a global identifier, a SIRET, a VAT number, or several at once. Each check comes back with its result, and valid is true only if every check passes. The API key goes in the X-API-Key header.

curl "https://api.jsonpage.com/v2/validate?siret=55203253400646&vat=FR27552032534" \
  -H "X-API-Key: $JSONPAGE_API_KEY"

Response (excerpt):

{
  "data": {
    "valid": true,
    "checks": [
      { "code": "siret_format", "ok": true, "value": "55203253400646" },
      { "code": "siret_key", "ok": true, "value": "55203253400646" },
      { "code": "vat_format", "ok": true, "value": "FR27552032534" },
      { "code": "identifiers_match", "ok": true, "value": "FR-552032534" },
      { "code": "company_exists", "ok": true, "value": "FR-552032534" },
      { "code": "company_active", "ok": true, "value": "active" },
      { "code": "vat_registered", "ok": true, "value": "valid" }
    ],
    "company": { "id": "FR-552032534", "name": "DANONE", "status": "active" }
  }
}

Spaces, dots and hyphens are ignored in the SIRET and the VAT number, so you do not need to clean the input before the call. VAT numbers of every European Union country are accepted, not only French ones.

03 / RESULT

Reading the result and deciding

Do not stop at valid: the checks list says which check failed, and so what to ask your counterpart.

ResultWhat it meansWhat to do before the invoice
valid: trueEvery check passed.Go ahead: issue or book the invoice.
siret_key or vat_format failedThe number was mistyped: a typo or a wrong check digit.Fix the number at the source, then run the check again.
company_active failedThe number exists, but the company or the establishment is closed.Ask the customer or supplier for a current number before going on.
identifiers_match failedThe SIRET and the VAT number do not point to the same company.Have the right pair of numbers confirmed.
vat unverifiableThe country's service did not answer: the number is not declared wrong.Try again later; do not treat it as invalid.

For a batch of numbers, for example a whole customer file before the first invoicing run, the Customer file page does the check without any programming, and the method to clean a customer file details the steps.

04 / CODE

Code examples

The same check in four languages, to plug into your invoicing software or ERP. The key is read from an environment variable: never put it in a page or in an application distributed to users.

JavaScript

async function checkParty(siret, vat) {
  const url = new URL("https://api.jsonpage.com/v2/validate");
  url.searchParams.set("siret", siret);
  url.searchParams.set("vat", vat);
  const res = await fetch(url, { headers: { "X-API-Key": process.env.JSONPAGE_API_KEY } });
  if (!res.ok) throw new Error("HTTP " + res.status);
  const { data } = await res.json();
  const failed = data.checks.filter((c) => !c.ok).map((c) => c.code);
  return { valid: data.valid, failed, company: data.company };
}

Python

import os
import requests


def check_party(siret, vat):
    r = requests.get(
        "https://api.jsonpage.com/v2/validate",
        params={"siret": siret, "vat": vat},
        headers={"X-API-Key": os.environ["JSONPAGE_API_KEY"]},
        timeout=10,
    )
    r.raise_for_status()
    data = r.json()["data"]
    failed = [c["code"] for c in data["checks"] if not c["ok"]]
    return data["valid"], failed, data["company"]

PHP

function checkParty(string $siret, string $vat): array
{
    $url = "https://api.jsonpage.com/v2/validate?" . http_build_query(["siret" => $siret, "vat" => $vat]);
    $context = stream_context_create(["http" => [
        "header" => "X-API-Key: " . getenv("JSONPAGE_API_KEY"),
        "timeout" => 10,
    ]]);
    $body = file_get_contents($url, false, $context);
    if ($body === false) {
        throw new RuntimeException("Request failed");
    }
    $data = json_decode($body, true)["data"];
    $failed = array_column(array_filter($data["checks"], fn ($c) => !$c["ok"]), "code");
    return [$data["valid"], $failed, $data["company"]];
}

Ruby

require "net/http"
require "json"

def check_party(siret, vat)
  uri = URI("https://api.jsonpage.com/v2/validate")
  uri.query = URI.encode_www_form(siret: siret, vat: vat)
  req = Net::HTTP::Get.new(uri, "X-API-Key" => ENV.fetch("JSONPAGE_API_KEY"))
  res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
  raise "HTTP #{res.code}" unless res.is_a?(Net::HTTPSuccess)

  data = JSON.parse(res.body)["data"]
  failed = data["checks"].reject { |c| c["ok"] }.map { |c| c["code"] }
  [data["valid"], failed, data["company"]]
end
05 / LIMITS

What the API does not do

The API checks numbers and the company they point to. It does not validate the invoice file (its structure, its fields, its compliance with the required format), does not send the invoice to a platform and does not replace the advice of your accountant. A VAT number reported as "not verifiable for now" is not a wrong number: try again later.

On volume, routes are limited per minute; beyond that the answer is 429 with a Retry-After header: wait that long before retrying. For a large batch, the batch route (100 companies per call) cuts the number of calls. See the documentation.

06 / FREQUENTLY ASKED QUESTIONS

Frequently asked questions

Should I check the SIREN before every invoice?+

At least when the customer or supplier is created, then when an invoice is rejected or a payment detail changes. A check at issue time avoids sending an invoice to a closed company or to a wrong number.

Does the API validate my e-invoice?+

No. It checks the identification numbers (SIREN, SIRET, VAT) and the company they point to. The format and content of the invoice file depend on your software or platform.

Can I check the VAT number of a foreign supplier?+

Yes. The check route accepts VAT numbers of European Union countries. If the country's service does not answer, the result is "unverifiable", which is not the same as an invalid number.

Do I need a paid account?+

No, the free account gives access to every route, with 100 requests per minute and 1,000 requests per day. Paid plans lift the daily cap.

What if the SIRET and the VAT number do not match?+

Ask your counterpart to confirm the pair of numbers before invoicing. The list of checks tells you whether the SIRET exists, is active and points to the same company as the VAT number.

07 / RELATED RESOURCES

Keep reading

API

Try it on your own numbers

The free account gives access to the check route: 100 requests per minute, no credit card.