Skip to content

Coupons ​

A coupon is a code a customer types into the cart to reduce their total. Ambikly supports percentage discounts, fixed cart discounts and fixed per-product discounts, each with product, customer, spend, schedule and usage restrictions. This page covers the Coupons screen, every field in the editor, how the limits are enforced, and what the customer sees when a code is rejected.

Coupons can be switched off store-wide with Enable Coupons in Ambikly → Settings → Store Settings. With it off, the cart page hides the coupon form and every code is rejected with Coupons are not currently accepted.

The Coupons screen ​

Ambikly → Coupons lists every coupon, 25 per page.

ColumnSortableNotes
CodeYesAlways stored and displayed uppercase
TypeNoPercentage, Cart discount or Product discount
AmountYesShown as 10% for a percentage, or as currency otherwise
Min spendNoBlank when there is none
UsageYesused / limit, or the count alone when unlimited
ExpiresYesRed when the expiry date has passed
StatusYesActive, Inactive or Expired
Actions—Edit and delete

The toolbar has a search box — matching code or description — and a status filter: All, Active, Inactive, Expired. A coupon whose expiry has passed is shown as Expired in the list even if its stored status still says Active.

Deleting a coupon stops it being applied to new orders. Orders that already used it are unaffected: an order keeps its coupon codes as plain text, not as a reference.

The coupon editor ​

Click Add Coupon, or edit an existing one. The editor has four sections. Nothing is saved until you click Save coupon, and leaving with unsaved changes prompts you first.

General ​

FieldTypeRequiredNotes
CodeTextYesWhat the customer types. Uppercased and trimmed on save. Must be unique
Discount typeSelectYesPercentage, Fixed cart or Fixed product discount
AmountNumberYesTwo decimals. Cannot be negative. Capped at 100 for a percentage
StatusSelectYesActive, Inactive or Expired. Only Active coupons can be applied
Description (internal)TextareaNoAdmin-only note. Never shown to customers, but it is searchable in the list

Saving a code that already exists returns Coupon code already exists. — on both create and edit.

Restrictions ​

FieldTypeNotes
Minimum spendNumberThe cart subtotal must be at least this much
Maximum spendNumberThe cart subtotal must not exceed this much
Restrict to these productsProduct pickerOnly these products count toward the discount. Leave empty for all products
Exclude these productsProduct pickerThese products never count toward the discount
Restrict to customer emailsChip inputOnly these email addresses may use the coupon. Leave empty for any customer
Individual use onlyCheckboxThis coupon cannot be combined with another
Exclude sale itemsCheckboxProducts currently on sale do not count toward the discount
Grant free shippingCheckboxForces the shipping total to zero

The two product fields are searchable pickers that query your published products and show each product's price alongside its name. Products already chosen are filtered out of the search, so a duplicate cannot be added. Editing a coupon re-loads the chosen products by name rather than by bare ID.

The email field accepts one address at a time — press Enter or comma to add each as a chip. A malformed address is rejected as you type. Matching is case-insensitive and ignores stray whitespace on either side, so a pasted address with a trailing space still matches.

There is no category restriction

Coupons restrict by product, not by category, tag or brand. Despite what the plugin readme says, no category field exists in the editor, the API or the discount calculation. To cover a category, add its products to Restrict to these products — and remember to update the coupon when you add products to that category.

Product include and exclude, and the email restriction, all work exactly as described above.

How restrictions shape the discount ​

The product and sale-item restrictions do not allow or block the coupon outright — they decide which cart lines count. Ambikly builds an eligible subtotal from the lines that survive all three filters, and every discount type is computed against that:

  1. If Restrict to these products is set, a line is eligible only if its product is on that list.
  2. If Exclude these products is set, a line on that list is dropped.
  3. If Exclude sale items is on, a line whose product is on sale right now is dropped. This is a live check, not a flag captured when the item was added to the cart.
  4. The surviving lines' price × quantity is the eligible subtotal.

So a 20% coupon on a cart of one eligible $50 item and one excluded $50 item discounts $10, not $20.

Usage limits ​

FieldTypeNotes
Total uses allowedNumberAcross all customers. Blank means unlimited
Uses per customerNumberPer customer, matched by customer record or by email. Blank means unlimited

The editor rejects a per-customer figure larger than the total limit.

Schedule ​

FieldTypeNotes
Starts atDate and timeBefore this moment the coupon is not active
Expires atDate and timeAfter this moment the coupon is not active

Both are entered in your own local time and stored in the store's timezone, so a coupon set to expire at midnight expires at midnight as the store sees it. The editor rejects an expiry that is not after the start.

A coupon is considered active only when its status is Active and the current time is inside the schedule. A coupon left with no dates is active as long as its status is.

The three discount types ​

Each is computed against the eligible subtotal described above, and the final discount is always clamped so it can never exceed the cart subtotal.

Percentage discount ​

The eligible subtotal × the amount, as a percentage. An amount above 100 is rejected on save by both the form and the server.

Cart: two eligible items at $30 and $70. A 15% coupon discounts $15.00.

Fixed cart discount ​

A flat amount off the cart, capped at the eligible subtotal. It is not pro-rated across lines.

Cart: one eligible item at $12 and one excluded item at $100. A $25 fixed-cart coupon discounts $12.00, not $25.00 — the excluded line cannot be discounted.

Fixed product discount ​

The amount, multiplied by the quantity, for every eligible line.

Cart: 3 units of an eligible product and 2 units of an excluded one. A $5 fixed-product coupon discounts $15.00.

Combining coupons ​

More than one coupon can be applied to a cart, and their discounts sum. Individual use only changes that:

  • Applying a coupon while an active individual-use coupon is already on the cart is refused with {CODE} cannot be combined with another coupon.
  • Applying an individual-use coupon clears every other coupon from the cart first.

An already-applied coupon that has since expired, been deactivated or hit its limit does not block a new one. It stops discounting, stays visible so the cart can flag it, and is ignored by the exclusivity check.

How usage limits are enforced ​

Validation when a code is applied is only advisory. The real enforcement happens once, at checkout, immediately after the order row is created and before any payment is attempted.

  1. The total limit is claimed with a single atomic conditional update: increment the usage count only if it is still below the limit. MySQL's row lock serializes concurrent attempts, so at most limit of them can ever succeed, however many arrive at the same instant.
  2. If that update affects no rows, the limit was already reached. The order is moved to failed, its stock is released, and checkout aborts with This coupon has reached its usage limit. No payment is taken.
  3. If a per-customer limit is set, the usage ledger is counted for this customer's ID or email. If they are already at the limit, the global slot claimed in step 1 is released again — so nobody else is blocked by this rejection — and checkout aborts with You have already used this coupon the maximum number of times allowed.
  4. Otherwise a row is written to the usage ledger recording the coupon, the order, the customer, their email and the discount amount.

Because the claim happens before the gateway runs, a customer is never charged for a discount that was not actually honored.

One narrow race remains

The per-customer check is a count followed by an insert, which is not itself race-proof against the same customer submitting two checkouts at the same instant. The cross-customer race — the one that matters for a limited-quantity promotion — is fully closed by the atomic update in step 1.

Applying a coupon at checkout ​

The customer enters the code in the coupon form on the cart page. The storefront posts it to POST /cart/coupons, the code is uppercased and trimmed, and the coupon is validated against the current cart. A code already on the cart is accepted as a no-op rather than an error.

Every applied coupon is then re-validated on every totals calculation, not only when it was applied. That matters because coupons are usually entered on the cart page, before checkout has collected an email or the cart has reached its final contents:

  • An email-restricted coupon is checked against the real checkout email, which checkout writes onto the cart before totals are computed.
  • A minimum-spend coupon stops discounting if the customer removes items and drops below the minimum.
  • A coupon that expires, is deactivated, or hits its limit while the cart sits open stops discounting immediately.

Failure messages ​

MessageCause
Enter a coupon code.Empty submission
Coupons are not currently accepted.Enable Coupons is off store-wide
Coupon does not exist.No coupon with that code
Coupon is not active or has expired.Status is not Active, or the current time is outside the schedule
Coupon usage limit reached.The total usage count has reached the limit
Minimum order of {amount} required.The cart subtotal is below the minimum spend
Maximum order of {amount} exceeded.The cart subtotal is above the maximum spend
Coupon not valid for this email.The email restriction does not include this customer
{CODE} cannot be combined with another coupon.An individual-use coupon is already applied
This coupon has reached its usage limit.Raised at checkout when the atomic claim fails
You have already used this coupon the maximum number of times allowed.Raised at checkout when the per-customer limit is reached

Coupons on the order ​

An order stores the comma-joined codes that were used and the discount amount as part of its totals. The usage ledger keeps the per-use detail — which coupon, which order, which customer, how much — which is what per-customer limits count against.

Coupon REST endpoints ​

Reading requires store-view permission; writing requires store-manage.

MethodRouteNotes
GET/couponsPaginated. Supports search, status, orderby, order, page, per_page
GET/coupons/{id}One coupon
POST/couponsCreate
PUT/coupons/{id}Update. Fields you omit are left alone
DELETE/coupons/{id}Delete
POST/cart/couponsPublic: apply a code to the current cart
DELETE/cart/coupons/{code}Public: remove an applied code

The server rejects a negative amount with Discount amount cannot be negative. and a percentage above 100 with Percentage discount cannot exceed 100., on both create and update.

PRODiscounts without codes

Dynamic Pricing applies rules automatically — quantity breaks, customer-group pricing, buy-one-get-one — with no code for the customer to type. Flash Sales runs scheduled, countdown-backed price drops across products or categories.

See pricing →

A product on a Flash Sales price counts as on sale for the Exclude sale items restriction, checked live at the moment totals are computed.

Next ​

Orders — the order list, statuses, and everything you can do to an order after it is placed.