ChartQuery

MwSt.-Nummer beim B2B-Checkout validieren

Überprüfen Sie europäische MwSt.-Nummern in Echtzeit beim Checkout, um B2B-Steuerbefreiungen korrekt anzuwenden und Betrug zu verhindern.

Übersicht

Dieses Playbook zeigt, wie Sie die MwSt.-Nummer eines Unternehmens beim Checkout validieren. Ein gültiges MwSt.-Ergebnis enthält den offiziellen Firmennamen und die Adresse, sodass Sie Benutzerformulare automatisch ausfüllen und die Rechnung korrekt ausstellen können.

Voraussetzungen

  • Einen Veille-API-Schlüssel — erhalten Sie einen auf app.veille.io
  • Installieren Sie die Abhängigkeiten für Ihre Sprache:
pip install requests

Keine zusätzlichen Abhängigkeiten — verwendet die native fetch-API (Node 18+).

curl-Erweiterung aktiviert (standardmäßig).

Keine zusätzlichen Abhängigkeiten — verwendet net/http (Go 1.18+).

Keine zusätzlichen Abhängigkeiten — verwendet java.net.http (Java 11+).

Keine zusätzlichen Abhängigkeiten — verwendet System.Net.Http (.NET 6+).

# Cargo.toml
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde_json = "1"

Schritte

MwSt.-Nummer validieren

Rufen Sie GET /v1/vat mit dem Parameter vat_number auf. Das Format ist Ländercode + Nummer (z.B. 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_number": "FR12345678901"},
)
result = response.json()
print(result)
const API_KEY = "YOUR_API_KEY";

const params   = new URLSearchParams({ vat_number: "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_number" => "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"
    "net/url"
)

func main() {
    params := url.Values{"vat_number": {"FR12345678901"}}
    req, _ := http.NewRequest("GET", "https://api.veille.io/v1/vat?"+params.Encode(), 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_number=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_number=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_number", "FR12345678901")])
        .send().await?.json::<serde_json::Value>().await?;

    println!("{:#?}", result);
    Ok(())
}

Firmendaten auslesen

Die Antwort enthält is_valid, company_name, address und country_code. Verwenden Sie diese Daten, um das Checkout-Formular automatisch auszufüllen.

if result.get("is_valid"):
    print(f"✓ Gültige MwSt.-Nummer")
    print(f"  Unternehmen : {result.get('company_name')}")
    print(f"  Adresse     : {result.get('address')}")
    print(f"  Land        : {result.get('country_code')}")
else:
    print("✗ Ungültige oder inaktive MwSt.-Nummer")
if (result.is_valid) {
  console.log("✓ Gültige MwSt.-Nummer");
  console.log(`  Unternehmen : ${result.company_name}`);
  console.log(`  Adresse     : ${result.address}`);
  console.log(`  Land        : ${result.country_code}`);
} else {
  console.log("✗ Ungültige oder inaktive MwSt.-Nummer");
}
if ($result["is_valid"] ?? false) {
    echo "✓ Gültige MwSt.-Nummer\n";
    echo "  Unternehmen : {$result['company_name']}\n";
    echo "  Adresse     : {$result['address']}\n";
    echo "  Land        : {$result['country_code']}\n";
} else {
    echo "✗ Ungültige oder inaktive MwSt.-Nummer\n";
}
if isValid, ok := result["is_valid"].(bool); ok && isValid {
    fmt.Printf("✓ Gültige MwSt.-Nummer\n  Unternehmen : %v\n  Adresse     : %v\n  Land        : %v\n",
        result["company_name"], result["address"], result["country_code"])
} else {
    fmt.Println("✗ Ungültige oder inaktive MwSt.-Nummer")
}
import org.json.*;

var r = new JSONObject(response.body());
if (r.getBoolean("is_valid")) {
    System.out.printf("✓ Gültige MwSt.-Nummer%n  Unternehmen : %s%n  Adresse     : %s%n  Land        : %s%n",
        r.getString("company_name"), r.getString("address"), r.getString("country_code"));
} else {
    System.out.println("✗ Ungültige oder inaktive MwSt.-Nummer");
}
using System.Text.Json;

var r = JsonDocument.Parse(body).RootElement;
if (r.GetProperty("is_valid").GetBoolean()) {
    Console.WriteLine("✓ Gültige MwSt.-Nummer");
    Console.WriteLine($"  Unternehmen : {r.GetProperty("company_name")}");
    Console.WriteLine($"  Adresse     : {r.GetProperty("address")}");
    Console.WriteLine($"  Land        : {r.GetProperty("country_code")}");
} else {
    Console.WriteLine("✗ Ungültige oder inaktive MwSt.-Nummer");
}
if result["is_valid"].as_bool().unwrap_or(false) {
    println!("✓ Gültige MwSt.-Nummer");
    println!("  Unternehmen : {}", result["company_name"].as_str().unwrap_or(""));
    println!("  Adresse     : {}", result["address"].as_str().unwrap_or(""));
    println!("  Land        : {}", result["country_code"].as_str().unwrap_or(""));
} else {
    println!("✗ Ungültige oder inaktive MwSt.-Nummer");
}

B2B-Checkout-Ablauf mit MwSt.-Steuerbefreiung

Prüfen Sie, ob eine MwSt.-Nummer gültig ist, und wenden Sie die entsprechende steuerliche Behandlung an (Reverse-Charge-Mechanismus innerhalb der EU).

import requests

API_KEY           = "YOUR_API_KEY"
SELLER_COUNTRY    = "FR"
PRODUCT_PRICE_EUR = 1000.00
VAT_RATE          = 0.20

def validate_vat(vat_number: str) -> dict:
    r = requests.get("https://api.veille.io/v1/vat",
        headers={"x-api-key": API_KEY}, params={"vat_number": vat_number})
    return r.json()

def calculate_checkout(vat_number: str | None) -> dict:
    if not vat_number:
        return {"price": PRODUCT_PRICE_EUR, "vat": PRODUCT_PRICE_EUR * VAT_RATE,
                "total": PRODUCT_PRICE_EUR * (1 + VAT_RATE), "type": "B2C"}

    v = validate_vat(vat_number)
    if not v.get("is_valid"):
        return {"error": "Ungültige MwSt.-Nummer. Bitte erneut prüfen."}

    buyer_country = v.get("country_code")
    # Innergemeinschaftlicher Reverse-Charge: MwSt.-befreit wenn Käufer ≠ Verkäufer-Land
    if buyer_country and buyer_country != SELLER_COUNTRY:
        return {"price": PRODUCT_PRICE_EUR, "vat": 0.0, "total": PRODUCT_PRICE_EUR,
                "type": "B2B (innergemeinschaftlich, Reverse-Charge)",
                "company": v.get("company_name"), "address": v.get("address")}

    vat_amount = PRODUCT_PRICE_EUR * VAT_RATE
    return {"price": PRODUCT_PRICE_EUR, "vat": vat_amount,
            "total": PRODUCT_PRICE_EUR + vat_amount, "type": "B2B (Inland)",
            "company": v.get("company_name"), "address": v.get("address")}

# Testfälle
for vat in [None, "INVALID_VAT", "DE123456789", "FR12345678901"]:
    print(f"MwSt.: {vat!r}{calculate_checkout(vat)}")
const API_KEY           = "YOUR_API_KEY";
const SELLER_COUNTRY    = "FR";
const PRODUCT_PRICE_EUR = 1000;
const VAT_RATE          = 0.2;

async function validateVat(vatNumber: string) {
  const params = new URLSearchParams({ vat_number: vatNumber });
  return (await fetch(`https://api.veille.io/v1/vat?${params}`, { headers: { "x-api-key": API_KEY } })).json();
}

async function calculateCheckout(vatNumber?: string) {
  if (!vatNumber) {
    return { price: PRODUCT_PRICE_EUR, vat: PRODUCT_PRICE_EUR * VAT_RATE,
             total: PRODUCT_PRICE_EUR * (1 + VAT_RATE), type: "B2C" };
  }
  const v = await validateVat(vatNumber);
  if (!v.is_valid) return { error: "Ungültige MwSt.-Nummer." };

  if (v.country_code && v.country_code !== SELLER_COUNTRY) {
    return { price: PRODUCT_PRICE_EUR, vat: 0, total: PRODUCT_PRICE_EUR,
             type: "B2B (Reverse-Charge)", company: v.company_name, address: v.address };
  }
  return { price: PRODUCT_PRICE_EUR, vat: PRODUCT_PRICE_EUR * VAT_RATE,
           total: PRODUCT_PRICE_EUR * (1 + VAT_RATE), type: "B2B (Inland)",
           company: v.company_name, address: v.address };
}

for (const vat of [undefined, "INVALID", "DE123456789", "FR12345678901"]) {
  console.log(`MwSt.: ${vat} →`, await calculateCheckout(vat));
}
<?php
const SELLER_COUNTRY    = "FR";
const PRODUCT_PRICE_EUR = 1000.0;
const VAT_RATE          = 0.20;

function validateVat(string $apiKey, string $vatNumber): array {
    $params = http_build_query(["vat_number" => $vatNumber]);
    $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}"]);
    $r = json_decode(curl_exec($ch), true);
    curl_close($ch);
    return $r;
}

function calculateCheckout(string $apiKey, ?string $vatNumber): array {
    if (!$vatNumber) {
        return ["price" => PRODUCT_PRICE_EUR, "vat" => PRODUCT_PRICE_EUR * VAT_RATE,
                "total" => PRODUCT_PRICE_EUR * (1 + VAT_RATE), "type" => "B2C"];
    }
    $v = validateVat($apiKey, $vatNumber);
    if (!($v["is_valid"] ?? false)) return ["error" => "Ungültige MwSt.-Nummer."];

    $buyerCountry = $v["country_code"] ?? "";
    if ($buyerCountry && $buyerCountry !== SELLER_COUNTRY) {
        return ["price" => PRODUCT_PRICE_EUR, "vat" => 0, "total" => PRODUCT_PRICE_EUR,
                "type" => "B2B (Reverse-Charge)", "company" => $v["company_name"]];
    }
    return ["price" => PRODUCT_PRICE_EUR, "vat" => PRODUCT_PRICE_EUR * VAT_RATE,
            "total" => PRODUCT_PRICE_EUR * (1 + VAT_RATE), "type" => "B2B (Inland)", "company" => $v["company_name"]];
}

foreach ([null, "INVALID_VAT", "DE123456789"] as $vat) {
    print_r(calculateCheckout("YOUR_API_KEY", $vat));
}
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "net/url"
)

const (
    APIKey        = "YOUR_API_KEY"
    SellerCountry = "FR"
    Price         = 1000.0
    VATRate       = 0.20
)

func validateVAT(vat string) map[string]any {
    params := url.Values{"vat_number": {vat}}
    req, _ := http.NewRequest("GET", "https://api.veille.io/v1/vat?"+params.Encode(), nil)
    req.Header.Set("x-api-key", APIKey)
    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    var v map[string]any
    json.Unmarshal(body, &v)
    return v
}

func checkout(vat string) string {
    if vat == "" { return fmt.Sprintf("B2C: Total=%.2f€ (MwSt.=%.2f€)", Price*(1+VATRate), Price*VATRate) }
    v := validateVAT(vat)
    if !(v["is_valid"].(bool)) { return "❌ Ungültige MwSt.-Nummer." }
    country, _ := v["country_code"].(string)
    if country != "" && country != SellerCountry {
        return fmt.Sprintf("B2B Reverse-Charge: Total=%.2f€ (MwSt.=0€) — %v", Price, v["company_name"])
    }
    return fmt.Sprintf("B2B Inland: Total=%.2f€ (MwSt.=%.2f€) — %v", Price*(1+VATRate), Price*VATRate, v["company_name"])
}

func main() {
    for _, vat := range []string{"", "INVALID", "DE123456789"} {
        fmt.Printf("MwSt.:%q%s\n", vat, checkout(vat))
    }
}
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 String SELLER      = "FR";
    static double PRICE       = 1000.0;
    static double VAT_RATE    = 0.20;

    static JSONObject validate(String vat) throws Exception {
        var req  = HttpRequest.newBuilder()
            .uri(URI.create("https://api.veille.io/v1/vat?vat_number=" + vat))
            .header("x-api-key", API_KEY).GET().build();
        return new JSONObject(client.send(req, HttpResponse.BodyHandlers.ofString()).body());
    }

    static String checkout(String vat) throws Exception {
        if (vat == null || vat.isEmpty())
            return String.format("B2C: Total=%.2f€ (MwSt.=%.2f€)", PRICE*(1+VAT_RATE), PRICE*VAT_RATE);
        var v = validate(vat);
        if (!v.getBoolean("is_valid")) return "❌ Ungültige MwSt.-Nummer.";
        var country = v.optString("country_code","");
        if (!country.isEmpty() && !country.equals(SELLER))
            return String.format("B2B Reverse-Charge: %.2f€ (keine MwSt.) — %s", PRICE, v.getString("company_name"));
        return String.format("B2B Inland: %.2f€ (MwSt.=%.2f€) — %s", PRICE*(1+VAT_RATE), PRICE*VAT_RATE, v.getString("company_name"));
    }

    public static void main(String[] args) throws Exception {
        for (var vat : new String[]{"", "INVALID", "DE123456789"})
            System.out.printf("MwSt.:%s → %s%n", vat, checkout(vat));
    }
}
using System.Net.Http;
using System.Text.Json;

const string apiKey  = "YOUR_API_KEY";
const string seller  = "FR";
const double price   = 1000.0;
const double vatRate = 0.20;

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", apiKey);

async Task<JsonElement?> ValidateVat(string vatNumber)
{
    var resp = await client.GetAsync($"https://api.veille.io/v1/vat?vat_number={vatNumber}");
    if (!resp.IsSuccessStatusCode) return null;
    return JsonDocument.Parse(await resp.Content.ReadAsStringAsync()).RootElement;
}

async Task<string> Checkout(string? vatNumber)
{
    if (string.IsNullOrEmpty(vatNumber))
        return $"B2C: Total={(price*(1+vatRate)):F2}€ (MwSt.={(price*vatRate):F2}€)";
    var v = await ValidateVat(vatNumber);
    if (v == null || !v.Value.GetProperty("is_valid").GetBoolean()) return "❌ Ungültige MwSt.-Nummer.";
    var country = v.Value.TryGetProperty("country_code", out var c) ? c.GetString() : "";
    if (!string.IsNullOrEmpty(country) && country != seller)
        return $"B2B Reverse-Charge: {price:F2}€ (keine MwSt.) — {v.Value.GetProperty("company_name")}";
    return $"B2B Inland: {price*(1+vatRate):F2}€ (MwSt.={(price*vatRate):F2}€)";
}

foreach (var vat in new string?[] { null, "INVALID", "DE123456789" })
    Console.WriteLine($"MwSt.:{vat}{await Checkout(vat)}");
use reqwest::Client;
use serde_json::Value;

const API_KEY: &str     = "YOUR_API_KEY";
const SELLER: &str      = "FR";
const PRICE: f64        = 1000.0;
const VAT_RATE: f64     = 0.20;

async fn validate_vat(client: &Client, vat: &str) -> Value {
    client.get("https://api.veille.io/v1/vat")
        .header("x-api-key", API_KEY)
        .query(&[("vat_number", vat)])
        .send().await.unwrap().json::<Value>().await.unwrap()
}

async fn checkout(client: &Client, vat: Option<&str>) -> String {
    let Some(vat) = vat else {
        return format!("B2C: Total={:.2}€ (MwSt.={:.2}€)", PRICE*(1.0+VAT_RATE), PRICE*VAT_RATE);
    };
    let v = validate_vat(client, vat).await;
    if !v["is_valid"].as_bool().unwrap_or(false) { return "❌ Ungültige MwSt.-Nummer.".to_string(); }
    let country = v["country_code"].as_str().unwrap_or("");
    if !country.is_empty() && country != SELLER {
        return format!("B2B Reverse-Charge: {:.2}€ (keine MwSt.) — {}", PRICE, v["company_name"].as_str().unwrap_or(""));
    }
    format!("B2B Inland: {:.2}€ (MwSt.={:.2}€)", PRICE*(1.0+VAT_RATE), PRICE*VAT_RATE)
}

#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
    let client = Client::new();
    for vat in [None, Some("INVALID"), Some("DE123456789")] {
        println!("MwSt.:{:?} → {}", vat, checkout(&client, vat).await);
    }
    Ok(())
}

Speichern Sie validierte MwSt.-Nummern und den entsprechenden Firmennamen in Ihrer Datenbank und vermeiden Sie unnötige erneute Validierungen. MwSt.-Nummern ändern sich selten — eine Neuvalidierung wöchentlich oder bei Kontoaktualisierung ist ausreichend.

Auf dieser Seite