{ "woocommerce" :
Champs KvK et TVA dans le paiement WooCommerce
Réponse courte
WooCommerce n'a pas de champ de registre KvK ou TVA. Vous l'ajoutez vous-même : sur le paiement classique via le filtre woocommerce_billing_fields, validé dans woocommerce_after_checkout_validation et écrit dans les métadonnées de la commande. Nous ne proposons pas d'extension WooCommerce. Nous fournissons une API REST et un widget que vous appelez depuis ces hooks.
# contrôle côté serveur au paiement
curl ".../v1/lookup/68750110" \
-H "Authorization: Bearer KEY"
{
"name": "Acme B.V.",
"isActive": true,
"vat": {
"number": "NL123456789B01",
"valid": true
}
}
Où les données d’entreprise doivent atterrir
WooCommerce n’a pas de champ de registre. Il a billing_company, qui est du texte libre. Dès que vous vendez en B2B aux Pays-Bas, il vous faut trois endroits où ranger les données.
| Emplacement | Ce qui doit s’y trouver | Pourquoi |
|---|---|---|
| Champ de paiement | Numéro KvK, saisi ou choisi | Saisie et validation |
| Métadonnées de commande | Numéro KvK, dénomination sociale, numéro de TVA | Facture et comptabilité |
| Métadonnées client | Les mêmes, par défaut | Deuxième commande sans ressaisie |
Ce que les équipes négligent : une commande est un instantané. Si vous ne stockez que le numéro KvK et récupérez le nom plus tard, votre facture de 2024 ne correspondra plus à la réalité quand l’entreprise changera de nom en 2026. Écrivez le nom et l’adresse sur la commande, pas seulement la clé.
Paiement classique : champ, validation, stockage
Trois hooks, dans cet ordre. Mettez-les dans une extension propre au site plutôt que dans le functions.php d’un thème que vous remplacerez plus tard.
add_filter( 'woocommerce_billing_fields', function ( $fields ) {
$fields['billing_kvk'] = [
'label' => 'Numéro KvK',
'required' => false,
'class' => [ 'form-row-wide' ],
'priority' => 35,
];
return $fields;
} );
add_action( 'woocommerce_after_checkout_validation', function ( $data, $errors ) {
$kvk = trim( $data['billing_kvk'] ?? '' );
if ( $kvk === '' ) {
return;
}
if ( ! preg_match( '/^\d{8}$/', $kvk ) ) {
$errors->add( 'billing_kvk', 'Un numéro KvK compte 8 chiffres.' );
return;
}
$res = wp_remote_get( "https://api.kvkbase.nl/v1/lookup/{$kvk}", [
'timeout' => 3,
'headers' => [ 'Authorization' => 'Bearer ' . KVKBASE_KEY ],
] );
if ( is_wp_error( $res ) || wp_remote_retrieve_response_code( $res ) >= 500 ) {
return; // API injoignable : laisser passer la commande, la signaler ensuite.
}
if ( wp_remote_retrieve_response_code( $res ) === 404 ) {
$errors->add( 'billing_kvk', 'Ce numéro KvK ne figure pas au registre du commerce.' );
}
}, 10, 2 );
add_action( 'woocommerce_checkout_create_order', function ( $order, $data ) {
if ( ! empty( $data['billing_kvk'] ) ) {
$order->update_meta_data( '_billing_kvk', wc_clean( $data['billing_kvk'] ) );
}
}, 10, 2 );
Le return anticipé sur un 5xx ou une erreur de transport est voulu. Un paiement qui bloque parce qu’un tiers est lent vous coûte du chiffre d’affaires. Laissez passer la commande et ajoutez une note de commande ou un indicateur de statut pour un contrôle manuel.
Le paiement par blocs est une seconde implémentation
Maintenant que le paiement par blocs est celui par défaut, le formulaire repose sur React et les filtres classiques ne se déclenchent jamais. Il faut y déclarer le champ via l’API Additional Checkout Fields sur woocommerce_init, sous votre propre espace de noms. Deux choses à savoir :
- La valeur est stockée sous une clé de métadonnées avec espace de noms, pas sous
_billing_kvk. Tout rapport ou extension de facturation qui lit votre ancienne clé renvoie des colonnes vides. - La validation côté serveur s’accroche aux hooks de validation propres à cette API, pas à
woocommerce_after_checkout_validation.
Si vous faites tourner les deux paiements côte à côte, écrivez dans la même clé de métadonnées personnalisée dans les deux chemins. Sinon, vos rapports doivent être construits en double.
Le widget comme aide à la saisie
Si vous voulez que les clients cherchent par nom d’entreprise plutôt que de taper un numéro, branchez le widget sur le champ. Une seule balise script, avec des sélecteurs CSS pour les champs qu’il peut remplir :
<script
src="https://widget.kvkbase.nl/v1/widget.js"
data-apikey="PUBLIC_KEY"
data-target="#billing_kvk"
data-autofill="true"
data-name-target="#billing_company"
data-city-target="#billing_city"
data-postal-target="#billing_postcode"
data-vat-target="#billing_vat"
></script>
Le widget remplit les champs dans le navigateur. C’est une aide à la saisie, pas une validation : tout ce qu’un navigateur remplit, un navigateur peut le modifier. Faites le contrôle qui compte côté serveur dans le hook ci-dessus, avec une clé qui ne figure pas dans le code source de votre page. La data-apikey est publique par définition.
Sur le paiement classique, cela fonctionne tel quel. Sur le paiement par blocs, le champ n’existe pas encore au chargement du script, donc un sélecteur simple ne trouve rien. Branchez le widget après l’affichage du champ, ou appelez directement l’API depuis votre propre composant de bloc.
Ce qui casse réellement en production
Le client colle un numéro d’établissement. Les factures et e-mails de confirmation néerlandais affichent souvent le vestigingsnummer à 12 chiffres au lieu du numéro KvK à 8 chiffres. Votre expression régulière l’attrape, mais le message d’erreur doit préciser quel numéro vous attendez, sinon le client abandonne.
Une vraie entreprise renvoie 404. Les entrées radiées disparaissent du registre. Traitez NOT_FOUND comme « n’est plus active » plutôt que comme « faute de frappe », et laissez un client existant poursuivre avec un indicateur de contrôle manuel.
VIES est injoignable. La validation de TVA s’appuie sur le service de l’État membre, qui tombe régulièrement. Vous recevez UPSTREAM_ERROR et pas de valid: true. Ne bloquez jamais le paiement là-dessus : appliquez la TVA, traitez la commande, et corrigez ensuite si l’autoliquidation s’avère applicable. Le fonctionnement est détaillé dans validation du numéro de TVA avec l’API VIES.
Un rattrapage en masse atteint la limite de débit. Enrichir les commandes existantes avec un foreach sur 3 000 clients épuise la limite par minute en quelques secondes. Utilisez POST /v1/lookup/batch et traitez par paquets depuis une action cron plutôt qu’une recherche par ligne.
Questions fréquentes
Avez-vous une extension WooCommerce ?
Le champ KvK doit-il être obligatoire ?
Le même code fonctionne-t-il dans le paiement par blocs ?
Puis-je déduire le numéro de TVA du numéro KvK ?
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