Where the code was entered decides how much the shopper is told. On the cart, the message gives the reason. On the checkout, every refusal comes back as "Discount code does not exist", whatever the reason. To find the real one, add the code to the cart (POST /cdna-api/cart/discount/<code>) and read data.cart.messages. Then, in order:

  1. "Code is not found". The code does not exist on this environment. Discounts are records, so a code created on staging does not exist on production until someone creates it there.
  2. "Code could not be added as its maximum usage is reached". Two causes are easy to miss:
    • Max uses is 0. In the admin, 0 forbids the code entirely. For no limit, leave the field empty.
    • Uses are counted from checkouts, not only orders. Every checkout that applied the code holds one use until the checkout ends, which for an abandoned one is 30 minutes after its last change. A code limited to 10 uses can be used up by 10 shoppers who reached the checkout and left. Uses by orders that were later refunded or cancelled still count.
  3. "This code cannot be applied because another code for the same discount is already in use". Only one code per discount can be applied at a time.
  4. "Code is not added as it is already added". It is already on the cart. Codes are matched without regard to case, so SPRING and spring are the same code.

A code that is accepted and gives no discount is a different case. An expired or not-yet-valid discount, or a cart that does not meet its conditions, adds the code with "Code has been added" and no discount, and a discount whose own maximum uses are reached stops applying the same way, without that message. Either way, compare discountTotal before and after adding a code, and tell the shopper the code "doesn't apply to this order" if it did not change (discounts).