API Storefront / Admin Shopify vs API d’annuaire : deux mondes distincts
C’est la confusion la plus fréquente quand un développeur arrive sur le sujet, donc on la pose en premier.
L’API Storefront et l’API Admin sont les deux APIs officielles de Shopify. Elles vivent toutes les deux sous le domaine du marchand : https://{shop}.myshopify.com/api/... (Storefront, GraphQL ou REST) et https://{shop}.myshopify.com/admin/api/... (Admin). L’authentification se fait avec un jeton d’accès attaché à un seul marchand, généralement obtenu via OAuth quand votre application est installée sur sa boutique. Ces APIs servent à un cas précis : votre application veut lire ou écrire des ressources qui appartiennent à ce marchand — produits, variantes, commandes, clients.
C’est exactement ce qu’il faut quand vous codez une application Shopify (avis, fidélité, livraison, comptabilité). Mais c’est inutilisable pour un cas d’usage transverse :
- Vous ne pouvez pas lister les boutiques Shopify qui utilisent Klaviyo, parce que vous n’avez pas de jeton sur ces 50 000 boutiques.
- Vous ne pouvez pas être notifié quand une nouvelle boutique Shopify Plus apparaît en France, parce que Shopify n’expose pas de flux multi-marchands à des tiers.
- Vous ne pouvez pas enrichir un compte HubSpot avec « est-ce que ce domaine tourne sous Shopify ? » sans explorer vous-même.
Une API d’annuaire raisonne à l’échelle de l’écosystème, pas à l’échelle d’un magasin :
- Endpoint sous votre propre domaine :
https://api.annuaire-shopify.fr/v1/stores?... - Une seule clé API par compte client (jeton Bearer), pas de OAuth par marchand.
- Réponses qui parlent de plusieurs marchands à la fois.
- Champs qui n’existent pas chez Shopify :
tld,theme_version,first_seen,last_verified.
Les deux APIs ne sont pas concurrentes, elles sont complémentaires.
Cas d’usage d’une API d’annuaire
Quatre patterns reviennent dans 90 % des intégrations clients.
1. Enrichir un CRM (HubSpot, Salesforce, Pipedrive, Attio). Votre équipe commerciale a un compte avec un domaine. Vous voulez savoir si ce domaine tourne sous Shopify, quel thème il utilise, depuis quand il existe. Flux : notification HubSpot sur création de compte → appel API annuaire avec le domaine → écriture des champs personnalisés dans la fiche compte.
2. Déclencher un flux de prospection sur les nouveaux marchands détectés. Vous voulez approcher chaque nouvelle boutique Shopify Plus française dans les 7 jours qui suivent sa détection. Flux : notification annuaire store.detected filtrée → enrichissement contact → ajout dans une séquence Lemlist ou Smartlead.
3. Alimenter un produit B2B avec une liste à jour. Vous éditez une place de marché de freelances Shopify, un comparateur de thèmes, un outil de découverte d’applications. Votre catalogue interne doit refléter l’état réel de l’écosystème.
4. Scoring et data science. Vous entraînez un modèle qui prédit la probabilité qu’un marchand passe sur Shopify Plus dans les 12 mois. Vous avez besoin d’un échantillon avec étiquettes, avec caractéristiques theme, theme_version, first_seen.
Pour le profil développeur complet, voir le cas d’usage développeurs d’outils Shopify.
Authentification : jeton Bearer
L’API utilise un schéma jeton Bearer classique. La clé est générée dans le tableau de bord.
curl -H "Authorization: Bearer $API_KEY" \
"https://api.annuaire-shopify.fr/v1/stores?limit=10"
Trois règles d’hygiène qu’il faut rappeler :
Ne commitez jamais la clé. Variable d’environnement (API_KEY dans .env ignoré par git pour le dev local), gestionnaire de secrets pour la production.
Une clé par environnement. Une clé pour staging, une autre pour production.
Rotation prévue. L’API supporte plusieurs clés actives par compte.
Endpoint principal /v1/stores
C’est l’endpoint que vous utiliserez à 90 %. Il liste les boutiques Shopify de la base, avec filtres et pagination.
Paramètres de requête
| Paramètre | Type | Exemple | Effet |
|---|---|---|---|
tld |
string | fr, com, de |
Filtre par extension de domaine. |
theme |
string | Dawn, Prestige, Impulse |
Nom exact du thème détecté. |
theme_version |
string | 12.0.1 |
Version exacte. |
first_seen_after |
date ISO | 2026-01-01 |
Marchands ajoutés à la base après cette date. |
updated_since |
date ISO | 2026-04-20T00:00:00Z |
Pour les synchronisations incrémentales. |
domain |
string | exemple.fr |
Recherche directe sur un domaine précis. |
limit |
int | 100 (max) |
Nombre de résultats par page. |
cursor |
string | eyJp... |
Curseur de pagination. |
Note de transparence : les booléens techno secondaires (klaviyo, shopify_plus, judge_me, recharge, yotpo) ne sont pas en base aujourd’hui. C’est sur la roadmap publique — étapes 1 et 2. Quand ils seront livrés, ces paramètres seront ajoutés à l’API sans casser la signature existante.
Exemple curl simple
Lister les marchands sur extension .fr avec thème Prestige :
curl -H "Authorization: Bearer $API_KEY" \
"https://api.annuaire-shopify.fr/v1/stores?tld=fr&theme=Prestige&limit=100"
Réponse JSON typique :
{
"data": [
{
"id": "str_a8f3c2",
"domain": "exemple-marchand.fr",
"store_name": "Exemple Marchand",
"tld": "fr",
"theme": "Prestige",
"theme_version": "9.4.0",
"first_seen": "2024-08-12",
"last_verified": "2026-04-22"
}
],
"next_cursor": "eyJpZCI6InN0cl9hOGYzYzIifQ==",
"remaining_quota": 49823
}
Notifications automatiques (webhooks) sur les nouveaux marchands
Les notifications automatiques sont l’autre moitié de l’API. Plutôt que d’interroger /v1/stores?first_seen_after=... toutes les heures, vous laissez l’annuaire vous notifier en push dès qu’un événement correspond à votre filtre.
Événements supportés
store.detected— un nouveau domaine Shopify est ajouté à la base.store.updated— une fiche existante voit un de ses champs changer (nouveau thème, etc.).store.removed— un domaine ne répond plus à la signature/products.jsondepuis 14 jours.
Charge utile type
{
"event": "store.detected",
"id": "evt_2x9f3a",
"timestamp": "2026-04-27T08:14:22Z",
"data": {
"id": "str_b7d4e1",
"domain": "nouveau-marchand.fr",
"store_name": "Nouveau Marchand",
"tld": "fr",
"theme": "Dawn",
"first_seen": "2026-04-27"
}
}
Vérification de signature HMAC
Chaque POST inclut un en-tête X-Annuaire-Signature calculé en HMAC-SHA256 sur le corps brut, encodé hexadécimal.
import hmac
import hashlib
def verify(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
Deux pièges à éviter :
- Calculer la signature sur le corps brut, pas sur un JSON re-sérialisé.
- Utiliser
compare_digest(temps constant), pas==. Sinon vous exposez un oracle temporel.
Politique de retry
Si votre endpoint renvoie un statut non-2xx ou met plus de 10 secondes à répondre, l’annuaire retente avec un délai exponentiel : 1 min, 5 min, 30 min, 2 h, 8 h. Au-delà de 5 échecs consécutifs, la notification passe en paused.
Idempotence : chaque événement a un id unique. Indexez vos événements reçus sur ce champ avec un INSERT ... ON CONFLICT DO NOTHING pour éviter les doublons sur retry.
Code complet : Python
import os
import time
import requests
API_KEY = os.environ["API_KEY"]
BASE_URL = "https://api.annuaire-shopify.fr/v1"
def list_stores(filters: dict, limit: int = 100):
"""Itère toutes les boutiques correspondant aux filtres, avec gestion 429."""
cursor = None
while True:
params = {**filters, "limit": limit}
if cursor:
params["cursor"] = cursor
r = requests.get(
f"{BASE_URL}/stores",
params=params,
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=30,
)
if r.status_code == 429:
wait = int(r.headers.get("Retry-After", "5"))
time.sleep(wait)
continue
r.raise_for_status()
body = r.json()
for store in body["data"]:
yield store
cursor = body.get("next_cursor")
if not cursor:
break
if __name__ == "__main__":
for store in list_stores({"tld": "fr"}):
print(store["domain"], store["store_name"])
Code complet : Node
const API_KEY = process.env.API_KEY;
const BASE_URL = 'https://api.annuaire-shopify.fr/v1';
async function* listStores(filters, limit = 100) {
let cursor = null;
while (true) {
const params = new URLSearchParams({ ...filters, limit });
if (cursor) params.set('cursor', cursor);
const r = await fetch(`${BASE_URL}/stores?${params}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
if (r.status === 429) {
const wait = parseInt(r.headers.get('Retry-After') ?? '5', 10);
await new Promise((res) => setTimeout(res, wait * 1000));
continue;
}
if (!r.ok) throw new Error(`HTTP ${r.status}`);
const body = await r.json();
for (const store of body.data) yield store;
cursor = body.next_cursor;
if (!cursor) break;
}
}
(async () => {
for await (const store of listStores({ tld: 'fr' })) {
console.log(store.domain, store.store_name);
}
})();
Limites de débit, pagination, idempotence
Limites de débit
Sur le format Pro avec API à 199 €/mois, les quotas sont :
- 50 000 appels / mois sur l’ensemble des endpoints.
- 20 requêtes / seconde en pic court.
- Au-delà : statut HTTP
429 Too Many Requests, en-têteRetry-Afteren secondes.
Pagination par curseur
L’API utilise un curseur opaque, pas un décalage. C’est volontaire : sur une base qui change, un décalage numérique saute ou duplique des lignes. Le curseur garantit la cohérence de l’itération.
Idempotence sur écritures
Pour les futurs endpoints en POST/PATCH, l’API supporte un en-tête Idempotency-Key.
Précisions sur le format Pro avec API
Transparence d’abord :
- Quotas durs. 50 000 appels API / mois, 5 notifications automatiques actives, 3 sièges, 20 000 boutiques accessibles / mois. Au-delà, statut 429.
- Pas d’engagement de service contractuel sur ce format. Disponibilité 99,5 % annoncée en meilleur effort. Pour un engagement contractuel avec pénalités, c’est un accord sur mesure.
- Détection automatisée techno secondaire en cours. Les booléens
klaviyo,shopify_plus,judge_me,recharge,yotpone sont pas en base aujourd’hui — c’est sur la roadmap. - Champ secteur sur la roadmap.
- Pas de SDK officiel. REST + JSON, documentation OpenAPI 3.1.
- Géo-distribution mono-région. Servi depuis AWS eu-west-3 (Paris).
Quand passer en accord sur mesure
Le format Pro avec API couvre la majorité des intégrations développeur solo ou au début. Vous basculez en accord sur mesure si un de ces signaux est vrai :
- Plus de 50 000 appels / mois sur 2 mois consécutifs.
- Besoin de fraîcheur soutenue.
- Enrichissement personnalisé. Champs métier qui n’existent pas en standard.
- Engagement de service contractuel avec pénalités.
- Notifications automatiques illimitées.
Voir aussi
- Reconnaître un site Shopify — les 4 signatures techniques.
- Combien de boutiques Shopify y a-t-il en France ? — méthodologie reproductible.
- Extraire une liste de boutiques Shopify — outil maison vs API vs achat.
- Prospecter les boutiques Shopify en B2B — pourquoi Apollo et Sales Navigator ne suffisent pas.
- RGPD prospection B2B e-commerce — base légale et opt-out.
Documentation API complète sur la page produit API · Tarifs sur la page tarifs · Cas d’usage développeurs d’outils · Retour au panorama des guides · Retour à l’accueil.