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.
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.
Reading the result and deciding
Do not stop at valid: the checks list says which check failed, and so what to ask your counterpart.
| Result | What it means | What to do before the invoice |
|---|---|---|
valid: true | Every check passed. | Go ahead: issue or book the invoice. |
siret_key or vat_format failed | The number was mistyped: a typo or a wrong check digit. | Fix the number at the source, then run the check again. |
company_active failed | The number exists, but the company or the establishment is closed. | Ask the customer or supplier for a current number before going on. |
identifiers_match failed | The SIRET and the VAT number do not point to the same company. | Have the right pair of numbers confirmed. |
vat unverifiable | The 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.
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
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.
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.
Keep reading
- E-INVOICINGFrance e-invoicing 2026: the list of mandatory invoice mentionsChecklist of French invoice mentions and the four new ones of the reform: customer SIREN, delivery, nature of operation, debits.
- INVOICINGCan your French customer receive e-invoices?Look up a French customer's approved platform in the official directory, and what the 2026-2027 timetable requires.
- E-INVOICINGFrance e-invoicing 2026: why your customers' SIREN becomes mandatoryThe four new mandatory mentions, the 2026-2027 timeline and how to verify your customers' SIREN numbers.
- APIIntra-EU VAT Number Verification API in JSONVerify a VAT number in one call: format, company, valid or invalid status. France, Belgium, Switzerland, Norway, Finland, Latvia, Sweden, Estonia, Lithuania. Fixed pricing.