Valider les numéros de TVA européens
Vérifiez les numéros de TVA européens au moment du paiement pour permettre les exonérations fiscales B2B et prévenir la fraude avec l'API de validation TVA Veille.
Vue d'ensemble
Les entreprises de l'UE sont exonérées de TVA lors d'achats auprès d'autres entreprises de l'UE — mais uniquement avec un numéro de TVA valide. Ce guide montre comment valider un numéro de TVA au moment du paiement et récupérer les informations associées à l'entreprise (nom et adresse) depuis la base VIES.
Prérequis
- Une clé API Veille — obtenez-en une sur app.veille.io
- Installez les dépendances pour votre langage :
pip install requestsAucune dépendance supplémentaire — utilise l'API native fetch (Node 18+).
Extension curl activée (par défaut).
Aucune dépendance supplémentaire — utilise net/http (Go 1.18+).
Aucune dépendance supplémentaire — utilise java.net.http (Java 11+).
Aucune dépendance supplémentaire — utilise System.Net.Http (.NET 6+).
# Cargo.toml
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde_json = "1"Étapes
Valider un numéro de TVA
Appelez GET /v1/vat avec le paramètre vat. Le numéro doit inclure le préfixe pays (p. ex. FR12345678901).
import requests
API_KEY = "YOUR_API_KEY"
response = requests.get(
"https://api.veille.io/v1/vat",
headers={"x-api-key": API_KEY},
params={"vat": "FR12345678901"},
)
result = response.json()
print(result)const API_KEY = "YOUR_API_KEY";
const params = new URLSearchParams({ vat: "FR12345678901" });
const response = await fetch(`https://api.veille.io/v1/vat?${params}`, {
headers: { "x-api-key": API_KEY },
});
const result = await response.json();
console.log(result);<?php
$apiKey = "YOUR_API_KEY";
$params = http_build_query(["vat" => "FR12345678901"]);
$ch = curl_init("https://api.veille.io/v1/vat?{$params}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-api-key: {$apiKey}"]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($result);package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.veille.io/v1/vat?vat=FR12345678901", nil)
req.Header.Set("x-api-key", "YOUR_API_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result map[string]any
json.Unmarshal(body, &result)
fmt.Println(result)
}import java.net.URI;
import java.net.http.*;
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.veille.io/v1/vat?vat=FR12345678901"))
.header("x-api-key", "YOUR_API_KEY")
.GET().build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());using System.Net.Http;
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_KEY");
var body = await client.GetStringAsync("https://api.veille.io/v1/vat?vat=FR12345678901");
Console.WriteLine(body);#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let result = reqwest::Client::new()
.get("https://api.veille.io/v1/vat")
.header("x-api-key", "YOUR_API_KEY")
.query(&[("vat", "FR12345678901")])
.send().await?.json::<serde_json::Value>().await?;
println!("{:#?}", result);
Ok(())
}Lire les informations de l'entreprise
Un numéro valide retourne is_valid: true, le company_name, company_address et country_code.
if result.get("is_valid"):
print(f"✅ Numéro de TVA valide")
print(f" Entreprise : {result.get('company_name')}")
print(f" Adresse : {result.get('company_address')}")
print(f" Pays : {result.get('country_code')}")
else:
print(f"❌ Numéro de TVA invalide : {result.get('error', 'Introuvable dans VIES')}")if (result.is_valid) {
console.log("✅ Numéro de TVA valide");
console.log(` Entreprise : ${result.company_name}`);
console.log(` Adresse : ${result.company_address}`);
console.log(` Pays : ${result.country_code}`);
} else {
console.log(`❌ Numéro de TVA invalide : ${result.error ?? "Introuvable dans VIES"}`);
}if ($result["is_valid"] ?? false) {
echo "✅ Numéro de TVA valide\n";
echo " Entreprise : {$result['company_name']}\n";
echo " Adresse : {$result['company_address']}\n";
echo " Pays : {$result['country_code']}\n";
} else {
echo "❌ Numéro de TVA invalide : " . ($result["error"] ?? "Introuvable dans VIES") . "\n";
}if result["is_valid"].(bool) {
fmt.Printf("✅ Numéro de TVA valide\n Entreprise : %v\n Adresse : %v\n Pays : %v\n",
result["company_name"], result["company_address"], result["country_code"])
} else {
errMsg := "Introuvable dans VIES"
if e, ok := result["error"].(string); ok { errMsg = e }
fmt.Println("❌ Numéro de TVA invalide :", errMsg)
}import org.json.*;
var r = new JSONObject(response.body());
if (r.getBoolean("is_valid")) {
System.out.printf("✅ Numéro de TVA valide%n Entreprise : %s%n Adresse : %s%n Pays : %s%n",
r.getString("company_name"), r.getString("company_address"), r.getString("country_code"));
} else {
System.out.println("❌ Numéro de TVA invalide : " + r.optString("error", "Introuvable dans VIES"));
}using System.Text.Json;
var r = JsonDocument.Parse(body).RootElement;
if (r.GetProperty("is_valid").GetBoolean())
{
Console.WriteLine("✅ Numéro de TVA valide");
Console.WriteLine($" Entreprise : {r.GetProperty("company_name")}");
Console.WriteLine($" Adresse : {r.GetProperty("company_address")}");
Console.WriteLine($" Pays : {r.GetProperty("country_code")}");
}
else
{
var error = r.TryGetProperty("error", out var e) ? e.GetString() : "Introuvable dans VIES";
Console.WriteLine($"❌ Numéro de TVA invalide : {error}");
}if result["is_valid"].as_bool().unwrap_or(false) {
println!("✅ Numéro de TVA valide");
println!(" Entreprise : {}", result["company_name"].as_str().unwrap_or(""));
println!(" Adresse : {}", result["company_address"].as_str().unwrap_or(""));
println!(" Pays : {}", result["country_code"].as_str().unwrap_or(""));
} else {
let err = result["error"].as_str().unwrap_or("Introuvable dans VIES");
println!("❌ Numéro de TVA invalide : {}", err);
}Construire un gestionnaire de paiement TVA B2B
Supprimez la TVA du total de la commande lorsqu'un numéro de TVA UE vérifié est fourni.
import requests
API_KEY = "YOUR_API_KEY"
VAT_RATE = 0.20 # TVA 20%
def lookup_vat(number: str) -> dict:
r = requests.get("https://api.veille.io/v1/vat",
headers={"x-api-key": API_KEY}, params={"vat": number})
return r.json()
def calculate_checkout(subtotal: float, vat_number: str | None = None) -> dict:
vat_amount = subtotal * VAT_RATE
vat_info = None
if vat_number:
result = lookup_vat(vat_number)
if result.get("is_valid"):
vat_amount = 0 # Autoliquidation B2B — pas de TVA facturée
vat_info = {"company": result["company_name"], "country": result["country_code"]}
else:
return {"error": "Le numéro de TVA fourni n'est pas valide."}
total = subtotal + vat_amount
return {"subtotal": subtotal, "vat": vat_amount, "total": total, "company": vat_info}
print(calculate_checkout(100.00))
print(calculate_checkout(100.00, vat_number="FR12345678901"))
print(calculate_checkout(100.00, vat_number="INVALID123"))const API_KEY = "YOUR_API_KEY";
const VAT_RATE = 0.20;
async function lookupVat(number: string) {
const params = new URLSearchParams({ vat: number });
const res = await fetch(`https://api.veille.io/v1/vat?${params}`, {
headers: { "x-api-key": API_KEY },
});
return res.json();
}
async function calculateCheckout(subtotal: number, vatNumber?: string) {
let vatAmount = subtotal * VAT_RATE;
let companyInfo: any = null;
if (vatNumber) {
const result = await lookupVat(vatNumber);
if (result.is_valid) {
vatAmount = 0;
companyInfo = { company: result.company_name, country: result.country_code };
} else {
return { error: "Le numéro de TVA fourni n'est pas valide." };
}
}
return { subtotal, vat: vatAmount, total: subtotal + vatAmount, company: companyInfo };
}
console.log(await calculateCheckout(100));
console.log(await calculateCheckout(100, "FR12345678901"));
console.log(await calculateCheckout(100, "INVALID123"));<?php
const VAT_RATE = 0.20;
function lookupVat(string $apiKey, string $number): array {
$params = http_build_query(["vat" => $number]);
$ch = curl_init("https://api.veille.io/v1/vat?{$params}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-api-key: {$apiKey}"]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
return $result;
}
function calculateCheckout(string $apiKey, float $subtotal, ?string $vatNumber = null): array {
$vatAmount = $subtotal * VAT_RATE;
$company = null;
if ($vatNumber) {
$result = lookupVat($apiKey, $vatNumber);
if ($result["is_valid"] ?? false) {
$vatAmount = 0;
$company = ["company" => $result["company_name"], "country" => $result["country_code"]];
} else {
return ["error" => "Numéro de TVA invalide."];
}
}
return ["subtotal" => $subtotal, "vat" => $vatAmount, "total" => $subtotal + $vatAmount, "company" => $company];
}
print_r(calculateCheckout("YOUR_API_KEY", 100.0));
print_r(calculateCheckout("YOUR_API_KEY", 100.0, "FR12345678901"));package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
const APIKey = "YOUR_API_KEY"
const VATRate = 0.20
func lookupVAT(number string) map[string]any {
req, _ := http.NewRequest("GET", "https://api.veille.io/v1/vat?vat="+number, nil)
req.Header.Set("x-api-key", APIKey)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var r map[string]any
json.Unmarshal(body, &r)
return r
}
func calculateCheckout(subtotal float64, vatNumber string) map[string]any {
vatAmount := subtotal * VATRate
var company map[string]any
if vatNumber != "" {
result := lookupVAT(vatNumber)
if result["is_valid"].(bool) {
vatAmount = 0
company = map[string]any{"company": result["company_name"], "country": result["country_code"]}
} else {
return map[string]any{"error": "Numéro de TVA invalide."}
}
}
return map[string]any{"subtotal": subtotal, "vat": vatAmount, "total": subtotal + vatAmount, "company": company}
}
func main() {
fmt.Println(calculateCheckout(100, ""))
fmt.Println(calculateCheckout(100, "FR12345678901"))
fmt.Println(calculateCheckout(100, "INVALID123"))
}import java.net.URI;
import java.net.http.*;
import org.json.*;
public class Main {
static HttpClient client = HttpClient.newHttpClient();
static String API_KEY = "YOUR_API_KEY";
static double VAT_RATE = 0.20;
static JSONObject lookupVat(String number) throws Exception {
var req = HttpRequest.newBuilder()
.uri(URI.create("https://api.veille.io/v1/vat?vat=" + number))
.header("x-api-key", API_KEY).GET().build();
var resp = client.send(req, HttpResponse.BodyHandlers.ofString());
return new JSONObject(resp.body());
}
static JSONObject calculateCheckout(double subtotal, String vatNumber) throws Exception {
double vatAmount = subtotal * VAT_RATE;
JSONObject company = null;
if (vatNumber != null && !vatNumber.isEmpty()) {
var result = lookupVat(vatNumber);
if (result.getBoolean("is_valid")) {
vatAmount = 0;
company = new JSONObject().put("company", result.getString("company_name"))
.put("country", result.getString("country_code"));
} else {
return new JSONObject().put("error", "Numéro de TVA invalide.");
}
}
return new JSONObject().put("subtotal", subtotal).put("vat", vatAmount)
.put("total", subtotal + vatAmount).put("company", company);
}
public static void main(String[] args) throws Exception {
System.out.println(calculateCheckout(100, null));
System.out.println(calculateCheckout(100, "FR12345678901"));
System.out.println(calculateCheckout(100, "INVALID123"));
}
}using System.Net.Http;
using System.Text.Json;
const double VAT_RATE = 0.20;
var apiKey = "YOUR_API_KEY";
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", apiKey);
async Task<JsonElement> LookupVat(string number)
{
var body = await client.GetStringAsync($"https://api.veille.io/v1/vat?vat={number}");
return JsonDocument.Parse(body).RootElement;
}
async Task<string> CalculateCheckout(double subtotal, string? vatNumber = null)
{
double vatAmount = subtotal * VAT_RATE;
string? company = null;
if (vatNumber != null)
{
var result = await LookupVat(vatNumber);
if (result.GetProperty("is_valid").GetBoolean())
{ vatAmount = 0; company = result.GetProperty("company_name").GetString(); }
else return """{"error":"Numéro de TVA invalide."}""";
}
return $"""{{ "subtotal": {subtotal}, "vat": {vatAmount}, "total": {subtotal + vatAmount}, "company": "{company}" }}""";
}
Console.WriteLine(await CalculateCheckout(100));
Console.WriteLine(await CalculateCheckout(100, "FR12345678901"));
Console.WriteLine(await CalculateCheckout(100, "INVALID123"));use reqwest::Client;
use serde_json::{json, Value};
const VAT_RATE: f64 = 0.20;
const API_KEY: &str = "YOUR_API_KEY";
async fn lookup_vat(client: &Client, number: &str) -> Value {
client.get("https://api.veille.io/v1/vat")
.header("x-api-key", API_KEY)
.query(&[("vat", number)])
.send().await.unwrap().json::<Value>().await.unwrap()
}
async fn calculate_checkout(client: &Client, subtotal: f64, vat_number: Option<&str>) -> Value {
let mut vat_amount = subtotal * VAT_RATE;
let mut company = json!(null);
if let Some(number) = vat_number {
let result = lookup_vat(client, number).await;
if result["is_valid"].as_bool().unwrap_or(false) {
vat_amount = 0.0;
company = json!({"company": result["company_name"], "country": result["country_code"]});
} else {
return json!({ "error": "Numéro de TVA invalide." });
}
}
json!({ "subtotal": subtotal, "vat": vat_amount, "total": subtotal + vat_amount, "company": company })
}
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new();
println!("{}", calculate_checkout(&client, 100.0, None).await);
println!("{}", calculate_checkout(&client, 100.0, Some("FR12345678901")).await);
println!("{}", calculate_checkout(&client, 100.0, Some("INVALID123")).await);
Ok(())
}Conservez toujours le nom et l'adresse de l'entreprise validée avec l'enregistrement de la commande. Les autorités fiscales de l'UE exigent la preuve que le mécanisme d'autoliquidation a été correctement appliqué.