Développeurs
API de contrôle douanier
Le même contrôle que sur ce site, appelé depuis votre logiciel. Vous envoyez un dossier en JSON, vous recevez un score sur 100, les points bloquants, les alertes et les actions recommandées — avec des codes d'anomalies stables et des messages traduits dans les 24 langues officielles de l'Union européenne.
API serveur-à-serveur. Une clé est un secret. Les appels depuis un navigateur ne sont pas pris en charge et aucun en-tête CORS n'est envoyé sur les routes authentifiées : une clé qui arrive dans un navigateur est une clé divulguée.
Vue d'ensemble
L'API expose le moteur de contrôle du validateur : treize règles transverses, quatre règles de complétude documentaire et les validateurs propres à chaque système déclaratif. Elle ne télétransmet rien et n'interroge aucune base tarifaire — elle vérifie la cohérence interne et le format de votre dossier avant que vous ne prépariez la déclaration.
Toutes les routes sont préfixées par leur version. Les routes de découverte et la spécification sont publiques : un intégrateur, ou un agent, peut lire le schéma avant même d'avoir une clé.
| Route | Rôle | Authentification |
|---|---|---|
| POST/v1/checks | Contrôle un dossier et renvoie le rapport complet | Clé requise |
| POST/v1/checks/batch | Contrôle jusqu'à 25 dossiers en un appel | Clé requise |
| GET/v1/me | Renvoie la clé courante et son quota, sans le consommer | Clé requise |
| GET/v1/declaration-types | Liste les types de déclaration reconnus | Publique |
| GET/v1/declaration-types/{type} | Décrit les champs attendus pour un type | Publique |
| GET/v1/openapi.json | Spécification OpenAPI 3.1 de l'API | Publique |
Authentification
L'API s'authentifie par jeton porteur. Le jeton n'est affiché qu'une fois, au moment de la création : seule son empreinte est conservée, une clé perdue se remplace mais ne se récupère pas.
Vous pouvez détenir trois clés actives simultanément, ce qui permet de faire tourner une clé sans interrompre votre intégration : créez la nouvelle, déployez-la, puis révoquez l'ancienne.
- 1Créez une clé depuis votre compte, dans l'espace « Clés API ».
- 2Envoyez-la dans l'en-tête Authorization de chaque requête.
- 3Révoquez-la si elle fuite : la coupure est immédiate et le contenu des dossiers soumis avec cette clé est purgé dans la foulée.
Authorization: Bearer cc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxPremier contrôle
Un dossier se compose d'un type, d'un en-tête et de lignes de marchandises. Toutes les valeurs sont des chaînes de caractères : le moteur s'occupe de les interpréter. Les noms des champs se découvrent à l'exécution, type par type.
La réponse arrive immédiatement, il n'y a rien à interroger ensuite.
curl https://www.customs-check.com/api/v1/checks \
-H "Authorization: Bearer $CUSTOM_CHECK_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "import-export",
"reference": "PO-2026-114",
"header": {
"flow": "IM",
"shipmentCountry": "CN",
"destinationCountry": "FR",
"incoterm": "FOB",
"companyName": "Acme SAS",
"companyCountry": "FR",
"eori": "FR12345678900012",
"transportMode": "sea",
"currency": "USD",
"invoiceTotal": "12500"
},
"items": [
{
"description": "Leather sport shoes",
"hsCode": "6403990000",
"quantity": "500",
"value": "12500",
"origin": "VN",
"grossMass": "850",
"netMass": "800"
}
],
"documents": { "commercialInvoice": "available", "packingList": "missing" }
}'Lire la réponse
Chaque anomalie porte à la fois une identité machine et une phrase lisible. Construisez votre logique sur l'identité machine : elle ne change pas sans changement de version.
- severity · code · path · rule
- Contrat stableStables. De nouveaux codes peuvent apparaître, les codes existants ne sont pas renommés sans changement de version.
- field · message · text
- AffichageTraduits pour l'affichage. Ils peuvent être reformulés à tout moment : ne les comparez jamais dans votre code.
- engine.version
- Change dès qu'une évolution des règles modifie le score d'un dossier inchangé. Archivez-la avec vos rapports.
Le champ « path » suit la forme de votre requête, ce qui permet de rattacher une anomalie directement au champ concerné dans votre propre interface.
header.<champ> · items.<n>.<champ> · documents.<category> · global
{
"id": "4c749e25-3408-48f9-b3ca-b18a7ad84681",
"createdAt": "2026-09-16T12:46:13.186Z",
"type": "import-export",
"locale": "en",
"reference": "PO-2026-114",
"score": 90,
"level": "good",
"counts": { "errors": 0, "warnings": 2, "infos": 0 },
"documents": { "commercialInvoice": "available", "packingList": "missing" },
"issues": [
{
"severity": "warning",
"code": "docPackingListMissing",
"path": "documents.packingList",
"rule": "DOC-002",
"params": null,
"field": "Packing list",
"message": "Packing list not provided",
"text": "Packing list not provided"
},
{
"severity": "warning",
"code": "docTransportMissing",
"path": "documents.transportDocument",
"rule": "DOC-003",
"params": null,
"field": "Transport document (B/L, AWB, CMR)",
"message": "Transport document not provided",
"text": "Transport document not provided"
}
],
"actions": [
{ "severity": "warning", "code": "docPackingListMissing",
"path": "documents.packingList", "text": "Add: Packing list" }
],
"tips": [],
"engine": { "version": "1.0.0", "rules": 13 }
}Découvrir les champs
Les types de déclaration et leurs champs sont publics, aucune clé n'est nécessaire. C'est la route à utiliser pour construire un formulaire, alimenter un mappage depuis votre ERP, ou donner à un agent le schéma qu'il doit remplir.
Les noms renvoyés ici sont exactement les clés à employer dans l'en-tête et dans chaque ligne de marchandise. Les listes d'options sont résolues et traduites ; ajoutez le paramètre pour les omettre si la réponse vous paraît trop lourde.
# The 8 declaration types
curl "https://www.customs-check.com/api/v1/declaration-types?locale=en"
# The fields of one type
curl "https://www.customs-check.com/api/v1/declaration-types/h7?locale=en"
# Same, without the resolved option lists
curl "https://www.customs-check.com/api/v1/declaration-types/h7?options=false"Traitement par lot
Jusqu'à 25 dossiers par appel. La réponse est toujours un succès dès lors que le lot est accepté, et chaque entrée porte son propre statut : un dossier mal formé ne fait jamais échouer les autres.
Si le quota restant ne couvre pas toutes les entrées valides, le lot entier est refusé plutôt que traité partiellement — vous n'avez jamais à deviner où le traitement s'est arrêté.
curl https://www.customs-check.com/api/v1/checks/batch \
-H "Authorization: Bearer $CUSTOM_CHECK_KEY" \
-H "Content-Type: application/json" \
-d '{ "checks": [ { "type": "h7", "header": {}, "items": [] } ] }'Quota
Chaque clé dispose de 500 contrôles par jour calendaire UTC. L'état courant accompagne chaque réponse authentifiée, vous n'avez donc jamais besoin d'un appel supplémentaire pour le connaître.
Les appels refusés sont comptés : un client qui boucle sur des requêtes invalides se limite donc lui-même. Le quota est fixé par clé — écrivez-nous s'il vous faut davantage.
X-RateLimit-Limit: 500
X-RateLimit-Remaining: 437
X-RateLimit-Reset: 1789603200
X-RateLimit-Policy: 500;w=86400Erreurs
Les messages d'erreur sont en anglais uniquement : ce sont des messages de protocole, destinés à des développeurs. Seul le contenu métier est traduit.
Chaque réponse porte un identifiant de requête, repris dans le corps. Citez-le lorsque vous nous contactez, il nous mène directement à l'appel concerné.
{
"error": {
"code": "invalid_request",
"message": "The request body failed validation.",
"details": [
{ "path": "items.0.quantity", "message": "expected a string" }
],
"requestId": "2bbb0946-6178-4b54-921c-b28f794c44bd"
}
}| Statut | code | Signification |
|---|---|---|
| 400 | invalid_json | Le corps n'est pas du JSON valide. |
| 422 | invalid_request | Le JSON est valide mais son contenu ne l'est pas. Le détail indique le champ fautif. |
| 401 | missing_credentials | En-tête Authorization absent ou mal formé. |
| 401 | invalid_key | Clé inconnue. |
| 401 | key_revoked | Clé révoquée. |
| 403 | account_suspended | Le compte propriétaire de la clé est suspendu. |
| 415 | unsupported_media_type | Le type de contenu n'est pas du JSON. |
| 413 | payload_too_large | Corps de requête trop volumineux. |
| 429 | rate_limit_exceeded | Quota journalier atteint. Voir l'en-tête Retry-After. |
| 500 | internal_error | Erreur de notre côté. Réessayez, puis signalez-la-nous avec l'identifiant de requête. |
Données et conservation
Les dossiers transmis par l'API sont des données de vos clients : nous en gardons le moins possible, et vous disposez d'un interrupteur pour n'en garder aucune.
- Envoyez « store » à false pour que rien du contenu ne soit écrit : seuls le score et les codes d'anomalies sont conservés.
- À défaut, le contenu des dossiers est purgé au bout de 30 jours.
- Révoquer une clé purge immédiatement le contenu des dossiers qu'elle a soumis.
- Les traitements ont lieu à Francfort et la base est hébergée dans l'Union européenne.
- Aucun fichier n'est déposé par l'API : vous déclarez seulement quels documents vous détenez.
200 items · 256 KB · 25 / batch · reference ≤ 64
Ce que cette API n'est pas
Le contrôle est une aide à la préparation. Il ne constitue pas une validation par l'administration des douanes, il ne dépose rien, et il ne remplace pas les obligations réglementaires applicables à votre opération.
Les codes douaniers sont vérifiés sur leur format et leur cohérence avec l'opération, jamais confrontés à une base tarifaire : un code bien formé reste un code à vérifier.