Clé publiable
Une clé publiable est une clé d'API faite pour être lue en clair dans le JavaScript d'une page publique. Elle permet à votre site de demander lui-même « quels sont vos points de vente autour de moi ? » sans que votre serveur ait à relayer l'appel, et sans que votre clé secrète quitte votre infrastructure.
Elle se reconnaît à son préfixe tdp_, elle n'ouvre
qu'un seul endpoint — GET /locations/search — et elle ne
fonctionne que depuis les domaines que vous déclarez.
Deux choses à savoir avant de publier
Ces deux points ne sont pas des détails d'intégration : ils changent ce que vous mettez dans le compte qui émet la clé et ce que vous affichez sur votre page. Lisez-les d'abord.
La restriction par domaine n'est pas une frontière de sécurité
La liste de domaines empêche la réutilisation
opportuniste d'une clé que quelqu'un trouverait dans le
code de votre site : collée dans une autre page, elle ne répond
plus. Elle n'arrête pas un appel forgé hors
navigateur — un curl fabrique un en-tête
Origin en une ligne, et rien ne peut l'en empêcher.
Et elle ne distingue pas vos référentiels. Une clé publiable porte
l'identifiant de votre compte, et le paramètre
referentiel n'est borné par rien : qui lit la clé dans
le code de votre page peut interroger n'importe quel
référentiel de ce compte en devinant son code
(interne, test, prospects…),
et la seule différence entre une réponse pleine et une réponse
vide lui confirme qu'il existe.
Traitez donc le compte entier qui émet la clé comme public, au sens plein du terme : ne mettez sur ce compte que ce que vous accepteriez de voir affiché n'importe où. Ce qui ne doit pas l'être — un site pas encore ouvert, un commentaire interne, un contact direct de responsable — ne se met pas à l'abri en changeant de référentiel, puisqu'un autre référentiel du même compte est tout aussi atteignable. Il lui faut un autre compte, qui n'émet aucune clé publiable et que vous servez depuis votre serveur avec sa clé secrète.
L'attribution est à votre charge
Les adresses et les positions viennent du référentiel BAN officiel
(IGN) et de l'INSEE ; dès qu'une requête demande une durée de
trajet (duree) ou des distances routières
(distances=true), le calcul vient d'OpenStreetMap,
sous licence ODbL.
La réponse porte alors un champ attribution :
affichez-le sur votre page, visible là où le
résultat l'est. C'est votre page qui est publique, donc c'est à
elle de porter la mention. Voir
Attribution OSM.
Deux sortes de clés, deux usages
Clé secrète td_… |
Clé publiable tdp_… |
|
|---|---|---|
| Où elle vit | Sur votre serveur, dans vos variables d'environnement | Dans le code de votre page publique |
| Ce qu'elle ouvre | Toute l'API, selon votre plan | GET /locations/search, et rien d'autre |
| D'où elle s'appelle | De partout | Des domaines déclarés sur la clé |
| Ce qu'elle reçoit | La fiche complète de chaque site | Une projection réduite (voir plus bas) |
| Réaffichable | Non — montrée une seule fois à la création | Oui, autant de fois que nécessaire |
La clé publiable est réaffichable parce qu'elle est publique par construction : elle vit déjà dans le code source de votre page. La cacher dans l'espace client n'ajouterait aucune protection, et vous obligerait à redéployer votre site pour un copier-coller perdu.
Ne mettez jamais votre clé secrète dans une page
Une clé td_… placée dans du JavaScript est lisible par
n'importe quel visiteur, et utilisable par lui sur
l'intégralité de l'API — vos référentiels, vos écritures,
votre quota. C'est exactement le problème que la clé publiable
existe pour résoudre.
Émettre une clé publiable
Depuis l'espace client, écran Clés API, section Clés publiables, sous votre clé secrète :
-
Déclarez vos domaines, un par ligne. Le schéma
httpsest obligatoire, le domaine se donne seul — ni chemin, ni paramètre. - Confirmez par votre code TOTP. La création, comme la modification des domaines, demande une double authentification : ce n'est pas la clé qui est sensible, c'est le geste d'ouvrir un domaine de plus sur votre quota.
- Copiez la clé et posez-la dans votre page. Vous pourrez la relire plus tard depuis le même écran.
Écrire la liste des domaines
Deux formes sont acceptées, jusqu'à dix domaines par clé :
| Forme | Correspond à |
|---|---|
https://www.exemple.fr |
Cette origine exactement |
https://*.exemple.fr |
Tout sous-domaine : www.exemple.fr, boutique.exemple.fr… |
Le joker ne couvre pas le domaine nu : si votre site
répond aussi sur https://exemple.fr, listez les deux. Il
est ancré sur la fin du nom d'hôte, donc
https://exemple.fr.autre-site.com ne correspond pas.
Le port par défaut est ignoré (https://exemple.fr:443 et
https://exemple.fr sont la même origine). Un domaine
accentué se déclare sous sa forme punycode
(xn--caf-dma.fr) — c'est celle que le navigateur envoie.
Pas de localhost
Seul https est accepté : il n'existe pas de joker de
développement local, parce que n'importe qui peut servir une page
en local. Pour mettre au point votre intégration, utilisez le
domaine de votre environnement de recette.
Combien de clés par plan
| Plan | Clés publiables actives |
|---|---|
| Discovery | 0 — service non inclus |
| Starter | 2 |
| Growth | 5 |
| Business | 10 |
Plusieurs clés actives, c'est ce qui rend une rotation possible sans
coupure : vous émettez la nouvelle, vous déployez votre page, puis
vous révoquez l'ancienne. Une création au-delà du plafond est refusée
en 409 (capacite_cles_publiables_depassee),
sans tolérance — une clé se crée une par une.
Appeler depuis le navigateur
Rien ne change dans l'URL ni dans les paramètres : c'est le même
GET /locations/search que décrit le guide
Mes lieux. Seule la clé change.
<script>
const CLE = "tdp_live_VOTRE_CLE_PUBLIABLE";
const BASE = "https://api.trustydata.app/services/v1/locations/search";
async function pointsDeVenteProches(adresse) {
const url = BASE
+ "?referentiel=boutiques"
+ "&adresse=" + encodeURIComponent(adresse)
+ "&rayon=10&limit=10";
const reponse = await fetch(url, {
headers: { Authorization: "Bearer " + CLE },
});
if (!reponse.ok) {
const erreur = await reponse.json().catch(() => null);
// `detail.code` est stable : branchez vos messages dessus,
// jamais sur la phrase française qui l'accompagne.
console.warn("TrustyData", reponse.status, erreur?.detail?.code);
return [];
}
const data = await reponse.json();
return data.resultats;
}
pointsDeVenteProches("Lyon").then((sites) => {
for (const site of sites) {
console.log(site.nom_public, site.ligne_voie, Math.round(site.distance_m), "m");
}
});
</script>
Le navigateur envoie l'en-tête Origin de lui-même : vous
n'avez rien à ajouter, et vous ne pouvez pas le remplacer. La requête
de pré-vol OPTIONS déclenchée par l'en-tête
Authorization est traitée automatiquement.
Un refus est lisible par votre JavaScript
Un appel refusé revient avec un vrai code HTTP et un corps JSON que votre page peut lire, pas avec une erreur réseau opaque : vous pouvez afficher un message utile à votre visiteur. C'est délibéré — le contrôle est fait côté serveur, pas par une règle CORS restrictive qui vous priverait de la réponse.
Ce que la réponse contient — et ce qu'elle ne contient pas
L'enveloppe est identique à celle d'un appel avec clé secrète :
resultats, pagination,
point_central, portee et, le cas échéant,
attribution. Ce sont les sites qui sont
réduits.
{
"resultats": [
{
"id_externe": "LYON-01",
"nom_public": "Boutique Lyon 1er",
"description": "Ouverte le dimanche matin",
"ligne_voie": "11 Rue du Jardin des Plantes",
"ligne_complement": null,
"code_postal": "69001",
"commune": "Lyon 1er Arrondissement",
"pays": "FR",
"latitude": 45.770325,
"longitude": 4.832611,
"fuseau": "Europe/Paris",
"tags": ["terrasse"],
"donnees": { "surface_m2": 120 },
"contacts": [
{ "id_externe": "tel-1", "type": "telephone",
"valeur": "+33 4 78 00 00 00", "libelle": "Boutique", "ordre": 0 }
],
"liens": [
{ "id_externe": "page-1", "url": "https://exemple.fr/lyon-01",
"libelle": "Voir la boutique", "ordre": 0 }
],
"horaires_hebdo": [{ "jour": 1, "debut": "09:30:00", "fin": "19:00:00", "ordre": 0 }],
"horaires_exception": [],
"ouverture": {
"statut": "ouvert",
"prochaine_ouverture": null,
"prochaine_fermeture": "2026-09-06T19:00:00+02:00"
},
"distance_m": 743.4,
"distance_routiere_m": null,
"duree_s": null
}
],
"pagination": { "limit": 10, "offset": 0, "next_offset": null, "total_estime": 3 },
"point_central": { "lat": 45.764, "lon": 4.8357, "adresse_resolue": "Lyon", "precision": "commune" },
"portee": { "type": "rayon", "rayon_km": 10 }
}
Sont retirés, et ne peuvent pas être demandés :
| Champ absent | Pourquoi |
|---|---|
nom_interne |
Le nom que vous vous donnez à vous-même — souvent un code d'exploitation, jamais destiné au public |
statut |
Une recherche ne rend que des sites actifs : le champ ne dirait rien |
geocodage_source, geocodage_score, geocodage_statut, geocodage_le |
L'état de notre résolution d'adresse — de la plomberie, pas de l'information client |
etag, cree_le, modifie_le |
Utiles à une intégration serveur, sans usage sur une page publique |
Cette liste est une liste de champs conservés, pas une liste de champs cachés : un champ ajouté demain à la fiche d'un site n'apparaîtra pas dans cette réponse tant qu'il n'y aura pas été ajouté explicitement. Si votre page a besoin de la fiche complète, c'est un appel serveur avec votre clé secrète.
Les erreurs à traiter
Le champ detail est un objet avec un code
stable : branchez vos messages sur ce code, jamais sur la phrase qui
l'accompagne.
| Statut | detail.code | Ce qui s'est passé |
|---|---|---|
403 |
origine_absente |
La requête n'a pas d'en-tête Origin. Typiquement un appel serveur ou un curl : utilisez votre clé secrète. |
403 |
origine_non_autorisee |
Le domaine appelant n'est pas dans la liste de la clé. Vérifiez le sous-domaine exact, et que le joker n'a pas été pris pour couvrir le domaine nu. |
403 |
cle_publiable_hors_perimetre |
La clé a été utilisée sur un autre endpoint. Une clé publiable n'ouvre que GET /locations/search. |
401 |
— | Clé inconnue ou révoquée. Une révocation prend effet en moins d'une minute. |
429 |
— | Trop d'appels depuis la même adresse IP. Le refus vient de la couche réseau : il n'a ni corps ni en-têtes CORS, votre page le verra comme une erreur de requête. |
422 |
origine_invalide, trop_d_origines |
À l'émission de la clé, pas à l'appel : domaine mal formé, ou plus de dix domaines. |
Les erreurs propres à la recherche elle-même — 422
portee_ambigue, 403 de plan, 503
du moteur d'itinéraire — sont inchangées : voir
Codes d'erreur.
Débit, quota et facturation
Chaque appel depuis le navigateur d'un visiteur est un appel d'API
comme un autre : il est compté sur le quota du compte
propriétaire de la clé, et il suit son plan. Une clé émise par un
compte
Starter se verra
donc refuser duree, distances et
tags, qui demandent
Growth.
Une page à succès consomme votre quota
C'est la différence de nature avec un appel serveur : le volume ne dépend plus de vous, mais du trafic de votre page. Un débit maximal par adresse IP de visiteur protège du bourrage, mais pas d'un succès. Surveillez votre consommation, et gardez les alertes de quota (80 / 90 / 100 %) actives sur votre compte. Une astuce simple divise la facture par dix : ne lancez la recherche que lorsque le visiteur a fini de saisir sa ville, jamais à chaque frappe.
distances=true mérite une mention à part : il déclenche
jusqu'à 25 calculs d'itinéraire par requête. Sur une page publique,
ne le demandez que sur une action explicite du visiteur, pas au
chargement.
Faire tourner une clé, en révoquer une
Modifier la liste des domaines d'une clé ne change pas la clé : votre page continue de fonctionner, vous n'avez rien à redéployer. C'est le bon geste pour ajouter un domaine.
Pour remplacer une clé, procédez dans cet ordre : émettez la nouvelle, déployez votre page avec elle, vérifiez, puis révoquez l'ancienne. Une clé révoquée cesse de fonctionner en moins d'une minute — le temps du cache de validation — et elle n'est jamais supprimée, pour que votre historique de consommation reste lisible.
Ce qu'une clé publiable ne fera pas
- Aucune écriture. Créer, modifier ou synchroniser des sites reste un geste serveur, avec la clé secrète.
- Aucun autre endpoint. Ni la fiche d'un site, ni la liste de vos référentiels, ni la recherche d'adresses ou d'entreprises. Chaque ouverture nouvelle sera une décision explicite. Attention au sens exact : la liste de vos référentiels n'est pas lisible, mais la recherche, elle, atteint chacun d'eux dès que son code est fourni — voir l'avertissement ci-dessus.
- Aucun widget de carte fourni. TrustyData rend des données ; le rendu, les styles et la carte vous appartiennent.
Pour aller plus loin
- Mes lieux — alimenter le référentiel, et tous les paramètres de la recherche
- Clés API dans l'espace client — émettre, relire et révoquer vos clés
- Attribution OSM — la mention exacte à afficher
- Plans & quotas — ce que chaque plan ouvre, et le suivi de consommation
- Codes d'erreur — la table complète