Si vous construisez des vitrines pour des clients — agences, freelances, prestataires de fulfillment, opérateurs de marketplace — l'API DZBuild est conçue pour être votre colonne vertébrale opérationnelle.
Ce guide est pour vous si l'un de ces points s'applique :
Vous gérez 5+ boutiques DZBuild pour différents clients.
Vous facturez vos clients par commande ou au mois et avez besoin d'un signal d'usage fiable.
Vous construisez des thèmes ou vitrines personnalisés pour le compte de clients.
Vous vendez DZBuild en white-label (« MyAgency Commerce, propulsé par DZBuild »).
Vous voulez scripter des opérations en masse : import produits, mise à jour prix, confirmation de commandes.
Comment les revendeurs utilisent l'API en pratique
Setup typique :
┌─────────────────────────┐
│ Votre back-office / │
│ dashboard agence │
│ (votre code, votre UI) │
└──────────┬──────────────┘
│ Bearer dzpk_live_…
▼
┌─────────────────────────────┐
│ api.dzbuild.app/v1/* │
└──────────┬──────────────────┘
▼
┌──────────┬─────────┬──────────┐
│ Boutique A │ Boutique B │ Boutique C │ ← clients que vous gérez
└──────────┴─────────┴──────────┘
Chaque client a sa propre boutique DZBuild (son compte marchand, son plan, ses commandes). Vous détenez une clé API par boutique et orchestrez tout — onboarding, customizing, reporting — depuis votre propre dashboard.
Modèle de clés pour revendeurs
Pas de type « clé revendeur » spécial, et pas de clé transversale entre boutiques. Chaque revendeur travaille avec une clé plateforme par boutique cliente, et POST /v1/keys est strictement limité à la boutique à laquelle appartient déjà la clé appelante.
A) La première clé du client est émise par DZBuild, puis vous est remise
Les clés se créent depuis le dashboard marchand, dans Paramètres → API (/dashboard/api), par le propriétaire de la boutique (plan Enterprise, au plus 3 clés actives par boutique) — intégrer un client signifie donc qu'il génère une clé et vous la remet, ou que vous la générez ensemble. Tant que le pilote dure, le support DZBuild peut aussi émettre et inscrire des clés. Vous stockez les secrets clients dans votre back-office, chiffrés, et chaque opération sur le client X utilise la clé du client X.
Pour : consentement clair, le client possède la clé, peut la révoquer. Contre : friction d'onboarding — une étape humaine par boutique.
B) Vous créez vous-même des clés supplémentaires pour une boutique dont vous avez déjà une clé
Dès que vous avez une clé pour une boutique, vous pouvez en créer d'autres pour cette même boutique sans contacter personne :
curl -X POST 'https://api.dzbuild.app/v1/keys' \
-H "Authorization: Bearer $CLIENT_X_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"type":"platform","name":"agency-reporting"}'
# HTTP 200 → { "data": { "key_id", "bearer_token", "signing_secret", "note" } }
La nouvelle clé hérite du tier de rate limit et du flag pilote de l'appelante. Pratique pour séparer vos jobs de reporting de vos jobs d'écriture sur la même boutique.
Ce qui n'existe pas : il n'y a aucune configuration « umbrella agence », sur aucun plan, qui vous permette de créer des clés pour des boutiques dont vous n'avez pas déjà une clé. Onboarder une nouvelle boutique cliente commence toujours par l'émission, par DZBuild, de la première clé de cette boutique.
Imports produits en masse
Vous construisez un catalogue pour un client ? Boucle CSV → API :
import requests, csv, uuid, osKEY = os.environ['DZ_KEY_CLIENT_X']
HEADERS = {
'Authorization': f'Bearer {KEY}',
'Content-Type': 'application/json',
}with open('products.csv') as f:
for row in csv.DictReader(f):
body = {
'name': row['name'],
'price': float(row['price']),
'compare_price': float(row['compare_price']) if row['compare_price'] else None,
'sku': row['sku'],
'description': row['description'],
'stock_quantity': int(row['stock']),
'track_stock': True,
'status': 'active',
}
r = requests.post(
'https://api.dzbuild.app/v1/products',
headers={**HEADERS, 'Idempotency-Key': str(uuid.uuid4())},
json=body,
)
if r.ok: # 200, PAS 201 — aucune création v1 ne renvoie 201
print(f"OK {row['sku']} → id {r.json()['data']['id']}")
else:
print(f"FAIL {row['sku']}: {r.text}")
Deux bugs à éviter dans cette boucle, que la version naïve contient tous les deux :
Ne testez pas
201.POST /v1/productsrenvoie 200 ; un test== 201affiche FAIL pour chaque produit qu'il vient pourtant de créer avec succès.N'utilisez pas
uuid4()pour la clé d'idempotence. Une clé fraîche à chaque exécution signifie qu'une ré-exécution crée des doublons au lieu de rejouer. Utilisez une clé déterministe commeimport-{client}-{sku}-{run}— ce que dit d'ailleurs l'astuce ci-dessous : gardez le code et l'astuce cohérents.
Astuces :
Utilisez une clé Idempotency déterministe (ex.
import-{client}-{sku}-{run}) pour que les retries skippent les lignes déjà importées. La réponse de chaque clé est mise en cache pendant 24 heures, erreurs comprises — changez de clé après avoir corrigé une requête invalide.Chaque boutique cliente que vous gérez via l'API doit être sur un plan Enterprise actif (l'API est réservée à Enterprise), ce qui autorise 600 req/min par boutique (partagées entre toutes ses clés) — ~1000 créations de produits demandent donc tout de même quelques minutes de temps réel. Cadencez autour de la moitié du plafond pour garder de la marge ; au-delà, vous obtenez
429 rate_limitedavec un en-têteRetry-After. Notez que les images de produits portent leur propre budget, plus serré — 10/min par boutique — si bien que les imports en masse avec photos sont cadencés par celui-ci, et non par la limite générale.Les uploads d'images passent par le dashboard pour l'instant ; l'API supportera les URL d'upload presigned en v1.1.
Opérations bulk sur commandes
⚠️ Attention — limit=200 est le plafond, pas « toutes »
limit est bridé à 200. Les deux scripts ci-dessous s'arrêtent là et ne vous disent rien de ce qu'ils ont manqué. Chaque réponse de liste porte has_more et next_cursor — bouclez dessus :
CURSOR=""
while :; do
PAGE=$(curl -sS "https://api.dzbuild.app/v1/orders?status=pending&limit=200${CURSOR:+&cursor=$CURSOR}" \
-H "Authorization: Bearer $KEY")
echo "$PAGE" | jq -r '.data.items[].id'
[ "$(echo "$PAGE" | jq -r '.data.has_more')" = "true" ] || break
CURSOR=$(echo "$PAGE" | jq -r '.data.next_cursor')
done
Les lectures de commandes ne sont par ailleurs jamais mises en cache (seuls les produits, les landing pages et la boutique le sont) : un balayage sur 50 boutiques clientes, ce sont 50 allers-retours non cachés, chacun comptant dans le budget par minute de cette boutique. Utilisez des fenêtres ?since= plutôt que de relire tout l'historique.
Confirmer toutes les pending d'un client
KEY="$(cat /etc/secrets/client-x.key)"
# 1. Lister pending
curl -sS 'https://api.dzbuild.app/v1/orders?status=pending&limit=200' \
-H "Authorization: Bearer $KEY" \
| jq -r '.data.items[].id' \
| while read OID; do
# 2. Confirmer chacune
curl -sS -X PATCH "https://api.dzbuild.app/v1/orders/$OID" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: confirm-$OID" \
-d '{"status":"confirmed"}'
done
Rapport de revenu quotidien sur tous les clients
clients = json.load(open('clients.json')) # [{name, key}, ...]
today = date.today().isoformat() + 'T00:00:00Z'for c in clients:
orders = requests.get(
f'https://api.dzbuild.app/v1/orders?since={today}&limit=200',
headers={'Authorization': f'Bearer {c["key"]}'},
).json()['data']['items']
revenue = sum(o['total'] for o in orders if o['status'] == 'delivered')
print(f"{c['name']}: {len(orders)} commandes, {revenue} DZD")
White-labeling
Vous voulez que vos vitrines aient l'aspect de votre marque, pas DZBuild. L'API le permet :
Construisez le front-end vous-même avec n'importe quelle stack/branding (voir Thèmes & vitrines personnalisés).
Utilisez votre propre domaine (
shop.yourbrand.com) — pointez-le vers votre vitrine custom, qui parle à DZBuild via API.Le dashboard marchand sur
dzbuild.com/dashboardreste DZBuild-brandé — c'est là que vous (ou votre client) confirmez les commandes. Vos clients finaux ne voient jamais DZBuild.
Il n'existe pas de dashboard marchand en white-label, sur aucun plan. Le seul levier de branding qui existe est hide_branding (plan Unlimited et au-delà), qui retire le branding DZBuild de la vitrine du marchand — pas du dashboard. Sa valeur actuelle est exposée sur GET /v1/store. S'il vous faut davantage, parlez-en aux ventes plutôt que de planifier autour d'un produit qui n'existe pas encore.
Webhooks pour revendeurs
Enregistrez un webhook par boutique cliente pointant sur votre back-office :
curl -X POST 'https://api.dzbuild.app/v1/webhooks' \
-H "Authorization: Bearer $CLIENT_X_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"url": "https://api.youragency.com/dz-hooks?store=client-x",
"events": ["order.created","order.confirmed","order.shipped","order.delivered","order.cancelled"]
}'
Utilisez le query parameter ?store=client-x pour qu'un seul endpoint gère tous les clients — et gardez le reste du chemin indevinable, car les signatures API v1 ne peuvent pas actuellement être vérifiées avec le secret par client (les livraisons ne sont pas signées avec). Confirmez tout ce qui compte en relisant GET /v1/orders/{id} avec la clé de ce client. Voir Vérifier les signatures.
Prévoyez aussi le trou de couverture : en API v1, order.created ne se déclenche que pour les commandes créées via POST /v1/orders, et les événements de statut uniquement pour les changements faits via l'API. Si vos clients prennent des commandes sur leur vitrine DZBuild et les confirment au dashboard, vous ne verrez rien ici — soit vous pollez GET /v1/orders?since=... par boutique, soit chaque client active l'addon Webhooks sans code sur /dashboard/webhooks (plan Unlimited et au-delà), qui couvre toutes les sources de commandes.
Comptes multi-boutique
Certains clients gèrent plusieurs boutiques sur un compte DZBuild (feature Multi-store). Chaque boutique a sa propre clé — indépendantes. Nommez-les clairement dans votre coffre :
DZ_KEY_CLIENT_X_BRAND_A=dzpk_live_... DZ_KEY_CLIENT_X_BRAND_B=dzpk_live_...
Plans — ce qu'on recommande
Chaque boutique que vous gérez via l'API doit être sur un plan Enterprise actif. L'API est réservée à Enterprise : sur tout autre plan — ou avec un abonnement Enterprise expiré — chaque appel renvoie 403 forbidden, quelle que soit la clé utilisée, et aucune nouvelle clé ne peut être créée pour la boutique.
Pour les boutiques clientes que vous n'automatisez pas (elles n'utilisent que le tableau de bord et la vitrine), les autres plans s'appliquent comme d'habitude :
Taille client | Plan recommandé | Pourquoi |
0–30 commandes/mois | Free | Validez l'idée avant de vous engager — mais le plan Free plafonne la boutique à 30 commandes par mois calendaire, après quoi |
30–500 commandes/mois | Pro | Lève le plafond mensuel de commandes |
500–2000 commandes/mois | Unlimited | Pas de plafond de commandes, plus |
2000+ / multi-brand / toute automatisation API | Enterprise | Contrat custom, support prioritaire — et le seul plan avec accès API |
ℹ️ Info — Le plan conditionne l'accès à l'API
Le plan d'abonnement de la boutique conditionne son accès à l'API : seules les boutiques sur un plan Enterprise actif peuvent créer des clés ou effectuer des appels API (600 req/min par boutique, partagées entre ses clés — voir Limites de taux). Rétrogradez un client, ou laissez son abonnement Enterprise expirer, et ses clés cessent de fonctionner immédiatement (403 forbidden) ; repassez-le sur Enterprise et les mêmes clés reprennent — rien à réémettre. L'inscription au pilote reste requise tant que le pilote dure — sans elle, chaque appel renvoie 403 forbidden "API is in pilot mode; key not enrolled".
Facturer vos clients
L'API vous donne des signaux d'usage fiables :
GET /v1/usage— count des appels API du mois en cours, par groupe d'endpointsGET /v1/usage/history— des lignes horaires (period_hour,endpoint_group,count,billable_count) sousdata.rows. Porte par défaut sur les 7 derniers jours et accepte une fenêtre de 90 jours maximum via?from=&to=; au-delà, retour400 bad_request "range too large (max 90 days)". Une année complète, ce sont donc cinq fenêtres de 90 jours à parcourir.GET /v1/orders?status=delivered&since=...— pour des modèles de commission par commande (souvenez-vous du plafond de 200 lignes par page et denext_cursor)
La plupart des revendeurs facturent :
Forfait mensuel fixe pour l'hébergement vitrine + revente de la licence DZBuild
% de commission sur les commandes livrées (lu via
?status=delivered)Ou un abonnement bundlé (ex. « 10000 DZD/mois pour tout »)
Choisissez le modèle attendu par votre marché.
Conseils opérationnels
Un environnement par client. Secrets dev en dev. Secrets prod en prod. Jamais de mélange.
Utilisez des Idempotency-Keys déterministes pour toute boucle de retry (surtout imports en bulk / confirmations en bulk).
Cachez les lectures produits.
GET /v1/products,GET /v1/landing-pagesetGET /v1/storesont mis en cache pendant 30 s, et vous pouvez ajouter une couche 5 min par-dessus — les produits changent rarement à la minute. Les lectures de commandes ne sont jamais mises en cache : prévoyez un aller-retour complet à chaque fois.Auto-rate-limitez-vous. Ne montez pas au plafond de votre tier dès que vous le pouvez — laissez de la marge pour le trafic organique du marchand.
Mettez des alertes Telegram sur
429 rate_limited,5xx, ou échecs de webhook.Audit trimestriel : rotation des clés pour les boutiques que vous ne gérez plus. Utilisez
DELETE /v1/keys/{key_id}.
Référence
Authentification — Bearer + DZ-Public
Idempotence — requise sur toutes les écritures
Limites de taux — caps par tier
Webhooks — push au lieu de polling
Thèmes & vitrines personnalisés — build headless complet