Skip to main content
POST
cURL
This API validates a single coupon identified by {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 lockReference from this API into redemption.couponsLockReference in the Order API. The coupon burns automatically — no separate Burn Coupon API call is needed.
If you validate a coupon with lock: true and then call the Release Coupons API before placing the order, the lock is released. If you then try to use the coupon code directly in the Order API, the request will fail. Only release the lock if you are canceling the transaction entirely.
To validate several coupon codes against the same cart in one call, use Validate Multiple Coupons.
Channel Merging Available
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.
Security: Requires apikey and secretkey headers.

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.
Send lineItems or the flat lists, not both. When lineItems is present, the top-level collectionId, collectionsIds, categories and productsIds are ignored for matching — put every category, collection and product on the lines instead. The cart-level fields are always read from the top of the body.
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

cURL

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

Is the customer real and active in your Gameball program?

Resolved from customerId, email or mobile.
2

If you referenced an existing lock, is it still usable by this customer?

Resolved from lockReference.
3

Does the coupon exist, does it apply to this cart, and may this customer use it?

Runs the ordered checks below.
The third question runs these checks in this exact order. The order matters: a coupon that is both expired and wrong for the cart reports the cart problem, because restrictions are checked first.

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:
Merchant and branch are checked in every mode, including OR. An OR coupon restricted to one merchant still rejects a different merchant, no matter what else in the cart matches.

When lineItems is required

If a coupon has two or more item-level restrictions and couponRulesLogicalOperator 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.
  • collectionId and collectionsIds are evaluated together as one list.
  • categories are free-text names, not IDs — whatever was typed when the coupon was configured, compared as plain strings.
  • variantId on 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. Sending collectionsIds to a coupon with no collection restriction neither satisfies anything nor triggers anything.
A restriction you send that the coupon does not carry is ignored.Request data is matched to restrictions by type. 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.
Request
Response
No collection was sent, and nothing else in the body speaks to a restriction this coupon carries — so there is nothing to enforce, and nothing to reject. Send collectionsIds and the same call becomes a cart question.
valid: true on an eligibility call means “this customer may use this coupon”, not “this coupon applies to this order”. Read entitledCollectionIds, entitledCategoryIds, entitledBranchIds, entitledMerchantIds, entitledProductIds, minOrderValue and couponRulesLogicalOperator off the response to see what the cart will have to satisfy, then validate again with those fields populated before you complete the order. That second call can reject a coupon that just came back valid.

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.
A cart that omits totalPurchaseAmount no longer slips past a coupon that has a minOrderValue. Both “you sent too little” and “you sent nothing” return 9017; read the message to tell them apart.

Locking a coupon

Set lock 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. When you pass an existing 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 only customerId 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.
This is the intended way to reserve a coupon before the basket is known. Read entitledCollectionIds, entitledCategoryIds, entitledBranchIds, entitledMerchantIds, entitledProductIds and couponRulesLogicalOperator off the response to see what the cart will have to satisfy.
A cart-less lock does not prove the coupon fits the eventual cart. Restrictions were never evaluated, and nothing re-evaluates them later — not when the lock is reused, and not when the order is placed. Validate again with the full cart, reusing the same lockReference, before you complete the order: that re-runs the restriction checks against the real basket and keeps the same lock.

Errors

Errors use the standard Gameball error envelope. The message 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

All 422.

Restriction errors

All 422. 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. An OR coupon never returns a required code for a collection, category or product — a restriction with no cart data is skipped. It can still return 9018 or 9024, because merchant and branch are checked in every mode.

Lock errors

A 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.
These affect calls you are already making, with no change on your side.
Previously any cart field switched on enforcement of every restriction the coupon held. A body carrying nothing but 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.Error precedence, the couponRulesLogicalOperator modes and every error code are unchanged.
  • Add branchId if your coupons are branch-restricted. There is no other way to satisfy a branch restriction.
  • Choose between lineItems and the flat lists. Sending both is not an error, but the flat lists are silently ignored. If you are unsure, send lineItems — it answers every case the flat lists do, plus the AND case they cannot.
  • Handle 9032 by retrying with lineItems. 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}/validate accepts only merchantId and collectionId, 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.

Authorizations

apikey
string
header
required
secretkey
string
header
required

Path Parameters

code
string
required

The coupon code you want to validate. Compared case-insensitively.

Body

application/json
customerId
string
required

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.

email
string

Customer's email address. Required if your account uses email-based channel merging.

mobile
string

Customer's mobile number. Required if your account uses mobile-based channel merging.

lock
boolean

Indicates whether the request is intended to validate the coupon or to lock it for a future redemption.

lockReference
string

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.

lockDuration
integer

Represents the number of minutes for which a coupon will be locked if the lock flag is set to True.

merchantId
string

Cart-level. The merchant the order is placed with. Required if the coupon is restricted to specific merchants.

Example:

"cairo-downtown"

branchId
string

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.

Example:

"branch-14"

collectionId
string

Item-level. A collection the basket touches. Evaluated together with collectionsIds as a single list. Ignored when lineItems is present.

collectionsIds
string[]

Item-level. Every collection the basket touches. Maximum 200 values. Ignored when lineItems is present.

Maximum array length: 200
categories
string[]

Item-level. Every category the basket touches. These are free-text category names, not IDs. Maximum 200 values. Ignored when lineItems is present.

Maximum array length: 200
Example:
productsIds
string[]

Item-level. Every product ID in the basket. Maximum 200 values. Ignored when lineItems is present.

Maximum array length: 200
lineItems
object[]

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

Maximum array length: 500
totalPurchaseAmount
number

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

200 - application/json

Coupon validated successfully

valid
boolean

Indicates whether the coupon is valid to be used by the customer or not.

coupon
object

A coupon as returned by the validate endpoints, including the restrictions it carries and how they combine.

lockReference
string

The unique reference code associated with the coupon lock session.

dateToExpire
string<date-time>

The exact date and time when the coupon lock will expire.