Passer au contenu principal

Codes promo

Listez, créez, modifiez et supprimez les codes promo d'une boutique depuis votre code, avec la règle de l'add-on, la confirmation à 100% et l'annulation.

Écrit par Support

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ée

Description

promos:read

Consulter les codes promo.

promos:write

Créer, modifier et supprimer des codes promo. Cela change les prix payés par vos acheteurs.

L'objet code promo

Champ

Type

Signification

id

int

L'id du code dans la boutique.

code

string

Ce que l'acheteur saisit. En majuscules, A-Z, 0-9, - et _, unique dans la boutique.

discount_type

string

percentage ou fixed.

discount_value

number

Le pourcentage (supérieur à 0, au plus 100) ou le montant en DZD.

min_order_amount

number ou null

Le sous-total produits qu'une commande doit atteindre pour que le code s'applique. null veut dire aucun minimum.

max_uses

int ou null

Combien de commandes peuvent utiliser le code. null veut dire illimité.

used_count

int

Combien de commandes l'ont utilisé. En lecture seule.

is_active

bool

Un code inactif est refusé au moment de commander.

starts_at

string ou null

Avant cette date, le code est refusé. null veut dire qu'il fonctionne tout de suite.

expires_at

string ou null

Après cette date, le code est refusé. null veut dire qu'il n'expire jamais.

created_at, updated_at

string

YYYY-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

Param

Type

Défaut

Notes

is_active

string

aucun

true, 1, yes ou on renvoie les codes actifs. Toute autre valeur renvoie les codes inactifs. Omettez-le pour avoir tous les codes.

limit

int

50

De 1 à 200.

cursor

string

aucun

Le 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

Champ

Type

Requis

Notes

code

string

oui

Les 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_type

string

oui

percentage ou fixed, en majuscules ou en minuscules. Il n'y a pas de valeur par défaut.

discount_value

number

oui

Supé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_amount

number ou null

non

Sous-total produits minimum en DZD. 0, "" ou null veut dire aucun minimum.

max_uses

int ou null

non

1 ou plus. 0, "" ou null veut dire illimité.

is_active

bool

non

true par défaut. Envoyez un booléen JSON : une chaîne comme "false" est lue comme true.

starts_at

string ou null

non

Un 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_at

string ou null

non

Mêmes formats. Doit être dans le futur et après starts_at. null ou "" veut dire aucune expiration.

confirm_token

string

non

Seulement pour une réduction de 100%.

confirm_full_discount

bool

non

Seulement 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

HTTP

Code

Cause

400

bad_request

L'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é.

403

forbidden

Missing 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.

404

not_found

Aucun code promo avec cet id dans la boutique.

409

addon_inactive

L'add-on Codes promotionnels n'est pas activé sur la boutique. Écritures seulement.

409

code_exists

Un autre code de la boutique a déjà ce texte.

422

invalid_code

code fait moins de 2 ou plus de 30 caractères, ou contient un caractère autre que A-Z, 0-9, - et _.

422

invalid_discount_type

discount_type manque, ou n'est ni percentage ni fixed.

422

invalid_discount_value

discount_value manque, n'est pas un nombre, vaut 0 ou moins, ou dépasse 100 pour percentage.

422

invalid_min_order_amount

min_order_amount n'est pas un nombre.

422

invalid_max_uses

max_uses n'est pas un nombre, ou est inférieur à 1.

422

invalid_starts_at, invalid_expires_at

La date ne peut pas être lue.

422

expires_at_in_past

Le expires_at envoyé n'est pas dans le futur.

422

invalid_date_window

expires_at n'est pas après starts_at.

422

confirmation_required, confirmation_stale

Une réduction de 100% attend l'accord du marchand. Voir la section plus haut.

422

idempotency_key_reuse

La même Idempotency-Key a servi avec un autre corps ou un autre chemin.

500

server_error

L'é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.

Avez-vous trouvé la réponse à votre question ?