Aller au contenu principal

Codes promo

Ces quatre endpoints gèrent les codes promo de la boutique, les codes que l'acheteur saisit au moment de commander pour payer moins. Ils travaillent sur les mêmes codes que la page des codes promo du dashboard, décrite dans Codes de réduction, et ils peuvent aussi renommer un code, ce que le dashboard ne permet pas.

La réduction d'un code s'applique au sous-total des produits, jamais à la livraison. Un code percentage prend ce pourcentage du sous-total. Un code fixed soustrait son montant en DZD et ne retire jamais plus que le sous-total. Un code ne peut pas être limité à un produit, une catégorie ou un client, ne peut pas plafonner la réduction sur un gros panier et ne peut pas offrir la livraison gratuite.

Avant de commencer​

  • L'add-on Codes promotionnels doit être activé sur la boutique (/dashboard/addons). La liste fonctionne sans lui et l'indique dans addon_enabled. Toute écriture répond 409 addon_inactive tant que l'add-on est inactif, et les acheteurs ne peuvent utiliser aucun code au moment de commander pendant ce temps.
  • La clé a besoin des portées des codes promo. Les clés créées depuis le dashboard (/dashboard/api) ont les deux. Les portées sont figées à la création de la clé : une clé qui ne les a pas répond 403 forbidden. Créez une nouvelle clé depuis le dashboard.
  • starts_at et expires_at sont à l'heure de l'Algérie, au format YYYY-MM-DD HH:MM:SS.
PortéeDescription
promos:readConsulter les codes promo.
promos:writeCréer, modifier et supprimer des codes promo. Cela change les prix payés par vos acheteurs.

L'objet code promo​

ChampTypeSignification
idintL'id du code dans la boutique.
codestringCe que l'acheteur saisit. En majuscules, A-Z, 0-9, - et _, unique dans la boutique.
discount_typestringpercentage ou fixed.
discount_valuenumberLe pourcentage (supérieur à 0, au plus 100) ou le montant en DZD.
min_order_amountnumber ou nullLe sous-total produits qu'une commande doit atteindre pour que le code s'applique. null veut dire aucun minimum.
max_usesint ou nullCombien de commandes peuvent utiliser le code. null veut dire illimité.
used_countintCombien de commandes l'ont utilisé. En lecture seule.
is_activeboolUn code inactif est refusé au moment de commander.
starts_atstring ou nullAvant cette date, le code est refusé. null veut dire qu'il fonctionne tout de suite.
expires_atstring ou nullAprès cette date, le code est refusé. null veut dire qu'il n'expire jamais.
created_at, updated_atstringYYYY-MM-DD HH:MM:SS, heure du serveur.

GET /v1/promo-codes​

Les codes de la boutique, du plus récent au plus ancien. Aucun appel ne lit un seul code par son id : parcourez cette liste.

Auth : clé plateforme avec promos:read.

Paramètres de requête​

ParamTypeDéfautNotes
is_activestringaucuntrue, 1, yes ou on renvoie les codes actifs. Toute autre valeur renvoie les codes inactifs. Omettez-le pour avoir tous les codes.
limitint50De 1 à 200.
cursorstringaucunLe next_cursor de la page précédente. Voir Pagination.

Requête​

curl 'https://api.dzbuild.app/v1/promo-codes?is_active=true' \
-H "Authorization: Bearer $DZ_KEY"

Réponse 200​

{
"data": {
"items": [
{
"id": 20,
"code": "WELCOME10",
"discount_type": "percentage",
"discount_value": 10,
"min_order_amount": 3000,
"max_uses": 100,
"used_count": 7,
"is_active": true,
"starts_at": null,
"expires_at": "2026-11-30 23:59:00",
"created_at": "2026-10-06 14:20:11",
"updated_at": "2026-10-06 14:20:11"
}
],
"next_cursor": null,
"has_more": false,
"addon_enabled": true
}
}

addon_enabled indique si l'add-on Codes promotionnels est activé. Quand il vaut false, la liste répond toujours, mais les écritures échouent et les acheteurs ne peuvent pas utiliser les codes.

POST /v1/promo-codes​

Crée un code. Il fonctionne au moment de commander dès sa création, sauf si vous envoyez is_active: false ou un starts_at dans le futur.

Auth : clé plateforme avec promos:write. Nécessite Idempotency-Key.

Corps​

ChampTypeRequisNotes
codestringouiLes espaces autour sont retirés et les lettres passent en majuscules, puis il doit faire de 2 à 30 caractères parmi A-Z, 0-9, - ou _. Un code qui existe déjà dans la boutique répond 409 code_exists.
discount_typestringouipercentage ou fixed, en majuscules ou en minuscules. Il n'y a pas de valeur par défaut.
discount_valuenumberouiSupérieur à 0. Au plus 100 pour percentage, et 100 demande la confirmation du marchand (voir la section sur la réduction de 100% plus bas). Aucune limite haute pour fixed.
min_order_amountnumber ou nullnonSous-total produits minimum en DZD. 0, "" ou null veut dire aucun minimum.
max_usesint ou nullnon1 ou plus. 0, "" ou null veut dire illimité.
is_activeboolnontrue par défaut. Envoyez un booléen JSON : une chaîne comme "false" est lue comme true.
starts_atstring ou nullnonUn format courant de date et d'heure, comme 2026-11-01 08:00 ou une chaîne ISO 8601. Enregistré au format YYYY-MM-DD HH:MM:SS à l'heure de l'Algérie ; une valeur avec un décalage UTC est convertie. null ou "" veut dire aucune date de début.
expires_atstring ou nullnonMêmes formats. Doit être dans le futur et après starts_at. null ou "" veut dire aucune expiration.
confirm_tokenstringnonSeulement pour une réduction de 100%.
confirm_full_discountboolnonSeulement pour une réduction de 100%.

Requête​

curl -X POST 'https://api.dzbuild.app/v1/promo-codes' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: promo-welcome10-create" \
-d '{"code": "welcome10", "discount_type": "percentage", "discount_value": 10, "min_order_amount": 3000, "max_uses": 100, "expires_at": "2026-11-30 23:59"}'

Réponse 201​

{
"data": {
"id": 20,
"code": "WELCOME10",
"discount_type": "percentage",
"discount_value": 10,
"min_order_amount": 3000,
"max_uses": 100,
"used_count": 0,
"is_active": true,
"starts_at": null,
"expires_at": "2026-11-30 23:59:00",
"created_at": "2026-10-06 14:20:11",
"updated_at": "2026-10-06 14:20:11"
}
}

PATCH /v1/promo-codes/{id}​

Change uniquement les champs que vous envoyez, avec les mêmes règles que la création. Un champ omis garde sa valeur.

Auth : clé plateforme avec promos:write. Nécessite Idempotency-Key.

  • code peut être changé. Le nouveau texte doit être libre dans la boutique, sinon l'appel répond 409 code_exists.
  • discount_type et discount_value sont vérifiés ensemble. Envoyer seulement discount_type: "percentage" sur un code fixed de 500 DZD répond 422 invalid_discount_value, parce que 500 dépasse 100. Envoyez les deux.
  • Un nouveau expires_at doit être dans le futur. Un code déjà expiré reste modifiable tant que vous n'envoyez pas expires_at.
  • used_count ne peut pas être écrit.
  • Un corps vide ne change rien et renvoie le code.
  • Un code d'une autre boutique répond 404, comme un code qui n'existe pas.

Requête​

curl -X PATCH 'https://api.dzbuild.app/v1/promo-codes/20' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: promo-20-extend" \
-d '{"max_uses": 200, "expires_at": "2026-12-31 23:59"}'

Réponse 200​

{
"data": {
"id": 20,
"code": "WELCOME10",
"discount_type": "percentage",
"discount_value": 10,
"min_order_amount": 3000,
"max_uses": 200,
"used_count": 7,
"is_active": true,
"starts_at": null,
"expires_at": "2026-12-31 23:59:00",
"created_at": "2026-10-06 14:20:11",
"updated_at": "2026-10-20 09:05:42"
}
}

DELETE /v1/promo-codes/{id}​

Supprime le code : les acheteurs ne peuvent plus l'utiliser. Les commandes déjà passées avec lui gardent leur réduction. Pour mettre un code en pause sans perdre son nombre d'utilisations, envoyez plutôt is_active: false avec PATCH.

Auth : clé plateforme avec promos:write. Nécessite Idempotency-Key.

Requête​

curl -X DELETE 'https://api.dzbuild.app/v1/promo-codes/20' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: promo-20-delete"

Réponse 200​

{
"data": {
"deleted": true,
"id": 20
}
}

Réduction de 100%​

Un code percentage à 100 rend les produits gratuits pour tout acheteur qui a le code. Une création, ou une modification qui envoie discount_type ou discount_value, n'est pas écrite au premier appel quand le résultat est un code percentage à 100% :

  1. L'appel répond 422 confirmation_required et n'écrit rien. L'erreur porte confirm_token (usage unique, valable 600 secondes), action et will_change, un résumé à montrer au marchand.
  2. Une fois que le marchand approuve, renvoyez le même corps avec confirm_token en plus et une nouvelle Idempotency-Key (la première clé est liée au corps sans le jeton). Un jeton expiré, déjà utilisé ou qui ne correspond plus à la requête répond 422 confirmation_stale avec un nouveau jeton.

Avec une clé créée depuis le dashboard, vous pouvez éviter cet aller-retour en envoyant confirm_full_discount: true dès le premier appel. Le DZBuild Copilot ne peut pas utiliser ce champ et passe toujours par le jeton.

{
"error": {
"code": "confirmation_required",
"message": "A 100% discount makes every order free ...",
"confirm_token": "cft_xxxxxxxxxxxxxxxx",
"confirm_token_expires_in": 600,
"action": "promo.full_discount:new",
"will_change": {
"action": "Create a promo code that makes orders free",
"code": "FREEGIFT",
"discount": "100% off the whole order subtotal",
"reversible": true,
"note": "Any customer with this code pays 0 for the goods. Orders already placed with it cannot be reversed by deleting the code."
}
}
}

Sur une modification, action se termine par l'id du code au lieu de new, et will_change.action devient Change promo code #20 to make orders free.

curl -X POST 'https://api.dzbuild.app/v1/promo-codes' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: promo-freegift-approved" \
-d '{"code": "FREEGIFT", "discount_type": "percentage", "discount_value": 100, "max_uses": 1, "confirm_token": "cft_REPLACE_WITH_TOKEN"}'

Historique des changements et annulation​

Chaque création, modification et suppression faite par l'API est enregistrée. Les codes modifiés sur la page du dashboard ne sont pas enregistrés, on ne peut donc pas les annuler par l'API.

  • GET /v1/changes?entity=promo_code liste les changements des codes promo, du plus récent au plus ancien, avec store:read. Chaque élément porte l'id du changement, l'id du code dans entity_id, l'action (create, update ou delete) et un summary.
  • POST /v1/changes/{id}/undo demande promos:write, une Idempotency-Key et l'add-on activé, comme toute écriture.
  • Annuler une modification remet les valeurs précédentes, sans confirmation, même une réduction de 100% ou une date d'expiration déjà passée. Si le code a été supprimé depuis, l'annulation répond 422 restore_target_missing.
  • Annuler une suppression recrée le code avec son nombre d'utilisations, et garde son id quand cet id est encore libre.
  • Annuler une création répond 422 nothing_to_restore : supprimez plutôt le code.
  • Le jeton d'une application installée ne peut ni lire ni annuler les changements : les deux répondent 403 forbidden.
curl -X POST 'https://api.dzbuild.app/v1/changes/500/undo' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: undo-500"
{
"data": {
"undone": true,
"change_id": 500,
"entity": "promo_code",
"undo_change_id": 510
}
}

Un changement annulé une seconde fois répond 409 already_undone.

Erreurs​

HTTPCodeCause
400bad_requestL'id dans le chemin n'est pas composé de chiffres, le corps n'est pas un JSON valide, ou Idempotency-Key manque ou est mal formé.
403forbiddenMissing scope: promos:read ou Missing scope: promos:write, ou API access requires an active Enterprise plan pour une clé du marchand dont la boutique n'a pas de plan Enterprise actif.
404not_foundAucun code promo avec cet id dans la boutique.
409addon_inactiveL'add-on Codes promotionnels n'est pas activé sur la boutique. Écritures seulement.
409code_existsUn autre code de la boutique a déjà ce texte.
422invalid_codecode fait moins de 2 ou plus de 30 caractères, ou contient un caractère autre que A-Z, 0-9, - et _.
422invalid_discount_typediscount_type manque, ou n'est ni percentage ni fixed.
422invalid_discount_valuediscount_value manque, n'est pas un nombre, vaut 0 ou moins, ou dépasse 100 pour percentage.
422invalid_min_order_amountmin_order_amount n'est pas un nombre.
422invalid_max_usesmax_uses n'est pas un nombre, ou est inférieur à 1.
422invalid_starts_at, invalid_expires_atLa date ne peut pas être lue.
422expires_at_in_pastLe expires_at envoyé n'est pas dans le futur.
422invalid_date_windowexpires_at n'est pas après starts_at.
422confirmation_required, confirmation_staleUne réduction de 100% attend l'accord du marchand. Voir la section plus haut.
422idempotency_key_reuseLa même Idempotency-Key a servi avec un autre corps ou un autre chemin.
500server_errorL'écriture a échoué. Réessayez avec la même Idempotency-Key.

Une réponse 4xx est conservée avec son Idempotency-Key pendant 24 heures et rejouée à tout réessai avec le même corps. Après avoir activé l'add-on ou corrigé le corps, envoyez l'appel avec une nouvelle clé. Les erreurs communes à tous les endpoints, comme 401, 402 et 429, sont dans Erreurs, et les règles de réessai dans Idempotence.

Limites connues​

  • Les utilisations peuvent dépasser max_uses. Quand plusieurs acheteurs commandent avec le même code au même moment, used_count peut finir au-dessus de max_uses.
  • Pas de webhook. Créer, modifier ou supprimer un code promo n'envoie aucun événement webhook.
Cette page pour les outils IAVoir en MarkdownOuvrir dans ChatGPTOuvrir dans Claude