Validate Single Coupon
Check whether one coupon can be used by a customer, optionally against the cart they are about to pay for, and reserve it while the order is completed.
{code} and checks its eligibility for use by a customer. You can also describe the cart, so the coupon is checked against what the customer is actually buying, and set lock to true to reserve the coupon so it cannot be spent elsewhere while the order is being completed.
Available on v4.0 and v4.1. Requires the Gameball Coupon Engine feature on your plan — accounts without it are rejected before any validation runs.
There are two ways to burn a coupon when placing an order:
- Option 1 — Use the coupon code directly in the Order API: Pass the coupon code in the Order API without needing the lock reference. The coupon burns automatically.
- Option 2 — Use the lock reference in the Order API: Pass the
lockReferencefrom this API intoredemption.couponsLockReferencein the Order API. The coupon burns automatically — no separate Burn Coupon API call is needed.
If your system uses different customer IDs across multiple channels (e.g., online and offline), Gameball’s channel merging feature helps unify customer profiles. By including the customer’s mobile number or email (based on your merging configuration) with each request, Gameball will combine activities into a single profile.For more information, head to the Omni-Channel Handling Guide.
Describing the cart
A coupon’s restrictions are only enforced when the request describes a cart, and whether it does is decided from that coupon’s own restrictions — see Eligibility checks. The fields that describe a cart fall into two groups, and the group decides how the restriction behaves.variantId on a line item is stored and echoed back on the coupon, but is never evaluated — there is no variant restriction.Size limits
lineItems accepts at most 500 entries, and any single ID list at most 200 values. A request over either limit is rejected with 400.
Example request
Example response
How validation works
A validate call answers three questions in order. The first failure ends the call — you get one error, never a list.Is the customer real and active in your Gameball program?
customerId, email or mobile.If you referenced an existing lock, is it still usable by this customer?
lockReference.Does the coupon exist, does it apply to this cart, and may this customer use it?
How restrictions are matched
A coupon can carry restrictions in five dimensions, plus a minimum order value. The group a restriction belongs to decides how it behaves.couponRulesLogicalOperator is returned on the coupon object and tells you how its item-level restrictions combine:
When lineItems is required
If a coupon has two or more item-level restrictions andcouponRulesLogicalOperator is 1 (AND), the flat lists cannot answer the question — they show that the basket holds a Sony item and an audio item, without showing whether one item is both. The call is rejected with code 9032, and you resend the same cart as lineItems.
In every other case lineItems is optional.
Matching rules
- Coupon codes and restriction values are compared case-insensitively, and surrounding whitespace is trimmed.
- Values within a single restriction are alternatives — matching any one of them is enough.
collectionIdandcollectionsIdsare evaluated together as one list.categoriesare free-text names, not IDs — whatever was typed when the coupon was configured, compared as plain strings.variantIdon a line item is stored and echoed back but never evaluated.
Eligibility checks
Whether a call is a cart question or an eligibility question is decided from the coupon’s own restrictions, not from which fields you happened to send. The request describes a cart when it carries data for a dimension this coupon restricts on. When it does, every restriction the coupon holds is enforced — including ones the request said nothing about. When it does not, the call is an eligibility question — “does this customer hold this coupon, and is it live?” — and the restrictions are reported back on the coupon instead, so you can discover what to send next. Every other check (active, dates, audience, limits) runs either way. A field the coupon does not restrict on is ignored as though it were never sent. SendingcollectionsIds to a coupon with no collection restriction neither satisfies anything nor triggers anything.
collectionsIds is only ever checked against a collection restriction, merchantId against a merchant restriction, totalPurchaseAmount against minOrderValue, and so on. When the coupon holds no restriction of that type, the field is dropped before matching — it cannot satisfy a different restriction, and it cannot cause a rejection.The coupon below restricts on collection only. Every other field in the request corresponds to nothing on it, so all of them are discarded, the call stays an eligibility check, and it returns valid: true.collectionsIds and the same call becomes a cart question.The minimum order value
minOrderValue behaves like any other restriction. totalPurchaseAmount is matched against it and nothing else, so on a coupon with no minOrderValue the amount is ignored outright — it cannot make the call a cart question. On a coupon that has one, the amount is enough to describe a cart on its own, and the minimum is then enforced whether or not you sent a value.
Locking a coupon
Setlock to true to reserve the coupon when it validates. The response carries a lockReference and a dateToExpire, and the coupon cannot be validated-and-locked by another order until the lock expires or is consumed.
lockReference it is checked before anything else, and must be unused, unexpired and belong to the same customer — otherwise the call fails with 9009 or 9010.
A lock is only ever created after the coupon has passed validation, so a returned lockReference always means the coupon was usable by that customer at that moment.
Locking without a cart
You can lock on an eligibility check. Send onlycustomerId with lock: true and no cart fields: a coupon that carries restrictions still validates — its restrictions are reported back rather than enforced — and it is still locked against that customer. The lock is built from the coupon code and the customer alone; the cart plays no part in it.
entitledCollectionIds, entitledCategoryIds, entitledBranchIds, entitledMerchantIds, entitledProductIds and couponRulesLogicalOperator off the response to see what the cart will have to satisfy.
Errors
Errors use the standard Gameball error envelope. Themessage names the specific values that failed, so it is the most useful field for diagnosing a rejection. It is returned in lower case.
By status
Customer and request errors
Coupon eligibility errors
All422.
Restriction errors
All422. A required code means the coupon restricts that dimension and your request described nothing for it. A not eligible code means you described it and the value was not on the coupon’s list.
9018 or 9024, because merchant and branch are checked in every mode.
Lock errors
lockDuration outside the permitted range is currently reported as the generic 4000 rather than the dedicated 9016. Read the message for the specific reason.What changed
This endpoint previously matched a coupon against two things only: the merchant and the collection. It now matches against four, and the request can describe the cart line by line.Behaviour changes on existing requests
Behaviour changes on existing requests
Restriction matching is now decided per coupon
Restriction matching is now decided per coupon
customerId and totalPurchaseAmount was enough to have a collection-restricted coupon rejected with 9020, for a dimension the caller never meant to describe.Enforcement is now decided from the coupon’s own restrictions. These affect calls you are already making, with no change on your side.couponRulesLogicalOperator modes and every error code are unchanged.Migration notes
Migration notes
- Add
branchIdif your coupons are branch-restricted. There is no other way to satisfy a branch restriction. - Choose between
lineItemsand the flat lists. Sending both is not an error, but the flat lists are silently ignored. If you are unsure, sendlineItems— it answers every case the flat lists do, plus the AND case they cannot. - Handle
9032by retrying withlineItems. It is not a permanent failure; it is a request for more detail about the same cart. - API v3 cannot satisfy the new restrictions.
POST /api/v3.0/integrations/coupons/{code}/validateaccepts onlymerchantIdandcollectionId, so a coupon restricted by branch, category or product is rejected with no field available to fix it. Move to v4 before configuring those restrictions.
Path Parameters
The coupon code you want to validate. Compared case-insensitively.
Body
Unique identifier for the customer that you can reference across the customer's whole lifetime. Could be a database ID, random string, email or anything that uniquely identifies the customer.
Customer's email address. Required if your account uses email-based channel merging.
Customer's mobile number. Required if your account uses mobile-based channel merging.
Indicates whether the request is intended to validate the coupon or to lock it for a future redemption.
Required only if the lock flag is set to True and you need to validate and lock a new or updated list of coupons within an existing lock session.
Represents the number of minutes for which a coupon will be locked if the lock flag is set to True.
Cart-level. The merchant the order is placed with. Required if the coupon is restricted to specific merchants.
"cairo-downtown"
Cart-level. The branch or outlet the order is placed at. Required if the coupon is restricted to specific branches. There is no plural or per-item form.
"branch-14"
Item-level. A collection the basket touches. Evaluated together with collectionsIds as a single list. Ignored when lineItems is present.
Item-level. Every collection the basket touches. Maximum 200 values. Ignored when lineItems is present.
200Item-level. Every category the basket touches. These are free-text category names, not IDs. Maximum 200 values. Ignored when lineItems is present.
200Item-level. Every product ID in the basket. Maximum 200 values. Ignored when lineItems is present.
200The cart described item by item. Maximum 500 entries. Required for a coupon that must satisfy two or more item-level restrictions on the same item. When lineItems is present, the flat collectionId, collectionsIds, categories and productsIds fields are ignored for matching.
500Cart-level. The total value of the purchase the coupon will be applied to. Checked against the coupon's minOrderValue. Sending this field describes a cart only when the coupon carries a minOrderValue; for those coupons it switches on full restriction enforcement, and omitting it is rejected the same way a value below the minimum is.
Response
Coupon validated successfully
Indicates whether the coupon is valid to be used by the customer or not.
A coupon as returned by the validate endpoints, including the restrictions it carries and how they combine.
The unique reference code associated with the coupon lock session.
The exact date and time when the coupon lock will expire.