Documentation · API de vérification
Liste de vérification d’intégration
Ce qu’il faut décider, construire et tester avant la mise en production de la vérification Crown Intelligence dans votre système : la collection, la correspondance des champs, le seuil de correspondance, la façon dont les correspondances possibles sont examinées et consignées, la mise à jour des fiches, ainsi que la gestion des limites et des erreurs par l’intégration.
L’API de vérification n’exige aucune clé pour l’instant et répond aux requêtes anonymes. Les contrôles ci-dessous utilisent les points d’accès décrits dans le guide de l’API de vérification et la référence de l’API. La vérification automatisée ou systématique, ainsi que l’utilisation dans un processus d’affaires, nécessitent une licence commerciale en vertu de nos conditions d’utilisation. Confirmez ce point avant de connecter un système en production.
Choisir une collection
Chaque collection constitue un parcours de correspondance distinct. Choisissez celle qui correspond aux listes visées par vos obligations. Un registre n’est pas une collection en soi; pour restreindre une recherche à un registre, utilisez include_dataset.
| Collection | Parcours de correspondance | Contenu |
|---|---|---|
| default | /api/match/default | Chaque fiche active : sanctions, PEPs, interdiction de contracter, mesures d’application de la loi et autres listes de risques. |
| sanctions | /api/match/sanctions | Inscriptions de sanctions uniquement. |
| peps | /api/match/peps | Personnes politiquement vulnérables (PPV). |
| crime | /api/match/crime | Interdictions de contracter, mandats fiscaux et avis d’insolvabilité. |
| maritime | /api/match/maritime | Navires et fiches comportant un numéro IMO. |
Faire correspondre les champs du client à la requête de correspondance
Une requête de correspondance envoie jusqu’à 20 requêtes nommées dans un seul corps, chacune avec schema et properties. Utilisez votre propre ID de client ou de contrepartie comme clé de requête, afin que chaque réponse soit rattachée à votre fiche.
| Votre champ | Champ de correspondance | Règles |
|---|---|---|
| Nom, ou chaque graphie que vous détenez | properties.name | Tableau d’au plus 5 chaînes. Ajoutez une forme translittérée si vous en détenez une. Obligatoire, sauf si imoNumber ou mmsi est envoyé. |
| Date de naissance | properties.birthDate | YYYY, YYYY-MM ou YYYY-MM-DD. Envoyez la précision dont vous disposez; une année seule est valide. |
| Nationalité (personne) | properties.nationality | Code ISO 3166 à deux lettres, par exemple ca ou ru. |
| Pays de constitution (entreprise) | properties.country | Code à deux lettres. Le même champ accepte aussi le pavillon d’un navire. |
| Numéro IMO (navire) | properties.imoNumber | Sept chiffres, par exemple 9418286. |
| MMSI (navire) | properties.mmsi | Neuf chiffres. |
| Type de partie | schema | Person, Company, Organization, LegalEntity ou Vessel. Une fiche d’un type différent fait baisser le score (type_mismatch). Envoyez le type que vous connaissez plutôt que LegalEntity par défaut. |
Un point de départ qui fait correspondre une fiche client, envoie un lot avec reprises et affiche le meilleur résultat pour chaque partie.
import os, time, json, requests
BASE = os.environ.get("CROWN_API_BASE", "https://api.crownintelligence.net")
session = requests.Session()
session.headers["User-Agent"] = "my-screening-tool/1.0 ([email protected])"
def to_query(customer):
"""Map one customer record to a match query (see the field table above)."""
props = {"name": customer["names"][:5]}
if customer.get("birth_date"):
props["birthDate"] = [customer["birth_date"]] # YYYY, YYYY-MM or YYYY-MM-DD
if customer.get("nationality"):
props["nationality"] = [customer["nationality"]] # ISO 3166-1 alpha-2, e.g. "ca"
if customer.get("imo"):
props["imoNumber"] = [customer["imo"]] # seven digits
return {"schema": customer["schema"], "properties": props}
def match(collection, queries, limit=5, threshold=0.75, changed_since=None, retries=3):
"""POST /api/match with retries for 429 (honour Retry-After) and 5xx (back off)."""
params = {"limit": limit, "threshold": threshold}
if changed_since:
params["changed_since"] = changed_since
for attempt in range(retries + 1):
r = session.post(f"{BASE}/api/match/{collection}", params=params,
json={"queries": queries}, timeout=60)
if r.status_code == 429 and attempt < retries:
time.sleep(int(r.headers.get("Retry-After", "5")))
continue
if r.status_code >= 500 and attempt < retries:
time.sleep(2 ** attempt)
continue
r.raise_for_status()
return r.json()
customers = {
"C-1001": {"schema": "Person", "names": ["Igor Putin", "Игорь Путин"], "birth_date": "1953-03-30", "nationality": "ru"},
"C-1002": {"schema": "Vessel", "names": ["Selam"], "imo": "9418286"},
"C-1003": {"schema": "Person", "names": ["Zz Crown Checklist Testperson"], "birth_date": "1980", "nationality": "ca"},
}
queries = {cid: to_query(c) for cid, c in customers.items()}
out = match("default", queries, limit=3, threshold=0.75)
for cid, answer in out["responses"].items():
print(cid, answer["status"], "candidates:", answer["total"])
for hit in answer["results"][:1]:
print(" top:", hit["caption"], hit["score"], "match" if hit["match"] else "no match", hit["datasets"][:1])
print("checked_at:", out["checked_at"], "| collection:", out["collection"], "| threshold:", out["threshold"])
Définir le seuil et lire l’indicateur de correspondance
Chaque résultat comporte un score de 0 à 1 et un indicateur match, qui vaut true lorsque le score est égal ou supérieur à threshold. Le seuil par défaut est de 0.75 et la valeur par défaut de limit est de 5 résultats par requête (jusqu’à 50). Les résultats sous le seuil sont tout de même renvoyés avec match défini à false, ce qui permet aux réviseurs de voir les quasi-correspondances.
| Caractéristique | Ce qui est mesuré | Effet sur le score |
|---|---|---|
name_match | Alignement mot à mot du nom de la requête avec les noms et alias de la fiche. | Établit le score de base. |
dob_match | Date de naissance, selon la précision de la fiche. | +0.10 en cas de correspondance; 0 si seule l’année correspond; −0.25 si elle diffère. |
country_match | Nationalité ou code de pays. | +0.05 en cas de correspondance; −0.10 si elle diffère. |
identifier_match | Numéro IMO. | Au moins 0.98 en cas de correspondance; −0.30 s’il diffère. |
type_mismatch | La fiche est d’un type différent de schema. | −0.20. |
Traiter les correspondances possibles
Un résultat dont match est défini à true est une correspondance possible, et non une conclusion. Acheminez-le vers une file d’examen et conservez une décision pour chacun.
Consigner ce qui a été vérifié
Nous ne conservons pas le corps des requêtes; votre système doit donc tenir son propre registre de chaque vérification, y compris celles sans correspondance. Conservez la réponse telle qu’elle a été reçue et ajoutez les champs ci-dessous.
| Champ à consigner | Provenance |
|---|---|
| Votre ID de client ou de contrepartie | Votre système. |
| Requête telle qu’envoyée | Le corps de votre requête. |
| Collection et sa version | Le nom de la collection utilisée et son version provenant de /api/catalog au moment de la vérification. |
| Algorithme, seuil et limite | Les paramètres de requête que vous avez envoyés. La réponse reprend algorithm, threshold et limit. |
| Heure de la vérification | checked_at dans la réponse (UTC). |
| ID de la fiche, entité fusionnée, score et caractéristiques | Les éléments id, merged_entity, score et features de chaque résultat. |
| Registres, sujets et programme | Les éléments datasets, topics et programme de chaque résultat. |
| Décision, réviseur et date de la décision | Votre file de révision. |
Revérifier et surveiller
Les listes changent. Une partie blanchie le mois dernier peut produire une correspondance après une nouvelle inscription. Effectuez une nouvelle vérification selon un calendrier établi, et chaque fois qu’une collection est reconstruite.
import os, json, requests
BASE = os.environ.get("CROWN_API_BASE", "https://api.crownintelligence.net")
# Versions now, to compare with the versions stored at the last run
catalog = requests.get(f"{BASE}/api/catalog", timeout=30).json()
versions = {c["name"]: c["version"] for c in catalog["collections"]}
last_run = {"sanctions": "20261004022212-jhp"} # the version stored at the last run
changed = [name for name, v in versions.items() if last_run.get(name) not in (None, v)]
print("collections rebuilt since the last run:", changed)
# Only records added or changed since the last run (ISO 8601 date or time)
body = {"queries": {"C-1001": {"schema": "Person", "properties": {"name": ["Igor Putin"], "birthDate": ["1953"]}}}}
r = requests.post(f"{BASE}/api/match/sanctions", params={"limit": 10, "changed_since": "2026-10-01"},
json=body, timeout=60)
r.raise_for_status()
answer = r.json()["responses"]["C-1001"]
print("changed since 2026-10-01:", answer["total"], "candidates;", r.json()["filters"]["changed_since"])
# Entity lookup for the review screen
ent = requests.get(f"{BASE}/api/entity/379781867", timeout=30).json()
print(ent["id"], ent["name"], ent["register"], ent["list_type"], ent["listings"][0]["register"])
Limites de débit, nouvelles tentatives et volume
Le service de données comporte une limite de requêtes par adresse que l’exploitant peut activer. Elle est désactivée actuellement et aucun chiffre n’est publié. Les conditions se réservent le droit d’appliquer des limites ou des plafonds de volume à l’utilisation automatisée; convenez donc de vos volumes avec nous avant d’envoyer un lot important.
Tester avec des noms connus
Testez l’intégration avec des noms dont l’inscription est connue avant la mise en production, et conservez le jeu de tests dans le contrôle de version. Incluez :
Une vérification que nous avons effectuée pour cette page : la requête Igor Putin, année de naissance 1953 et nationalité ru, sur la collection de sanctions avec un seuil de 0.8, a retourné l’inscription aux sanctions avec un score de 1 et match défini à true. Les résultats dépendent de la construction utilisée; consignez donc la version de la collection à chaque exécution de test et répétez les tests après chaque reconstruction.
Vérifications avant la mise en production
Exemples
Les exemples ci-dessous sont des points de départ; exécutez-les dans un environnement de test avant de vous y fier. Définissez CROWN_API_BASE pour modifier l’adresse de base; la valeur par défaut est le service public.
Node.js : requête de correspondance
const BASE = process.env.CROWN_API_BASE ?? "https://api.crownintelligence.net";
const queries = {
vessel: { schema: "Vessel", properties: { name: ["Selam"], imoNumber: ["9418286"] } },
person: { schema: "Person", properties: { name: ["Igor Putin"], birthDate: ["1953-03-30"], nationality: ["ru"] } },
};
const params = new URLSearchParams({ limit: "3", threshold: "0.75" });
const res = await fetch(`${BASE}/api/match/maritime?${params}`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ queries }),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
for (const [key, answer] of Object.entries(data.responses)) {
const top = answer.results[0];
console.log(key, answer.status, answer.total, top ? [top.caption, top.score, top.match] : "no hits");
}
curl : versions des collections et une correspondance
# Versions of each collection, to see when a list was rebuilt
curl -s "$CROWN_API_BASE/api/catalog" | python3 -c 'import json,sys; [print(c["name"], c["version"]) for c in json.load(sys.stdin)["collections"]]'
# One party against the sanctions collection
curl -s -X POST "$CROWN_API_BASE/api/match/sanctions?limit=3&threshold=0.8&topics=sanction" \
-H "Content-Type: application/json" \
-d '{"queries":{"q1":{"schema":"Person","properties":{"name":["Igor Putin"],"birthDate":["1953"],"nationality":["ru"]}}}}'
Dernière mise à jour : 2026-10-10