{ "shopify" :

Validation de TVA B2B sur Shopify pour les clients néerlandais

Réponse courte

Sur la plupart des offres, Shopify ne permet pas d'accrocher une vérification de TVA en direct à la page de paiement. Les extensions d'interface de paiement sont réservées à Plus, et les Shopify Functions s'exécutent sans accès réseau : elles ne peuvent donc pas joindre VIES. La voie praticable consiste à valider avant ou après le paiement via un proxy d'application, et à stocker le résultat dans un metafield.

proxy d'application
# boutique -> votre application
GET "/apps/kvk/lookup?kvk=68750110"

# votre application, côté serveur
curl ".../v1/validate/vat/NL12..B01" \
  -H "Authorization: Bearer KEY"

{
  "number": "NL123456789B01",
  "valid": true
}

Ce que Shopify permet de scripter, et ce qu’il interdit

C’est le cœur de toute intégration de données d’entreprise sur Shopify, et la plupart des guides l’esquivent : le paiement est fermé.

Ce que vous voulezPossibleCondition
Un champ sur la page de paiementOuiExtension d’interface de paiement, Shopify Plus
Un appel d’API externe depuis le paiementOuiMême extension, avec accès réseau
Un appel d’API externe depuis une FunctionNonLes Functions s’exécutent sans réseau
Un champ sur la page du panier ou du compteOuiThème standard, toute offre
Un contrôle après la commandeOuiWebhook sur orders/create

Une Function de validation du panier ou du paiement est du WebAssembly sans accès réseau. Elle ne peut jamais appeler elle-même VIES ni notre endpoint. Elle peut en revanche lire un metafield ou un attribut de panier renseigné plus tôt, et bloquer le paiement lorsqu’il indique vatValid: false. C’est la seule voie vers un blocage ferme dans le paiement, et elle suppose que la validation ait eu lieu en amont.

Où ranger les données

  • Attribut de panier pour la commande en cours. Il apparaît comme détail supplémentaire de la commande et suit jusqu’à l’expédition.
  • Metafield client pour les achats répétés, par exemple custom.kvk_number et custom.vat_valid_at. Stockez un horodatage avec la valeur, sinon dans un an personne ne sait plus ce que signifie ce true.
  • Site de l’entreprise si vous faites du B2B. C’est là que va l’identifiant fiscal et là que se rattache l’exonération.
  • Metafield de commande pour la preuve au moment de la commande. Pour la facturation électronique et tout audit ultérieur, vous voulez ce que vous avez vu à ce moment-là, pas ce qui est vrai aujourd’hui.

Le proxy d’application, concrètement

Un proxy d’application vous donne une route sous le domaine de votre boutique, que Shopify transmet à votre serveur. La clé d’API reste côté serveur et vous évitez totalement CORS.

# shopify.app.toml
[app_proxy]
url = "https://your-app.example.com/proxy"
subpath = "kvk"
prefix = "apps"

La boutique appelle /apps/kvk/lookup?kvk=68750110, Shopify le transmet à votre endpoint avec les paramètres de requête plus une signature. Vérifiez toujours cette signature avec le secret de votre application avant de consommer une recherche. Si vous la sautez, votre proxy est un tuyau ouvert vers votre quota pour quiconque connaît le chemin.

Votre gestionnaire effectue ensuite l’appel réel :

const r = await fetch(`https://api.kvkbase.nl/v1/lookup/${kvk}?enrich=true`, {
  headers: { Authorization: `Bearer ${process.env.KVKBASE_KEY}` },
});
if (r.status === 404) return json({ ok: false, reason: "not_found" }, 200);
const c = await r.json();
return json({
  ok: c.isActive,
  name: c.statutoryName ?? c.name,
  vat: c.vat?.number ?? null,
  vatValid: c.vat?.valid ?? null,
});

Remarquez le 200 renvoyé sur notre 404. Un front qui transforme tout code hors 2xx en erreur générique dit au client « une erreur est survenue » alors que la vraie réponse est « ce numéro n’existe pas ».

Si vous voulez seulement une aide à la saisie sur la page du panier ou du compte sans construire d’application, le widget peut aller directement dans votre thème. Il remplit les champs nom, adresse et TVA à partir d’une recherche, avec une clé publique. Pour la validation qui compte, restez sur le proxy.

Ce qui casse réellement en production

VIES est en panne. Les vérifications de TVA passent par le service de l’État membre, qui tombe régulièrement. Vous recevez UPSTREAM_ERROR au lieu d’un verdict. Si vous bloquez strictement sur ce résultat, votre paiement B2B est hors ligne aussi longtemps qu’un service public étranger. Stockez unknown, laissez passer la commande avec la TVA appliquée, et réévaluez dans le webhook.

Le client saisit le numéro de TVA de la holding. Au sein d’un groupe, la holding est souvent connue de VIES alors que l’entité qui passe commande ne l’est pas, ou l’inverse. Le numéro est valide, mais le nom de l’entreprise ne correspond pas aux données de livraison. Conservez les deux et signalez l’écart plutôt que de faire confiance aveuglément.

Le rattrapage des clients existants s’enlise. Enrichir des milliers de fiches clients par des appels unitaires atteint la limite de débit en moins d’une minute. Utilisez POST /v1/lookup/batch et traitez par blocs avec une pause entre chacun.

Les attributs de panier ne survivent pas à toutes les sessions. Si le client vide son panier ou revient dans une nouvelle session, votre attribut a disparu alors qu’il est convaincu de l’avoir déjà renseigné. Écrivez la validation dans le metafield client dès sa connexion, et reconstituez le panier à partir de là.

Questions fréquentes

Avez-vous une application Shopify ?
Non. Nous fournissons une API REST et un widget JavaScript. Vous construisez le côté Shopify : une application personnalisée avec un proxy d'application, ou une section de thème qui charge le widget. Pour une seule boutique, une application personnalisée suffit et ne passe pas par la validation de l'App Store.
Puis-je valider le numéro de TVA dans le paiement lui-même ?
Seulement sur Shopify Plus, avec une extension d'interface de paiement qui déclare un accès réseau. Sur les autres offres, la page de paiement ne peut pas être étendue. Il faut alors valider sur la page du panier ou du compte et transmettre le résultat sous forme d'attribut de panier.
Pourquoi une Shopify Function ne peut-elle pas faire cela ?
Les Functions de validation du panier et du paiement s'exécutent en WebAssembly sans accès réseau, elles ne peuvent donc appeler aucune API externe. Elles peuvent en revanche lire un metafield ou un attribut de panier que vous avez renseigné plus tôt, et bloquer en fonction de cette valeur.
Un numéro de TVA valide active-t-il automatiquement l'autoliquidation ?
Non, vous la configurez dans Shopify. En B2B, l'exonération se règle sur le site de l'entreprise ; hors B2B, dans les paramètres de taxe du client. Notre API vous indique seulement si VIES connaît le numéro et le considère comme valide. La décision fiscale reste la vôtre.

Mis à jour:

Un seul appel vous donne toute l'entreprise

Les données KvK, le numéro de TVA déduit et un contrôle VIES en direct, en une seule requête. L'offre gratuite comprend 50 recherches par mois, sans carte bancaire.

50
recherches gratuites par mois
1
requête au lieu de trois
0
carte bancaire, contrat ou appel commercial