Discounts let you create coupon codes and automatic merchandise offers for a market. Use the read_markets scope to view discounts and write_markets to create or change them.
The API supports six discount types:
percentagereduces eligible merchandise by a percentage.fixed_amountsubtracts a currency-specific amount. Provide an amount for the store's base currency and any additional market currencies you support.buy_x_get_yrewards customers when a complete qualifying set is present.bundleapplies a fixed price or percentage saving to a complete group of products or variants.free_giftgrants gift-only products throughgift_modeandgift_items.tieredapplies the highest reached subtotal tier, usingtier_value_kindand ascendingtiersin the base currency.
Fixed savings, including tiers, are capped at the remaining eligible merchandise value. A threshold of 100 with 200 off is valid: at a subtotal of 100 the saving is 100, leaving zero merchandise value, never a negative amount. Tax, shipping and other charges follow their own rules.
Each type accepts the fields described for it below. Value, amounts, Buy X Get Y, bundle and gift fields sent with another type are rejected; tier_value_kind and tiers sent with another type are ignored. The limits endpoint lists the supported values, field limits, and configuration options: GET /markets/{marketId}/discounts/limits.
Discounts are applied to eligible merchandise before tax is calculated. Buy X Get Y, bundle and claimed gift offers use specific cart units, which no other such offer can use. Bundle savings are distributed proportionally across the participating order lines.
When a market allows discounts to combine, Buy X Get Y, bundle and gift offers apply first, then product-targeted offers, then order-wide offers. Each later discount is calculated from the amount remaining on the affected line. Tringify records these allocations in the order's pricing snapshot, so order reads and webhooks preserve the exact savings applied at checkout.
Coupon codes use letters A–Z, digits, hyphens and underscores, are stored in upper case, are unique within a market, and are matched without regard to case. Each discount also has a unique priority position. A discount is stored as active or disabled; active discounts may appear as scheduled, active, or expired according to their start and end dates. Unlimited usage limits are null in responses and webhooks; send -1 or null to set them.
Reading one discount returns its targeting and eligibility IDs; list records leave those arrays empty. Product, variant, collection, category, Buy X Get Y, bundle and gift labels are included when the token has read_products; customer names, email addresses, and customer-group names require read_customers. The can_view_products and can_view_customers fields indicate whether those related labels are available to the current token. Response dates starts_at, ends_at, created_at and updated_at are display strings in the store's time zone; starts_at_iso and ends_at_iso give local store time in the form create and update accept.
Create each discount type#
Percentage#
A coupon that takes 15% off two collections, capped at a maximum saving per currency and limited to one use per customer.
// POST /api/2025-01/markets/{marketId}/discounts
{
"name": "Spring Sale",
"type": "percentage",
"activation": "coupon",
"code": "SPRING15",
"priority": 10,
"value": 15,
"applies_to": "specific_collections",
"collection_ids": ["11111111-1111-4111-8111-111111111111", "22222222-2222-4222-8222-222222222222"],
"max_discount": { "USD": "40.00", "EUR": "36.00" },
"customer_eligibility": "everyone",
"per_customer_limit": 1,
"starts_at": "2025-03-01T00:00:00",
"ends_at": "2025-03-31T23:59:59"
}
Fixed amount#
An automatic offer that subtracts a set amount once the order reaches a minimum subtotal. Include the store's base currency; amounts for other market currencies are optional, and a currency without one uses the base amount converted at the market's rate.
// POST /api/2025-01/markets/{marketId}/discounts
{
"name": "$10 off orders over $75",
"type": "fixed_amount",
"activation": "automatic",
"priority": 20,
"amounts": { "USD": "10.00", "EUR": "9.00" },
"applies_to": "entire_order",
"min_subtotal": { "USD": "75.00", "EUR": "68.00" },
"exclude_sale_items": true,
"customer_eligibility": "everyone"
}
Buy X Get Y#
Buy two items from a collection and receive one free. bxgy_buy_items defines what qualifies, bxgy_get_items defines the reward, and bxgy_max_uses caps how many times one order may repeat the offer. Buy and Get independently accept simple products (product), exact variants (variant), collections, and categories; an item qualifies when it matches any target on its side. A variable parent must be expanded to exact variants. Each side may hold up to max_bxgy_items_per_discount targets of any mix of types. Collection and category membership matches the parent of a cart variant. Bought and reward items are always different units, even when the two sides overlap, and the cheapest qualifying items become the rewards, whatever their order in the cart. Rewards apply only when a complete qualifying set is present.
// POST /api/2025-01/markets/{marketId}/discounts
{
"name": "Buy 2 tees, get 1 free",
"type": "buy_x_get_y",
"activation": "automatic",
"priority": 30,
"bxgy_buy_quantity": 2,
"bxgy_get_quantity": 1,
"bxgy_get_type": "free",
"bxgy_max_uses": 3,
"bxgy_buy_items": [ { "item_type": "collection", "item_id": "11111111-1111-4111-8111-111111111111" } ],
"bxgy_get_items": [ { "item_type": "collection", "item_id": "11111111-1111-4111-8111-111111111111" } ],
"applies_to": "entire_order",
"customer_eligibility": "everyone"
}
Set bxgy_get_type to percentage or fixed with bxgy_get_value when the reward is reduced rather than free.
// BXGY examples: keep the quantities and reward fields above.
// Collection purchase -> exact variant reward
{"bxgy_buy_items":[{"item_type":"collection","item_id":"11111111-1111-4111-8111-111111111111"}],"bxgy_get_items":[{"item_type":"variant","item_id":"1043"}]}
// Exact variant purchase -> category reward
{"bxgy_buy_items":[{"item_type":"variant","item_id":"1043"}],"bxgy_get_items":[{"item_type":"category","item_id":"7"}]}
// Simple product purchase -> exact variant reward
{"bxgy_buy_items":[{"item_type":"product","item_id":"42"}],"bxgy_get_items":[{"item_type":"variant","item_id":"1043"}]}
Bundle#
A bundle prices a specific complete set. Every component must be present at its required quantity. A product component matches any variant of that product; a variant component matches only that variant, and variants may come from different products. Use bundle_value_mode fixed_price with bundle_prices, or percentage with bundle_percentage. Discount reads include a display-only parent_id for each resolved variant component, and its label includes both product and variant names. Do not send parent_id or label in component writes; write only item_type, item_id, and quantity.
// POST /api/2025-01/markets/{marketId}/discounts
{
"name": "Camera starter kit",
"type": "bundle",
"activation": "automatic",
"priority": 40,
"bundle_value_mode": "fixed_price",
"bundle_prices": { "USD": "499.00", "EUR": "459.00" },
"bundle_max_sets": 1,
"bundle_items": [
{ "item_type": "product", "item_id": "812", "quantity": 1 },
{ "item_type": "variant", "item_id": "1043", "quantity": 1 },
{ "item_type": "product", "item_id": "907", "quantity": 2 }
],
"applies_to": "entire_order",
"customer_eligibility": "everyone"
}
Free gift#
An automatic offer that lets the shopper claim one exact variant of a gift-only variable product. Use a simple gift-only product without variant_id, or identify an exact variant that belongs to a gift-only variable product.
// POST /api/2025-01/markets/{marketId}/discounts
{
"name": "Choose a free T-shirt",
"type": "free_gift",
"activation": "automatic",
"priority": 50,
"gift_mode": "offer",
"gift_items": [
{ "product_id": 42, "variant_id": 4201, "quantity": 1 }
],
"applies_to": "entire_order",
"customer_eligibility": "everyone"
}
Tiered#
An automatic offer with ascending base-currency subtotal thresholds. Only the highest threshold reached applies, judged on the merchandise subtotal before any discount. A tiered discount also accepts min_subtotal and max_discount, and applies them; it rejects min_quantity.
// POST /api/2025-01/markets/{marketId}/discounts
{
"name": "Spend more, save more",
"type": "tiered",
"activation": "automatic",
"priority": 60,
"tier_value_kind": "percentage",
"tiers": [
{ "min_subtotal": "100.00", "value": "10" },
{ "min_subtotal": "200.00", "value": "20" }
],
"applies_to": "entire_order",
"customer_eligibility": "everyone"
}
Target products and customers#
A percentage, fixed-amount or free gift discount can cover the whole order or selected products, exact variants, collections, or categories; for a free gift, the selection is what the shopper must buy to unlock the gift. With applies_to set to specific_products, use product_ids for simple products or whole variable products and variant_ids for exact variants. A whole variable product includes its current and future variants. You can mix both arrays, but do not include a variable product and one of its child variants in the same discount. The combined product and variant count cannot exceed max_products_per_discount. Eligibility can include everyone, selected customers, or selected customer groups. The detail response always includes the selected ids. Names and labels are included when your token can read the related products or customers.
// Percentage off one simple product, every variant of product 812, and one exact variant of another product
{
"type": "percentage",
"value": 15,
"applies_to": "specific_products",
"product_ids": [42, 812],
"variant_ids": [1043]
}
Schedule and control usage#
Coupon discounts require a code; automatic discounts apply when the order qualifies and the market's discount settings allow it. Add optional start and end dates, order conditions, total usage limits, and per-customer limits. A use is held when an order is placed and counts toward both limits while the checkout is unpaid; it is given back when the checkout expires unpaid or the order is cancelled, and, if refund_restores_usage is on, shortly after a full refund. A payment that arrives after its checkout expired keeps its use, even past the limit. Customers are recognised by account or by email address, so guest orders count toward that email's per-customer limit and disqualify it from first-order offers. usage_count includes held uses, and usage_held_count says how many are held. Disable an offer to pause it without losing its definition. When enabled, its current status follows its schedule.
Combine offers#
Market discount settings decide how offers combine. With stacking_mode single, one discount applies: every eligible automatic discount and every entered code are ranked together, and the first wins. With stack, every eligible automatic discount applies, plus entered codes in ranked order up to coupon_limit (automatic discounts do not count toward it). priority_mode sets the ranking: best_for_customer by each discount's own saving, manual by priority number, lowest first. Discounts are ranked one by one, not searched for the largest combined saving; when two rank equally, automatic discounts come first. With auto_coupon_combine false, codes apply only when no automatic discount applies; it has no effect in single mode. Buy X Get Y, bundle and claimed gift offers use specific cart units, and two of them cannot use the same units: the higher-ranked keeps them, and an offer that cannot get every unit it needs does not apply at all. Offers apply in three steps: Buy X Get Y, bundle and gift offers; then product, collection and category discounts; then order-wide discounts. Within a step they follow the ranking, and each uses the amount left after the earlier ones. With apply_to_quantity_priced false, items with quantity pricing get no discount and do not count toward minimum spend, minimum quantity or tiers. New settings apply the next time a cart or checkout is priced.
Read applied discounts#
Discounts reduce merchandise before tax is calculated. Orders retain the exact saving allocated to each order item, including free reward lines and proportional bundle savings. Use the order's saved pricing snapshot for reconciliation, refunds, and reporting rather than recalculating an old order from the discount's current definition.
Webhook events#
Endpoints#
Subscribe to these events when your app keeps a local view of discounts or needs to react when an offer changes. Create and update events contain the current discount definition. Delete events contain the id, market, and last known name. Enabling or disabling an offer publishes discounts/update; changing how offers combine publishes discount_settings/update. Requests that make no change do not publish an event.
Discount created
Subscribe to receive the complete discount definition after a discount is created in a market.
Payload fields
| Field | Type | Description |
|---|---|---|
discount.gift_mode |
string |
Selectable in the Payload builder
Whether unlocked gifts are offered to claim (offer) or inserted automatically (auto_add). |
discount.gift_items[*].product_id |
integer |
Selectable in the Payload builder
The gift-only product id. |
discount.gift_items[*].variant_id |
integer |
Selectable in the Payload builder
The exact gift variant id for a variable product; omitted for a simple product. |
discount.gift_items[*].quantity |
integer |
Selectable in the Payload builder
Granted quantity per cart while the offer qualifies. |
discount.tier_value_kind |
string |
Selectable in the Payload builder
percentage or fixed_amount for tiered discounts. |
discount.tiers[*].min_subtotal |
string |
Selectable in the Payload builder
Ascending threshold in the store base currency. Only the highest reached tier applies. |
discount.tiers[*].value |
string |
Selectable in the Payload builder
Percentage or base-currency amount granted by this tier. |
discount.id |
string |
Always present
The stable discount id. |
discount.market_id |
string |
Selectable in the Payload builder
The market where this discount is evaluated. |
discount.name |
string |
Selectable in the Payload builder
The merchant-facing name of the discount. |
discount.type |
string |
Selectable in the Payload builder
The pricing rule: percentage, fixed amount, Buy X Get Y, bundle, free gift, or tiered. |
discount.activation |
string |
Selectable in the Payload builder
Whether the discount applies automatically or after a coupon code is entered. |
discount.code |
string |
Selectable in the Payload builder
The coupon code, or null for an automatic discount. |
discount.status |
string |
Selectable in the Payload builder
The current effective status after applying the schedule and enabled state. |
discount.priority |
integer |
Selectable in the Payload builder
The merchant-defined order used when priority decides between competing offers. |
discount.value |
number |
Selectable in the Payload builder
The percentage value for a percentage discount; null for other types. |
discount.amounts |
object |
Selectable in the Payload builder
Fixed discount amounts keyed by currency code; empty for other types. |
discount.applies_to |
string |
Selectable in the Payload builder
The merchandise scope selected by the merchant. |
discount.exclude_sale_items |
boolean |
Selectable in the Payload builder
Whether items already on sale are excluded. |
discount.min_subtotal |
object |
Selectable in the Payload builder
The qualifying merchandise subtotal keyed by currency code. |
discount.min_quantity |
integer |
Selectable in the Payload builder
The minimum qualifying item quantity, or null when unused. |
discount.max_discount |
object |
Selectable in the Payload builder
The cap on the amount saved, keyed by currency code (percentage, bundle and tiered discounts). |
discount.usage_limit |
integer |
Selectable in the Payload builder
The total number of uses allowed, or null when unlimited. |
discount.per_customer_limit |
integer |
Selectable in the Payload builder
The number of uses allowed per customer (recognised by account or email), or null when unlimited. |
discount.customer_eligibility |
string |
Selectable in the Payload builder
Whether everyone, selected customers, or selected customer groups qualify. |
discount.first_order_only |
boolean |
Selectable in the Payload builder
Whether only a customer's first paid order qualifies; guests are recognised by email. |
discount.refund_restores_usage |
boolean |
Selectable in the Payload builder
Whether an order gives its use back to the total and per-customer limits once every item this discount reduced is refunded, including when the whole order is refunded. |
discount.show_in_cart |
boolean |
Selectable in the Payload builder
Whether an eligible coupon may be surfaced before checkout. |
discount.bxgy_buy_quantity |
integer |
Selectable in the Payload builder
The quantity required from the Buy X set. |
discount.bxgy_get_quantity |
integer |
Selectable in the Payload builder
The quantity rewarded from the Get Y set. |
discount.bxgy_get_type |
string |
Selectable in the Payload builder
Whether reward items are free, reduced by a percentage, or reduced by a fixed amount off each item. |
discount.bxgy_get_value |
number |
Selectable in the Payload builder
The percentage off, or the fixed base-currency amount off, each reward item; null when rewards are free. |
discount.bxgy_max_uses |
integer |
Selectable in the Payload builder
The maximum number of complete Buy X Get Y sets per order. |
discount.bxgy_buy_items[*].item_type |
string |
Selectable in the Payload builder
The kind of Buy X target: simple product, exact variant, collection, or category. |
discount.bxgy_buy_items[*].item_id |
string |
Selectable in the Payload builder
The id of the Buy X target. |
discount.bxgy_get_items[*].item_type |
string |
Selectable in the Payload builder
The kind of Get Y target: simple product, exact variant, collection, or category. |
discount.bxgy_get_items[*].item_id |
string |
Selectable in the Payload builder
The id of the Get Y target. |
discount.bundle_value_mode |
string |
Selectable in the Payload builder
Whether a complete bundle has a fixed set price or a percentage reduction. |
discount.bundle_percentage |
number |
Selectable in the Payload builder
The percentage reduction for each complete bundle set. |
discount.bundle_prices |
object |
Selectable in the Payload builder
The fixed price of one complete bundle keyed by currency code. |
discount.bundle_max_sets |
integer |
Selectable in the Payload builder
The maximum number of complete bundle sets discounted per order, or null when unlimited. |
discount.bundle_items[*].item_type |
string |
Selectable in the Payload builder
product (matches any variant of the product) or variant (matches only that variant). |
discount.bundle_items[*].item_id |
string |
Selectable in the Payload builder
The product or variant id for this component. |
discount.bundle_items[*].quantity |
integer |
Selectable in the Payload builder
The quantity required in each complete bundle set. |
discount.product_ids |
array |
Selectable in the Payload builder
Product ids used when the discount targets selected products. |
discount.variant_ids |
array |
Selectable in the Payload builder
Exact variant ids used when the discount targets selected products or variants. |
discount.collection_ids |
array |
Selectable in the Payload builder
Collection ids used when the discount targets selected collections. |
discount.category_ids |
array |
Selectable in the Payload builder
Category ids used when the discount targets selected categories. |
discount.customer_ids |
array |
Selectable in the Payload builder
Customer ids used when eligibility is limited to selected customers. |
discount.group_ids |
array |
Selectable in the Payload builder
Customer-group ids used when eligibility is limited to selected groups. |
discount.starts_at |
string |
Selectable in the Payload builder
The optional start of the discount window, in the store's time zone with its offset. |
discount.ends_at |
string |
Selectable in the Payload builder
The optional end of the discount window, in the store's time zone with its offset. |
discount.created_at |
string |
Selectable in the Payload builder
When the discount was created. |
discount.updated_at |
string |
Selectable in the Payload builder
When the discount last changed. |
Get discount limits
Learn which discount options and limits are available to this store.
The response lists the accepted values and bounds for discount requests: the supported types, targeting and eligibility choices, percentage and priority ranges, relation caps, sort fields, page sizes, and the store's maximum number of discounts. Use list_default_limit for the initial page, page_size_options for page-size choices, list_max_limit as the upper bound for both per_page and bulk selections, and search_max_length for search text. type_capabilities lists which fields each type supports. Limits are store-wide: every market returns the same values, and the market id in the path is not checked. The sample shows current production values; read the response rather than hard-coding them.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID.
Discount updated
Subscribe to receive the current discount definition after its offer, targeting, schedule, limits, or enabled state changes.
Payload fields
| Field | Type | Description |
|---|---|---|
discount.gift_mode |
string |
Selectable in the Payload builder
Whether unlocked gifts are offered to claim (offer) or inserted automatically (auto_add). |
discount.gift_items[*].product_id |
integer |
Selectable in the Payload builder
The gift-only product id. |
discount.gift_items[*].variant_id |
integer |
Selectable in the Payload builder
The exact gift variant id for a variable product; omitted for a simple product. |
discount.gift_items[*].quantity |
integer |
Selectable in the Payload builder
Granted quantity per cart while the offer qualifies. |
discount.tier_value_kind |
string |
Selectable in the Payload builder
percentage or fixed_amount for tiered discounts. |
discount.tiers[*].min_subtotal |
string |
Selectable in the Payload builder
Ascending threshold in the store base currency. Only the highest reached tier applies. |
discount.tiers[*].value |
string |
Selectable in the Payload builder
Percentage or base-currency amount granted by this tier. |
discount.id |
string |
Always present
The stable discount id. |
discount.market_id |
string |
Selectable in the Payload builder
The market where this discount is evaluated. |
discount.name |
string |
Selectable in the Payload builder
The merchant-facing name of the discount. |
discount.type |
string |
Selectable in the Payload builder
The pricing rule: percentage, fixed amount, Buy X Get Y, bundle, free gift, or tiered. |
discount.activation |
string |
Selectable in the Payload builder
Whether the discount applies automatically or after a coupon code is entered. |
discount.code |
string |
Selectable in the Payload builder
The coupon code, or null for an automatic discount. |
discount.status |
string |
Selectable in the Payload builder
The current effective status after applying the schedule and enabled state. |
discount.priority |
integer |
Selectable in the Payload builder
The merchant-defined order used when priority decides between competing offers. |
discount.value |
number |
Selectable in the Payload builder
The percentage value for a percentage discount; null for other types. |
discount.amounts |
object |
Selectable in the Payload builder
Fixed discount amounts keyed by currency code; empty for other types. |
discount.applies_to |
string |
Selectable in the Payload builder
The merchandise scope selected by the merchant. |
discount.exclude_sale_items |
boolean |
Selectable in the Payload builder
Whether items already on sale are excluded. |
discount.min_subtotal |
object |
Selectable in the Payload builder
The qualifying merchandise subtotal keyed by currency code. |
discount.min_quantity |
integer |
Selectable in the Payload builder
The minimum qualifying item quantity, or null when unused. |
discount.max_discount |
object |
Selectable in the Payload builder
The cap on the amount saved, keyed by currency code (percentage, bundle and tiered discounts). |
discount.usage_limit |
integer |
Selectable in the Payload builder
The total number of uses allowed, or null when unlimited. |
discount.per_customer_limit |
integer |
Selectable in the Payload builder
The number of uses allowed per customer (recognised by account or email), or null when unlimited. |
discount.customer_eligibility |
string |
Selectable in the Payload builder
Whether everyone, selected customers, or selected customer groups qualify. |
discount.first_order_only |
boolean |
Selectable in the Payload builder
Whether only a customer's first paid order qualifies; guests are recognised by email. |
discount.refund_restores_usage |
boolean |
Selectable in the Payload builder
Whether an order gives its use back to the total and per-customer limits once every item this discount reduced is refunded, including when the whole order is refunded. |
discount.show_in_cart |
boolean |
Selectable in the Payload builder
Whether an eligible coupon may be surfaced before checkout. |
discount.bxgy_buy_quantity |
integer |
Selectable in the Payload builder
The quantity required from the Buy X set. |
discount.bxgy_get_quantity |
integer |
Selectable in the Payload builder
The quantity rewarded from the Get Y set. |
discount.bxgy_get_type |
string |
Selectable in the Payload builder
Whether reward items are free, reduced by a percentage, or reduced by a fixed amount off each item. |
discount.bxgy_get_value |
number |
Selectable in the Payload builder
The percentage off, or the fixed base-currency amount off, each reward item; null when rewards are free. |
discount.bxgy_max_uses |
integer |
Selectable in the Payload builder
The maximum number of complete Buy X Get Y sets per order. |
discount.bxgy_buy_items[*].item_type |
string |
Selectable in the Payload builder
The kind of Buy X target: simple product, exact variant, collection, or category. |
discount.bxgy_buy_items[*].item_id |
string |
Selectable in the Payload builder
The id of the Buy X target. |
discount.bxgy_get_items[*].item_type |
string |
Selectable in the Payload builder
The kind of Get Y target: simple product, exact variant, collection, or category. |
discount.bxgy_get_items[*].item_id |
string |
Selectable in the Payload builder
The id of the Get Y target. |
discount.bundle_value_mode |
string |
Selectable in the Payload builder
Whether a complete bundle has a fixed set price or a percentage reduction. |
discount.bundle_percentage |
number |
Selectable in the Payload builder
The percentage reduction for each complete bundle set. |
discount.bundle_prices |
object |
Selectable in the Payload builder
The fixed price of one complete bundle keyed by currency code. |
discount.bundle_max_sets |
integer |
Selectable in the Payload builder
The maximum number of complete bundle sets discounted per order, or null when unlimited. |
discount.bundle_items[*].item_type |
string |
Selectable in the Payload builder
product (matches any variant of the product) or variant (matches only that variant). |
discount.bundle_items[*].item_id |
string |
Selectable in the Payload builder
The product or variant id for this component. |
discount.bundle_items[*].quantity |
integer |
Selectable in the Payload builder
The quantity required in each complete bundle set. |
discount.product_ids |
array |
Selectable in the Payload builder
Product ids used when the discount targets selected products. |
discount.variant_ids |
array |
Selectable in the Payload builder
Exact variant ids used when the discount targets selected products or variants. |
discount.collection_ids |
array |
Selectable in the Payload builder
Collection ids used when the discount targets selected collections. |
discount.category_ids |
array |
Selectable in the Payload builder
Category ids used when the discount targets selected categories. |
discount.customer_ids |
array |
Selectable in the Payload builder
Customer ids used when eligibility is limited to selected customers. |
discount.group_ids |
array |
Selectable in the Payload builder
Customer-group ids used when eligibility is limited to selected groups. |
discount.starts_at |
string |
Selectable in the Payload builder
The optional start of the discount window, in the store's time zone with its offset. |
discount.ends_at |
string |
Selectable in the Payload builder
The optional end of the discount window, in the store's time zone with its offset. |
discount.created_at |
string |
Selectable in the Payload builder
When the discount was created. |
discount.updated_at |
string |
Selectable in the Payload builder
When the discount last changed. |
List discounts
Browse the discounts configured for a market.
Use this endpoint for a paginated discount list. You can filter by current status, discount type, or activation method, and search by name or coupon code. Search matches any part of the name or code, ignoring case. List records carry the discount definition plus worded labels (status_label, type_label, value_label, usage_summary and others); their targeting, eligibility, Buy X Get Y, bundle and gift arrays are always empty and can_view_products/can_view_customers are false. Read one discount to get those. Scheduled and expired statuses are calculated from the discount's dates when you read it. A per_page above list_max_limit is reduced to it, and sorting by ends_at lists discounts without an end date last.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
Query parameters
| Name | Type | Description |
|---|---|---|
page
|
integer |
The page to return, starting at 1. |
per_page
|
integer |
The number of discounts to return on each page. |
status
|
string |
Return only |
type
|
string |
Filter by type: |
activation
|
string |
Return coupon discounts or automatic discounts. |
search
|
string |
Search by discount name or coupon code. |
sort_by
|
string |
Sort by |
sort_direction
|
string |
Sort in ascending ( |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
400MARKET_DISCOUNT_FILTER_INVALIDStatus/type/activation filter is not a supported value.
-
400MARKET_DISCOUNT_SEARCH_TOO_LONGSearch query exceeds the discount limits max length.
-
400MARKET_DISCOUNT_LIST_INVALID_SORT_BYSort_by is not a discount sort column.
-
400MARKET_DISCOUNT_LIST_INVALID_SORT_DIRECTIONSort_direction is not asc or desc.
-
404MARKET_NOT_FOUNDMarket does not exist in this store.
Create a discount
Add a merchandise discount to a market.
Choose one discount type and provide the fields for that type. value, amounts, Buy X Get Y, bundle and gift fields sent for another type are rejected; tier_value_kind and tiers sent for a type other than tiered are ignored, and so are unknown fields. Empty money maps ({}) are treated as not set, so money maps from a GET can be sent back unchanged for any type. Percentage discounts use value; fixed-amount discounts use amounts; Buy X Get Y offers define qualifying and reward sets; bundles define every required component and either a set price or percentage reduction. Free gifts specify gift-only products and how they enter the cart; tiered discounts specify ascending base-currency subtotal thresholds and apply only the highest reached tier. Coupon discounts need a code that is unique within the market, while automatic discounts apply without one. Product, collection, category, customer, and group ids must belong to the same store. Free delivery is configured with the market's shipping methods. The response is the saved discount, with usage_count and usage_held_count at 0 and a matching usage_summary. A successful create publishes discounts/create.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Body parameters
| Name | Type | Description |
|---|---|---|
name
required
|
string |
A name merchants can recognize when managing the discount. |
type
required
|
string |
Choose |
gift_mode
|
string|null |
For free_gift: offer or auto_add. On create, omitted or null means offer; on update, omitted or null keeps the current mode. With best_for_customer ranking a gift ranks at its full value (each gift's quantity-specific unit price times its granted quantity) whether or not it is in the cart yet, including advertised coupons before entry. Gift-only units never qualify for other discounts or inflate their ranking. A gift grant is eligible only when its complete set is channel-available, priced, within quantity limits and in stock alongside all physical merchandise, including quantity-priced items excluded from discounts. Stacked gift sets share stock in ranking order; a set is granted only if its complete demand fits after higher-ranked gifts. When automatic discounts and codes don't combine, an offer the shopper hasn't claimed doesn't keep codes out; a code that applies withdraws the offer. |
gift_items
|
array<object> |
For free_gift: a gift-only product_id, positive quantity per cart, and optional variant_id. Omit variant_id for a simple product; a variable product requires the exact variant_id that belongs to it. |
tier_value_kind
|
string|null |
For tiered: percentage or fixed_amount. |
tiers
|
array<object> |
For tiered: 1–10 tiers with strictly ascending min_subtotal thresholds from 0 to money_amount_max, and positive values, in the base currency and its precision. Only the highest reached tier applies, chosen from the merchandise subtotal before any discount. Percentage values cannot exceed 100. Fixed savings can exceed the threshold but are capped at remaining eligible merchandise at checkout; merchandise never becomes negative. Other markets use the base amounts converted at the market's rate. |
activation
required
|
string |
Use |
code
|
string |
Required for coupon activation. Use letters A–Z, digits, hyphens and underscores, up to code_max_length characters; the code is stored in upper case. Codes are unique within the market and matched without regard to case. |
priority
|
integer |
The discount's position when manual priority decides between competing offers. Omission uses 0 on both create and full replacement, which can conflict with another discount at that priority. Send an explicit unique whole number from priority_min through max_priority in the limits response. |
value
|
number |
The percentage reduction for a percentage discount. It must be greater than percentage_min_exclusive, no more than percentage_max, and use no more than percentage_decimal_places from the limits response. |
amounts
|
object |
Fixed discount amounts keyed by currency code. Include the store's base currency; additional entries must be currencies enabled for the market. Each amount must be greater than 0, at most money_amount_max, and fit that currency's minor-unit precision. A market currency without its own amount uses the base amount converted at the market's rate. |
applies_to
required
|
string |
Apply the discount to the whole order or to selected products or variants, collections, or categories. Buy X Get Y and bundle offers define their items separately and use |
product_ids
|
array<integer> |
Products to discount when |
variant_ids
|
array<integer> |
Exact variants to discount when |
collection_ids
|
array<string> |
The collections to discount when |
category_ids
|
array<integer> |
The categories to discount when |
customer_eligibility
required
|
string |
Make the discount available to everyone, selected customers, or selected customer groups. |
customer_ids
|
array<string> |
The customers who qualify when eligibility is |
group_ids
|
array<string> |
The customer groups that qualify when eligibility is |
exclude_sale_items
|
boolean |
Skip items already on sale. Only percentage and fixed-amount discounts accept true; other types reject it with DISCOUNT_TARGETS_FORBIDDEN. |
min_subtotal
|
object |
Require a minimum merchandise subtotal, keyed by currency code. Include the base currency when you set this condition; other market currencies without an entry use the converted base amount. It is checked before any discount. For percentage, fixed-amount and free gift discounts it counts only the items matched by |
min_quantity
|
integer |
Require between quantity_min and min_quantity_max eligible items from the limits response. Percentage, fixed-amount and free gift discounts accept this condition; Buy X Get Y, bundle and tiered discounts reject it with DISCOUNT_MIN_QUANTITY_FORBIDDEN. |
max_discount
|
object |
Cap the amount saved, keyed by currency code. Percentage, bundle and tiered discounts accept it; fixed-amount, Buy X Get Y and free gift discounts reject it with DISCOUNT_MAX_DISCOUNT_FORBIDDEN. |
starts_at
|
string |
Start the discount at this local store time, formatted as |
ends_at
|
string |
Stop the discount at this local store time. It must be later than |
usage_limit
|
integer |
The total number of uses allowed. Send unlimited_sentinel (-1) or null for no limit, or a whole number from quantity_min through max_usage_limit in the limits response; an unlimited discount is returned as null. A use is held when an order is placed and counts toward the limit while the checkout is unpaid, so new orders are refused with DISCOUNT_USAGE_EXHAUSTED once the limit is reached. The use is given back if the checkout expires unpaid or the order is cancelled. A payment that arrives after its checkout expired still keeps its use, which can take the count past the limit. A discount with no usage_limit and no per_customer_limit counts no uses. |
per_customer_limit
|
integer |
The number of uses allowed for each customer. Send unlimited_sentinel (-1) or null for no limit, or a whole number from quantity_min through max_per_customer_limit in the limits response; an unlimited discount is returned as null. A customer is recognised by account or by email address, ignoring case, so guest orders count toward that email's limit; an order with neither is not checked. Orders over the limit are refused with DISCOUNT_CUSTOMER_LIMIT_REACHED. |
refund_restores_usage
|
boolean |
Give a use back to usage_limit and per_customer_limit when every item this discount reduced on an order is refunded, or the whole order is refunded. The use is returned shortly after the refund, following the setting the discount has at that moment. The release is final for that order and discount: payment capture or retry cannot reclaim it. |
first_order_only
|
boolean |
Restrict to a customer's first order. Earlier paid, cash-on-delivery or refunded orders under the same account or the same email address (ignoring case) disqualify; test and cancelled orders do not. Guests are recognised by email. An order with neither an account nor an email does not qualify. |
show_in_cart
|
boolean |
Allow the storefront to show this coupon before checkout. Coupon discounts only; sending true for an automatic discount returns DISCOUNT_TARGETS_FORBIDDEN. |
bxgy_buy_quantity
|
integer |
The quantity a shopper must add from the Buy X set. |
bxgy_get_quantity
|
integer |
The quantity rewarded from the Get Y set. |
bxgy_get_type
|
string |
Make reward items |
bxgy_get_value
|
number |
The percentage off each reward item, or the fixed amount deducted from each reward item in the store base currency, converted to the order currency at the market's exchange rate. Fixed means an amount off, not a final selling price. The deduction is capped at the remaining reward-item value. Omit this field when rewards are free. Fixed amounts use the base currency precision and the live money_amount_max. |
bxgy_max_uses
|
integer |
The maximum number of complete Buy X Get Y sets that may apply to one order: a whole number from bxgy_max_uses_min through bxgy_max_uses_max in the limits response. Omit it or send null for no per-order cap; unlimited_sentinel (-1) is not accepted here. |
bxgy_buy_items
|
array<object> |
Simple products, exact variants, collections, or categories that can satisfy Buy X. Each item contains |
bxgy_get_items
|
array<object> |
Simple products, exact variants, collections, or categories that can be rewarded as Get Y, independently of Buy X targets. The shopper adds reward items to the cart; the discount never adds them. Whole variable products cannot be saved as product targets; select their exact variants. |
bundle_value_mode
|
string |
Use |
bundle_prices
|
object |
The price of one complete bundle, keyed by currency code. Include the base currency for fixed-price bundles; other market currencies without an entry use the converted base price. |
bundle_percentage
|
number |
The percentage reduction for each complete bundle when the value mode is |
bundle_max_sets
|
integer |
The maximum number of complete bundle sets discounted on one order. Send -1 or null for no limit; an unlimited bundle is returned as null. |
bundle_items
|
array<object> |
The products or variants and quantities required for one complete bundle. Provide between bundle_components_min and bundle_components_max different components. A |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
400DISCOUNT_NAME_REQUIREDName is empty after trimming.
-
400DISCOUNT_NAME_TOO_LONGName is longer than name_max_length.
-
400DISCOUNT_TYPE_INVALIDType is not a supported discount type.
-
400DISCOUNT_ACTIVATION_INVALIDActivation is not coupon or automatic.
-
400DISCOUNT_CODE_REQUIREDA coupon discount has no code.
-
400DISCOUNT_CODE_AUTOMATIC_FORBIDDENAn automatic discount was sent a code.
-
400DISCOUNT_CODE_TOO_LONGThe code is longer than code_max_length.
-
400DISCOUNT_CODE_CHARACTERSThe code uses a character other than A–Z, digits, hyphen or underscore.
-
400DISCOUNT_PRIORITY_RANGEPriority is outside priority_min to max_priority.
-
400DISCOUNT_VALUE_RANGEA percentage value is not above 0 and at most 100.
-
400DISCOUNT_PERCENTAGE_TOO_PRECISEA percentage has more than percentage_decimal_places decimal places.
-
400DISCOUNT_VALUE_FORBIDDENValue was sent for a type that does not take one.
-
400DISCOUNT_AMOUNTS_REQUIREDA fixed-amount discount has no amounts.
-
400DISCOUNT_AMOUNTS_FORBIDDENAmounts were sent for a type that does not take them.
-
400DISCOUNT_CURRENCY_BASE_REQUIREDA money map is missing the store's base currency.
-
400DISCOUNT_CURRENCY_INVALIDA money map uses a currency not assigned to the market.
-
400DISCOUNT_CURRENCY_VALUE_RANGEA money value is not greater than 0.
-
400DISCOUNT_CURRENCY_VALUE_TOO_LARGEA money value is above money_amount_max.
-
400DISCOUNT_CURRENCY_VALUE_TOO_PRECISEA money value, fixed Buy X Get Y value, tier threshold or fixed tier value has more decimal places than its currency.
-
400DISCOUNT_APPLIES_TO_INVALIDApplies_to is not a supported value.
-
400DISCOUNT_ENTIRE_ORDER_ONLYA Buy X Get Y, bundle or tiered discount was not set to entire_order.
-
400DISCOUNT_ELIGIBILITY_INVALIDCustomer_eligibility is not a supported value.
-
400DISCOUNT_TARGETS_REQUIREDSpecific targeting or eligibility was chosen without its id list, or a referenced id is malformed, does not exist, or belongs to another store.
-
400DISCOUNT_TARGETS_FORBIDDENAn id list was sent that does not match the targeting or eligibility, exclude_sale_items or show_in_cart was set where it is not supported, or a Buy X Get Y item has an unsupported item_type.
-
400DISCOUNT_MIN_QUANTITY_FORBIDDENMin_quantity was sent for Buy X Get Y, bundle or tiered.
-
400DISCOUNT_MIN_QUANTITY_RANGEMin_quantity is below quantity_min.
-
400DISCOUNT_MIN_QUANTITY_TOO_LARGEMin_quantity is above min_quantity_max.
-
400DISCOUNT_MAX_DISCOUNT_FORBIDDENMax_discount was sent for fixed-amount, Buy X Get Y or free gift.
-
400DISCOUNT_USAGE_LIMIT_RANGEUsage_limit is not -1, null, or within quantity_min to max_usage_limit.
-
400DISCOUNT_PER_CUSTOMER_RANGEPer_customer_limit is not -1, null, or within quantity_min to max_per_customer_limit.
-
400DISCOUNT_DATE_INVALIDStarts_at or ends_at is not in YYYY-MM-DDTHH:mm:ss form.
-
400MARKET_DISCOUNT_DATE_INVALIDEnds_at is not after starts_at.
-
400DISCOUNT_BXGY_FIELDS_FORBIDDENBuy X Get Y fields were sent for another type.
-
400DISCOUNT_BXGY_BUY_REQUIREDBuy X Get Y has no valid buy items.
-
400DISCOUNT_BXGY_GET_REQUIREDBuy X Get Y has no valid reward items.
-
400DISCOUNT_BXGY_QUANTITY_RANGEA buy or reward quantity is outside 1 to max_bxgy_quantity.
-
400DISCOUNT_GET_TYPE_REQUIREDBuy X Get Y has no bxgy_get_type.
-
400DISCOUNT_GET_TYPE_INVALIDBxgy_get_type is not free, percentage or fixed.
-
400DISCOUNT_GET_VALUE_FORBIDDENBxgy_get_value was sent for free rewards.
-
400DISCOUNT_GET_VALUE_RANGEA percentage reward is not above 0 and at most 100.
-
400DISCOUNT_GET_VALUE_POSITIVEA fixed reward amount is not greater than 0.
-
400DISCOUNT_GET_VALUE_TOO_LARGEA fixed reward amount is above money_amount_max.
-
400DISCOUNT_MAX_USES_PER_ORDER_RANGEBxgy_max_uses is below bxgy_max_uses_min.
-
400DISCOUNT_MAX_USES_PER_ORDER_TOO_LARGEBxgy_max_uses is above bxgy_max_uses_max.
-
400DISCOUNT_BUNDLE_FIELDS_FORBIDDENBundle fields were sent for another type.
-
400DISCOUNT_BUNDLE_MODE_REQUIREDA bundle has no bundle_value_mode.
-
400DISCOUNT_BUNDLE_MODE_INVALIDBundle_value_mode is not fixed_price or percentage, the other mode's field was also sent (bundle_percentage with fixed_price, or bundle_prices with percentage), or a component's item_type is not product or variant.
-
400DISCOUNT_BUNDLE_PRICE_REQUIREDA fixed-price bundle has no bundle_prices.
-
400DISCOUNT_BUNDLE_PERCENT_REQUIREDA percentage bundle has no valid bundle_percentage.
-
400DISCOUNT_BUNDLE_ITEMS_RANGEThe number of components is outside bundle_components_min to bundle_components_max, or a component has a blank item_id.
-
400DISCOUNT_BUNDLE_ITEM_DUPLICATEThe same product or variant appears twice in the bundle.
-
400DISCOUNT_BUNDLE_ITEM_QUANTITYA component quantity is outside 1 to bundle_item_quantity_max.
-
400DISCOUNT_BUNDLE_MAX_SETS_RANGEBundle_max_sets is not -1, null, or within bundle_max_sets_min to bundle_max_sets_max.
-
400DISCOUNT_GIFT_FIELDS_FORBIDDENGift fields were sent for another type.
-
400DISCOUNT_GIFT_MODE_INVALIDGift_mode is not offer or auto_add.
-
400DISCOUNT_GIFT_ITEMS_RANGEThe number of gift items is outside gift_items_min to gift_items_max.
-
400DISCOUNT_GIFT_ITEM_DUPLICATEThe same gift product or variant appears twice.
-
400DISCOUNT_GIFT_ITEM_QUANTITYA gift quantity is outside 1 to gift_item_quantity_max.
-
400DISCOUNT_GIFT_NOT_GIFT_ONLYA gift product_id is not positive, does not exist in the store, or is not marked gift-only.
-
400DISCOUNT_GIFT_VARIANT_REQUIREDA variable gift product has no variant_id.
-
400DISCOUNT_GIFT_VARIANT_INVALIDThe gift variant does not exist, belongs to another product, or was sent for a simple product.
-
400DISCOUNT_TIERS_COUNTThe number of tiers is outside tiers_min to tiers_max.
-
400DISCOUNT_TIER_THRESHOLD_INVALIDA tier threshold is negative or above money_amount_max. A threshold with more decimal places than the base currency returns DISCOUNT_CURRENCY_VALUE_TOO_PRECISE instead.
-
400DISCOUNT_TIER_THRESHOLD_ORDERTier thresholds do not strictly increase.
-
400DISCOUNT_TIER_VALUE_INVALIDA tier value is not positive, a percentage is above 100, or an amount is out of range.
-
400MARKET_DISCOUNT_RELATION_LIMIT_REACHEDAn id list is longer than its max_*_per_discount limit.
-
400MARKET_DISCOUNT_RELATION_DUPLICATEAn id appears twice in a targeting, eligibility or Buy X Get Y list, or a product is targeted together with one of its own variants.
-
400MARKET_DISCOUNT_LIMIT_REACHEDThe market already has max_per_market discounts.
-
400STORE_API_INVALID_REQUEST_BODYThe body is not valid JSON, or is not a JSON object.
-
400INVALID_INPUTA field has the wrong JSON type, for example a string where a number is expected.
-
404MARKET_NOT_FOUNDMarket does not exist in this store.
-
409MARKET_DISCOUNT_CODE_DUPLICATEAnother discount in the market has this code, ignoring case.
-
409MARKET_DISCOUNT_PRIORITY_DUPLICATEAnother discount in the market has this priority.
Discount deleted
Subscribe to remove a deleted discount from your integration. The payload keeps its id, market id, and last known name.
Payload fields
| Field | Type | Description |
|---|---|---|
id |
string |
Always present
The stable id of the deleted discount. |
market_id |
string |
Selectable in the Payload builder
The market that owned the discount. |
name |
string |
Selectable in the Payload builder
The discount name at the time it was deleted. |
Discount settings updated
Subscribe when your app needs the current rules for combining discounts in a market.
Payload fields
| Field | Type | Description |
|---|---|---|
discount_settings.market_id |
string |
Always present
The market whose combination settings changed. |
discount_settings.stacking_mode |
string |
Selectable in the Payload builder
single applies one discount per order, chosen by priority_mode; stack applies every eligible automatic discount plus codes up to coupon_limit. |
discount_settings.priority_mode |
string |
Selectable in the Payload builder
How discounts are ranked: best_for_customer by each discount's own saving, manual by priority number, lowest first. The ranking picks the single discount, fills the coupon limit, and decides which offer keeps items two offers both need. |
discount_settings.coupon_limit |
integer |
Selectable in the Payload builder
The maximum number of codes that can apply to one order in stack mode. Automatic discounts do not count. |
discount_settings.auto_coupon_combine |
boolean |
Selectable in the Payload builder
In stack mode, true lets codes apply alongside automatic discounts; false lets codes apply only when no automatic discount applies. No effect in single mode. |
discount_settings.apply_to_quantity_priced |
boolean |
Selectable in the Payload builder
When false, items with quantity pricing get no discount and do not count toward minimum spend, minimum quantity or tiers. |
Get a discount
Read one discount and its targeting choices.
The response includes the complete discount definition and the ids it targets. Product-facing labels (products, variants, collections, categories, Buy X Get Y, bundle and gift items) are included when your token has read_products; customer names and group labels are included with read_customers. The ids remain available without those additional scopes, and can_view_products and can_view_customers tell you whether labels were included. The returned status reflects the discount's current schedule. usage_count includes uses held by unpaid checkouts; usage_held_count says how many of them are held, and usage_summary words both. Uses are counted only while the discount has a usage_limit or a per_customer_limit: with neither, orders record no use, usage_count doesn't change and usage_summary says uses are not counted. Adding a limit later counts uses from then on. starts_at, ends_at, created_at and updated_at are display strings in the store's time zone; starts_at_iso and ends_at_iso give the start and end as local store time in the YYYY-MM-DDTHH:mm:ss form that create and update accept.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
discountId
required
|
string |
Discount id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
404MARKET_NOT_FOUNDMarket does not exist in this store.
-
404MARKET_DISCOUNT_NOT_FOUNDDiscount does not exist in this market.
Update a discount
Replace the editable definition of a discount.
Send the complete definition you want to keep, including all targeting and eligibility lists; read them with GET first, because list records leave them empty. The same type-specific rules used during creation apply here. Updating a disabled discount does not enable it; use the enable endpoint when it is ready to run again. Sending an unchanged definition leaves the discount untouched and publishes no webhook. A successful change publishes discounts/update. The response is the saved discount with its current usage_count, usage_held_count and usage_summary.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
discountId
required
|
string |
Discount id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Body parameters
| Name | Type | Description |
|---|---|---|
name
required
|
string |
A name merchants can recognize when managing the discount. |
type
required
|
string |
Choose |
gift_mode
|
string|null |
For free_gift: offer or auto_add. On create, omitted or null means offer; on update, omitted or null keeps the current mode. With best_for_customer ranking a gift ranks at its full value (each gift's quantity-specific unit price times its granted quantity) whether or not it is in the cart yet, including advertised coupons before entry. Gift-only units never qualify for other discounts or inflate their ranking. A gift grant is eligible only when its complete set is channel-available, priced, within quantity limits and in stock alongside all physical merchandise, including quantity-priced items excluded from discounts. Stacked gift sets share stock in ranking order; a set is granted only if its complete demand fits after higher-ranked gifts. When automatic discounts and codes don't combine, an offer the shopper hasn't claimed doesn't keep codes out; a code that applies withdraws the offer. |
gift_items
|
array<object> |
For free_gift: a gift-only product_id, positive quantity per cart, and optional variant_id. Omit variant_id for a simple product; a variable product requires the exact variant_id that belongs to it. |
tier_value_kind
|
string|null |
For tiered: percentage or fixed_amount. |
tiers
|
array<object> |
For tiered: 1–10 tiers with strictly ascending min_subtotal thresholds from 0 to money_amount_max, and positive values, in the base currency and its precision. Only the highest reached tier applies, chosen from the merchandise subtotal before any discount. Percentage values cannot exceed 100. Fixed savings can exceed the threshold but are capped at remaining eligible merchandise at checkout; merchandise never becomes negative. Other markets use the base amounts converted at the market's rate. |
activation
required
|
string |
Use |
code
|
string |
Required for coupon activation. Use letters A–Z, digits, hyphens and underscores, up to code_max_length characters; the code is stored in upper case. Codes are unique within the market and matched without regard to case. |
priority
|
integer |
The discount's position when manual priority decides between competing offers. Omission uses 0 on both create and full replacement, which can conflict with another discount at that priority. Send an explicit unique whole number from priority_min through max_priority in the limits response. |
value
|
number |
The percentage reduction for a percentage discount. It must be greater than percentage_min_exclusive, no more than percentage_max, and use no more than percentage_decimal_places from the limits response. |
amounts
|
object |
Fixed discount amounts keyed by currency code. Include the store's base currency; additional entries must be currencies enabled for the market. Each amount must be greater than 0, at most money_amount_max, and fit that currency's minor-unit precision. A market currency without its own amount uses the base amount converted at the market's rate. |
applies_to
required
|
string |
Apply the discount to the whole order or to selected products or variants, collections, or categories. Buy X Get Y and bundle offers define their items separately and use |
product_ids
|
array<integer> |
Products to discount when |
variant_ids
|
array<integer> |
Exact variants to discount when |
collection_ids
|
array<string> |
The collections to discount when |
category_ids
|
array<integer> |
The categories to discount when |
customer_eligibility
required
|
string |
Make the discount available to everyone, selected customers, or selected customer groups. |
customer_ids
|
array<string> |
The customers who qualify when eligibility is |
group_ids
|
array<string> |
The customer groups that qualify when eligibility is |
exclude_sale_items
|
boolean |
Skip items already on sale. Only percentage and fixed-amount discounts accept true; other types reject it with DISCOUNT_TARGETS_FORBIDDEN. |
min_subtotal
|
object |
Require a minimum merchandise subtotal, keyed by currency code. Include the base currency when you set this condition; other market currencies without an entry use the converted base amount. It is checked before any discount. For percentage, fixed-amount and free gift discounts it counts only the items matched by |
min_quantity
|
integer |
Require between quantity_min and min_quantity_max eligible items from the limits response. Percentage, fixed-amount and free gift discounts accept this condition; Buy X Get Y, bundle and tiered discounts reject it with DISCOUNT_MIN_QUANTITY_FORBIDDEN. |
max_discount
|
object |
Cap the amount saved, keyed by currency code. Percentage, bundle and tiered discounts accept it; fixed-amount, Buy X Get Y and free gift discounts reject it with DISCOUNT_MAX_DISCOUNT_FORBIDDEN. |
starts_at
|
string |
Start the discount at this local store time, formatted as |
ends_at
|
string |
Stop the discount at this local store time. It must be later than |
usage_limit
|
integer |
The total number of uses allowed. Send unlimited_sentinel (-1) or null for no limit, or a whole number from quantity_min through max_usage_limit in the limits response; an unlimited discount is returned as null. A use is held when an order is placed and counts toward the limit while the checkout is unpaid, so new orders are refused with DISCOUNT_USAGE_EXHAUSTED once the limit is reached. The use is given back if the checkout expires unpaid or the order is cancelled. A payment that arrives after its checkout expired still keeps its use, which can take the count past the limit. A discount with no usage_limit and no per_customer_limit counts no uses. |
per_customer_limit
|
integer |
The number of uses allowed for each customer. Send unlimited_sentinel (-1) or null for no limit, or a whole number from quantity_min through max_per_customer_limit in the limits response; an unlimited discount is returned as null. A customer is recognised by account or by email address, ignoring case, so guest orders count toward that email's limit; an order with neither is not checked. Orders over the limit are refused with DISCOUNT_CUSTOMER_LIMIT_REACHED. |
refund_restores_usage
|
boolean |
Give a use back to usage_limit and per_customer_limit when every item this discount reduced on an order is refunded, or the whole order is refunded. The use is returned shortly after the refund, following the setting the discount has at that moment. The release is final for that order and discount: payment capture or retry cannot reclaim it. |
first_order_only
|
boolean |
Restrict to a customer's first order. Earlier paid, cash-on-delivery or refunded orders under the same account or the same email address (ignoring case) disqualify; test and cancelled orders do not. Guests are recognised by email. An order with neither an account nor an email does not qualify. |
show_in_cart
|
boolean |
Allow the storefront to show this coupon before checkout. Coupon discounts only; sending true for an automatic discount returns DISCOUNT_TARGETS_FORBIDDEN. |
bxgy_buy_quantity
|
integer |
The quantity a shopper must add from the Buy X set. |
bxgy_get_quantity
|
integer |
The quantity rewarded from the Get Y set. |
bxgy_get_type
|
string |
Make reward items |
bxgy_get_value
|
number |
The percentage off each reward item, or the fixed amount deducted from each reward item in the store base currency, converted to the order currency at the market's exchange rate. Fixed means an amount off, not a final selling price. The deduction is capped at the remaining reward-item value. Omit this field when rewards are free. Fixed amounts use the base currency precision and the live money_amount_max. |
bxgy_max_uses
|
integer |
The maximum number of complete Buy X Get Y sets that may apply to one order: a whole number from bxgy_max_uses_min through bxgy_max_uses_max in the limits response. Omit it or send null for no per-order cap; unlimited_sentinel (-1) is not accepted here. |
bxgy_buy_items
|
array<object> |
Simple products, exact variants, collections, or categories that can satisfy Buy X. Each item contains |
bxgy_get_items
|
array<object> |
Simple products, exact variants, collections, or categories that can be rewarded as Get Y, independently of Buy X targets. The shopper adds reward items to the cart; the discount never adds them. Whole variable products cannot be saved as product targets; select their exact variants. |
bundle_value_mode
|
string |
Use |
bundle_prices
|
object |
The price of one complete bundle, keyed by currency code. Include the base currency for fixed-price bundles; other market currencies without an entry use the converted base price. |
bundle_percentage
|
number |
The percentage reduction for each complete bundle when the value mode is |
bundle_max_sets
|
integer |
The maximum number of complete bundle sets discounted on one order. Send -1 or null for no limit; an unlimited bundle is returned as null. |
bundle_items
|
array<object> |
The products or variants and quantities required for one complete bundle. Provide between bundle_components_min and bundle_components_max different components. A |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
400DISCOUNT_NAME_REQUIREDName is empty after trimming.
-
400DISCOUNT_NAME_TOO_LONGName is longer than name_max_length.
-
400DISCOUNT_TYPE_INVALIDType is not a supported discount type.
-
400DISCOUNT_ACTIVATION_INVALIDActivation is not coupon or automatic.
-
400DISCOUNT_CODE_REQUIREDA coupon discount has no code.
-
400DISCOUNT_CODE_AUTOMATIC_FORBIDDENAn automatic discount was sent a code.
-
400DISCOUNT_CODE_TOO_LONGThe code is longer than code_max_length.
-
400DISCOUNT_CODE_CHARACTERSThe code uses a character other than A–Z, digits, hyphen or underscore.
-
400DISCOUNT_PRIORITY_RANGEPriority is outside priority_min to max_priority.
-
400DISCOUNT_VALUE_RANGEA percentage value is not above 0 and at most 100.
-
400DISCOUNT_PERCENTAGE_TOO_PRECISEA percentage has more than percentage_decimal_places decimal places.
-
400DISCOUNT_VALUE_FORBIDDENValue was sent for a type that does not take one.
-
400DISCOUNT_AMOUNTS_REQUIREDA fixed-amount discount has no amounts.
-
400DISCOUNT_AMOUNTS_FORBIDDENAmounts were sent for a type that does not take them.
-
400DISCOUNT_CURRENCY_BASE_REQUIREDA money map is missing the store's base currency.
-
400DISCOUNT_CURRENCY_INVALIDA money map uses a currency not assigned to the market.
-
400DISCOUNT_CURRENCY_VALUE_RANGEA money value is not greater than 0.
-
400DISCOUNT_CURRENCY_VALUE_TOO_LARGEA money value is above money_amount_max.
-
400DISCOUNT_CURRENCY_VALUE_TOO_PRECISEA money value, fixed Buy X Get Y value, tier threshold or fixed tier value has more decimal places than its currency.
-
400DISCOUNT_APPLIES_TO_INVALIDApplies_to is not a supported value.
-
400DISCOUNT_ENTIRE_ORDER_ONLYA Buy X Get Y, bundle or tiered discount was not set to entire_order.
-
400DISCOUNT_ELIGIBILITY_INVALIDCustomer_eligibility is not a supported value.
-
400DISCOUNT_TARGETS_REQUIREDSpecific targeting or eligibility was chosen without its id list, or a referenced id is malformed, does not exist, or belongs to another store.
-
400DISCOUNT_TARGETS_FORBIDDENAn id list was sent that does not match the targeting or eligibility, exclude_sale_items or show_in_cart was set where it is not supported, or a Buy X Get Y item has an unsupported item_type.
-
400DISCOUNT_MIN_QUANTITY_FORBIDDENMin_quantity was sent for Buy X Get Y, bundle or tiered.
-
400DISCOUNT_MIN_QUANTITY_RANGEMin_quantity is below quantity_min.
-
400DISCOUNT_MIN_QUANTITY_TOO_LARGEMin_quantity is above min_quantity_max.
-
400DISCOUNT_MAX_DISCOUNT_FORBIDDENMax_discount was sent for fixed-amount, Buy X Get Y or free gift.
-
400DISCOUNT_USAGE_LIMIT_RANGEUsage_limit is not -1, null, or within quantity_min to max_usage_limit.
-
400DISCOUNT_PER_CUSTOMER_RANGEPer_customer_limit is not -1, null, or within quantity_min to max_per_customer_limit.
-
400DISCOUNT_DATE_INVALIDStarts_at or ends_at is not in YYYY-MM-DDTHH:mm:ss form.
-
400MARKET_DISCOUNT_DATE_INVALIDEnds_at is not after starts_at.
-
400DISCOUNT_BXGY_FIELDS_FORBIDDENBuy X Get Y fields were sent for another type.
-
400DISCOUNT_BXGY_BUY_REQUIREDBuy X Get Y has no valid buy items.
-
400DISCOUNT_BXGY_GET_REQUIREDBuy X Get Y has no valid reward items.
-
400DISCOUNT_BXGY_QUANTITY_RANGEA buy or reward quantity is outside 1 to max_bxgy_quantity.
-
400DISCOUNT_GET_TYPE_REQUIREDBuy X Get Y has no bxgy_get_type.
-
400DISCOUNT_GET_TYPE_INVALIDBxgy_get_type is not free, percentage or fixed.
-
400DISCOUNT_GET_VALUE_FORBIDDENBxgy_get_value was sent for free rewards.
-
400DISCOUNT_GET_VALUE_RANGEA percentage reward is not above 0 and at most 100.
-
400DISCOUNT_GET_VALUE_POSITIVEA fixed reward amount is not greater than 0.
-
400DISCOUNT_GET_VALUE_TOO_LARGEA fixed reward amount is above money_amount_max.
-
400DISCOUNT_MAX_USES_PER_ORDER_RANGEBxgy_max_uses is below bxgy_max_uses_min.
-
400DISCOUNT_MAX_USES_PER_ORDER_TOO_LARGEBxgy_max_uses is above bxgy_max_uses_max.
-
400DISCOUNT_BUNDLE_FIELDS_FORBIDDENBundle fields were sent for another type.
-
400DISCOUNT_BUNDLE_MODE_REQUIREDA bundle has no bundle_value_mode.
-
400DISCOUNT_BUNDLE_MODE_INVALIDBundle_value_mode is not fixed_price or percentage, the other mode's field was also sent (bundle_percentage with fixed_price, or bundle_prices with percentage), or a component's item_type is not product or variant.
-
400DISCOUNT_BUNDLE_PRICE_REQUIREDA fixed-price bundle has no bundle_prices.
-
400DISCOUNT_BUNDLE_PERCENT_REQUIREDA percentage bundle has no valid bundle_percentage.
-
400DISCOUNT_BUNDLE_ITEMS_RANGEThe number of components is outside bundle_components_min to bundle_components_max, or a component has a blank item_id.
-
400DISCOUNT_BUNDLE_ITEM_DUPLICATEThe same product or variant appears twice in the bundle.
-
400DISCOUNT_BUNDLE_ITEM_QUANTITYA component quantity is outside 1 to bundle_item_quantity_max.
-
400DISCOUNT_BUNDLE_MAX_SETS_RANGEBundle_max_sets is not -1, null, or within bundle_max_sets_min to bundle_max_sets_max.
-
400DISCOUNT_GIFT_FIELDS_FORBIDDENGift fields were sent for another type.
-
400DISCOUNT_GIFT_MODE_INVALIDGift_mode is not offer or auto_add.
-
400DISCOUNT_GIFT_ITEMS_RANGEThe number of gift items is outside gift_items_min to gift_items_max.
-
400DISCOUNT_GIFT_ITEM_DUPLICATEThe same gift product or variant appears twice.
-
400DISCOUNT_GIFT_ITEM_QUANTITYA gift quantity is outside 1 to gift_item_quantity_max.
-
400DISCOUNT_GIFT_NOT_GIFT_ONLYA gift product_id is not positive, does not exist in the store, or is not marked gift-only.
-
400DISCOUNT_GIFT_VARIANT_REQUIREDA variable gift product has no variant_id.
-
400DISCOUNT_GIFT_VARIANT_INVALIDThe gift variant does not exist, belongs to another product, or was sent for a simple product.
-
400DISCOUNT_TIERS_COUNTThe number of tiers is outside tiers_min to tiers_max.
-
400DISCOUNT_TIER_THRESHOLD_INVALIDA tier threshold is negative or above money_amount_max. A threshold with more decimal places than the base currency returns DISCOUNT_CURRENCY_VALUE_TOO_PRECISE instead.
-
400DISCOUNT_TIER_THRESHOLD_ORDERTier thresholds do not strictly increase.
-
400DISCOUNT_TIER_VALUE_INVALIDA tier value is not positive, a percentage is above 100, or an amount is out of range.
-
400MARKET_DISCOUNT_RELATION_LIMIT_REACHEDAn id list is longer than its max_*_per_discount limit.
-
400MARKET_DISCOUNT_RELATION_DUPLICATEAn id appears twice in a targeting, eligibility or Buy X Get Y list, or a product is targeted together with one of its own variants.
-
400STORE_API_INVALID_REQUEST_BODYThe body is not valid JSON, or is not a JSON object.
-
400INVALID_INPUTA field has the wrong JSON type, for example a string where a number is expected.
-
404MARKET_NOT_FOUNDMarket does not exist in this store.
-
409MARKET_DISCOUNT_CODE_DUPLICATEAnother discount in the market has this code, ignoring case.
-
409MARKET_DISCOUNT_PRIORITY_DUPLICATEAnother discount in the market has this priority.
-
404MARKET_DISCOUNT_NOT_FOUNDDiscount does not exist in this market.
Bulk update discounts
Delete, enable or disable selected discounts.
Read discounts/limits first. The batch must contain between 1 and list_max_limit unique, nonzero UUIDs: this is exactly the maximum pagination size, not max_per_market. Empty, duplicate, malformed or oversized selections and unsupported actions are rejected before any writes. Each discount is then processed independently within the authenticated store and requested market. HTTP 200 may contain failed items; inspect every results entry and retry only failed ids. Successful changes are retained if another item fails. Enable resumes the schedule; it does not force a scheduled or expired discount to become active. Each changed discount records the discount and market names in the audit log and publishes discounts/update or discounts/delete together with the change. Unchanged status emits neither. Existing order snapshots remain unchanged.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Body parameters
| Name | Type | Description |
|---|---|---|
ids
required
|
array<uuid> |
Unique discount UUIDs, at most list_max_limit from the limits endpoint. |
action
required
|
string |
delete, enable or disable. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
400INVALID_INPUTInvalid action or ids: selection must be unique, valid UUIDs and contain 1 to list_max_limit items.
-
400STORE_API_INVALID_REQUEST_BODYMissing ids or malformed request body.
Delete a discount
Remove a discount from a market.
Deleting a discount prevents it from applying to future orders and removes its saved targeting and eligibility configuration. Existing orders keep the discount amounts that were recorded when they were placed. A successful deletion publishes discounts/delete with the deleted discount's identity.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
discountId
required
|
string |
Discount id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
404MARKET_NOT_FOUNDMarket does not exist in this store.
-
404MARKET_DISCOUNT_NOT_FOUNDDiscount does not exist in this market.
Enable a discount
Allow a disabled discount to follow its schedule again.
After enabling, the returned status is active, scheduled, or expired according to the saved dates. Enabling a discount that is already enabled changes nothing. The response is the discount with its current usage_count, usage_held_count and usage_summary. A successful state change publishes discounts/update.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
discountId
required
|
string |
Discount id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
404MARKET_NOT_FOUNDMarket does not exist in this store.
-
404MARKET_DISCOUNT_NOT_FOUNDDiscount does not exist in this market.
Disable a discount
Pause a discount without deleting its configuration.
A disabled discount does not apply to new orders and remains disabled until it is enabled explicitly. Disabling a discount that is already disabled changes nothing. The response is the discount with its current usage_count, usage_held_count and usage_summary. A successful state change publishes discounts/update.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
discountId
required
|
string |
Discount id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
404MARKET_NOT_FOUNDMarket does not exist in this store.
-
404MARKET_DISCOUNT_NOT_FOUNDDiscount does not exist in this market.
Get discount settings
Read how discounts are allowed to combine in this market.
In single mode, one discount applies: every eligible automatic discount and every entered code are ranked together by priority_mode, and the first one wins. In stack mode, every eligible automatic discount applies, plus entered codes in ranked order up to coupon_limit; with auto_coupon_combine false, codes apply only when no automatic discount does. best_for_customer ranks by each discount's own saving; manual ranks by priority number, lowest first. Buy X Get Y, bundle and claimed gift offers use specific cart units, and two of them cannot use the same units: the higher-ranked keeps them and the other does not apply at all. Offers apply in three steps (Buy X Get Y, bundle and gift; then product, collection and category discounts; then order-wide discounts), and each uses the amount left after the earlier ones. With apply_to_quantity_priced false, quantity-priced items get no discount and do not count toward minimum spend, minimum quantity or tiers. Settings take effect the next time a cart or checkout is priced; placed orders keep their discounts.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
404MARKET_NOT_FOUNDMarket does not exist in this store.
Update discount settings
Change how discounts combine in this market.
Send only the settings you want to change; omitted or null settings keep their current values. stacking_mode accepts single or stack, and priority_mode accepts best_for_customer or manual. coupon_limit must be a whole number from 1 to the platform maximum, currently 5, and is checked in either mode; a value outside that range is rejected with MARKET_COUPON_LIMIT_OUT_OF_RANGE, and the error states the maximum. A new market starts with single, best_for_customer, 1, true and false. An unchanged request publishes no event; a successful change publishes discount_settings/update with all five settings.
Path parameters
| Name | Type | Description |
|---|---|---|
marketId
required
|
uuid |
Market id. |
Headers
| Name | Type | Description |
|---|---|---|
Authorization
required
|
string |
Bearer Store API token. |
Body parameters
| Name | Type | Description |
|---|---|---|
stacking_mode
|
string |
Use |
priority_mode
|
string |
How discounts are ranked: |
coupon_limit
|
integer |
The maximum number of codes that may apply to one order in stack mode, from 1 to the platform maximum (currently 5). Automatic discounts do not count. |
auto_coupon_combine
|
boolean |
In stack mode, true lets codes apply alongside automatic discounts; false lets codes apply only when no automatic discount applies. No effect in single mode. |
apply_to_quantity_priced
|
boolean |
When false, items with quantity pricing get no discount and do not count toward minimum spend, minimum quantity or tiers. When true, they are discounted like any other item, on top of their quantity price. |
Errors
-
400STORE_API_INVALID_REQUEST_BODYmarketIdmust be a valid UUID. -
400MARKET_STACKING_MODE_INVALIDStacking_mode is not single or stack.
-
400MARKET_PRIORITY_MODE_INVALIDPriority_mode is not best_for_customer or manual.
-
400MARKET_COUPON_LIMIT_OUT_OF_RANGECoupon_limit is below 1 or above the platform maximum (currently 5). The message states the maximum.
-
400STORE_API_INVALID_REQUEST_BODYThe body is not valid JSON or a field has the wrong type.
-
404MARKET_NOT_FOUNDMarket does not exist in this store.