annuaire-shopify

API annuaire Shopify : intégrer la donnée écosystème dans votre produit

L'API Storefront ou Admin de Shopify parle d'un seul marchand à la fois — celui de votre application. Une API d'annuaire parle de l'écosystème : les 70 000 boutiques Shopify recensées, les nouveaux marchands détectés. Ce guide pose la distinction, donne les endpoints, et fournit du code prêt à copier en curl, Python et Node.

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.json depuis 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ête Retry-After en 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, yotpo ne 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

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.

Décision simple

Vous voulez tester sur votre cible ?

Recevez 10 fiches d’exemple, sans carte bancaire, puis passez au CSV ou Pro si la donnée colle à votre marché.