Skip to main content

Guide: Reading from GET Β· ← GET response Β· Application β†’

rule_conditions β€” full reference

info

Field in the GET response

In GET /discounts and GET /discounts/{id}, this block is returned in **rule_conditions** (JSON string). After parsing, the structure is conditions.and[] / conditions.or[] as in this section.

On this page​


What they do​

They define complex eligibility for the campaign to apply: they combine logical operators (and, or) with data from the customer, the cart/cart, and line items (products, categories, attributes, store, payment, totals).

The question they answer at evaluation time: β€œDo this customer and this cart qualify for the discount campaign to apply, or should I discard it?”

Two formats for the same concept​

FormatWhere it usually appearsStructure
**conditions.and[] / conditions.or[]**GET /discounts and GET /discounts/{id} β†’ rule_conditionsTyped clauses with key, field, operator
FlatPOST /discounts examples in Campaigns APIlines[], total_cart, country[], payment_method[]

Prefer the **conditions.and[]** format when reading external listings. Both express the same rules with different serialization.

Logical structure (AND, OR, and subgroups)​

conditions
└── and[] β†’ ALL entries in the array must be satisfied
β”œβ”€β”€ { key, field, operator… } β†’ standalone clause
└── { and: [ … ] } β†’ subgroup: ALL inner clauses must be satisfied

conditions.or[] may also exist (at least one clause in the group must pass). In practice, complex campaigns use several { "and": [ … ] } blocks in the root and (for example, one block for customer conditions + another for lines/store).

When the root node of rule_conditions is conditions.or[] (not a nested or subgroup inside a root and), read it as:

conditions
└── or[] β†’ AT LEAST ONE entry in the array must be satisfied
β”œβ”€β”€ { key, field, operator… } β†’ standalone clause
└── { or: [ … ] } β†’ subgroup: AT LEAST ONE inner clause must be satisfied

How to read the OR diagram: it is enough for one clause or subgroup to pass for the campaign to apply. Only if none pass is the campaign discarded. A subgroup { "or": [ … ] } works the same way: at least one inner clause must pass.

RootRuleIf it fails…
conditions.and[]All must be satisfiedOne failure β†’ discarded
conditions.or[]At least one must be satisfiedAll fail β†’ discarded

How to tell what each clause evaluates​

JSON fieldRole when interpreting the JSON
**field**Authoritative. Indicates which datum is compared. value / values are always interpreted against this field.
**key**Informational only (platform / Owner App label). May help orientation, but does not define what is evaluated. If key and field look inconsistent, field wins.
**array_field**Optional. Indicates which list on the cart the field applies within.
**operator** + **value** / **values**How and against which threshold the field is compared.

Without array_field (cart- or customer-level datum)​

field points directly at the attribute being evaluated.

Quick classification rule:

field prefix / patternFamily
Starts with customer.Customer condition
country, total, original_total, total_cart_without_additional_costs, location_id, location_code, location_categories, attributes.* (without customer.)Cart / cart / store condition
fieldHow to read it
customer.idCustomer ID (customer condition)
countryCountry of the purchase / transaction (cart condition, not customer)
totalCart total
location_idStore by numeric ID
location_codeStore by external code

With array_field (datum inside a cart list)​

The condition iterates each element of the array and evaluates **field** in that context:

array_fieldfieldMeaning
linesproduct_categoriesProduct categories on cart line items
linesproduct_idProduct ID on line items
linesattributes.colorLine attribute (inside lines[].attributes)
paymentstype**type** field on each entry in the payments array (payment method)

Mental example: array_field: lines + field: product_categories + values: ["frutas|17852"] (feature_pk) β†’ β€œAre there line items with that product category?”.

Example: array_field: payments + field: type + values: ["Tarjeta OH!"] β†’ β€œDoes the cart have a payment whose type matches?”.


Structural fields (clauses inside rule_conditions)​

**bundle / grouped (flags) β‰  rule_group (grouping in the effect).**
The bundle and grouped fields in the conditions/application JSON are internal Owner App serialization: ignore their numeric value when integrating from GET.
Bundle / 2-for-1 / grouped combo mechanics are read via **rule_effects.rule_group: true** and the **quantity** subconditions in **rule_conditions** (group size) and **rule_application** (how many units in the group receive the effect). Details: Bundle mechanics (rule_group).

FieldDescription
**field**Evaluated field (data path). Primary reference for integrations
keyInformational platform label; does not replace field
operatorComparison; depends on the data type of field
valueSingle value compared against field
valuesList compared against field (in, not_in, all_in, …)
array_fieldIf present: cart list where field is read (lines, payments)
bundleOnly in **rule_conditions**: internal, ignore value when integrating
groupedOnly in **rule_conditions**: internal, ignore value when integrating
conditionsNested subconditions (typical in clauses with array_field: lines)
payment_method_idsInternal payment method IDs (auxiliary; business criterion remains field: type + values)

Operators by data type​

The valid operator depends on the type of the evaluated attribute or field.

TypeCommon operatorsExample
Text (string)eq, neq, in, not_in, contains, starts_with, ends_with, not_containsloyalty_tier = "silver"; referral_code contains "77777"
Numericeq, neq, gt, gte, lt, lte, in,not_intotal > 40000; quantity >= 1
Booleaneq, neqvip_status = true
Date (ISO string YYYY-MM-DD)eq, neq, gt, gte, lt, ltecustomer.created_at >= "2023-10-27"
List on the customerin, not_in, all_inpreferred_store_ids all_in [1,2,3,4] β†’ all those stores must appear in the customer attribute

Catalog β€” customer conditions​

Use **field** to identify the condition. The key column is informational reference only.

Rule: customer conditions have field that always starts with customer. (e.g. customer.id, customer.attributes.tags, customer.location.country).
field: country (no prefix) is a cart condition, not customer β€” see the cart catalog.

field (evaluate this)key (informational)What it validatesNotes
customer.idcustomer_idMini-segmentation: explicit customer listoperator: in with comma-separated IDs in values; maximum 500 IDs
customer.created_atcustomer_created_atCustomer registration dateDate operators
customer.location.countrycustomer_registration_countriesCountry of the customer’s registration storein / not_in
customer.tier_achievementstierProgram tier(s)values = tier IDs
customer.attributes.name``client_attributesCustom customer propertyOperator depends on attribute type
customer.calculated_attributes.id``client_calculated_attributesCalculated attribute (CDP / Loyalty Insights)id is usually ca_number`` (e.g. ca_125). Operator depends on attribute type

Examples of customer.attributes (master JSON)​

fieldoperatorInterpretation
customer.attributes.tagsinCustomer has at least one of those tags
customer.attributes.interestsnot_inCustomer does not have those interests
customer.attributes.vip_statuseqVIP flag (boolean)
customer.attributes.loyalty_tiereqText tier (silver, …)
customer.attributes.referral_codecontainsCode contains the substring
customer.attributes.customer_scoregtNumeric score greater than threshold
customer.attributes.preferred_store_idsall_inAll listed stores are in the customer’s preferred stores
customer.attributes.preferred_communicationstarts_withPreferred channel starts with the given text
customer.attributes.membership_start_datelteMembership start date on or before

Examples of customer.calculated_attributes (calculated attributes)​

Calculated attributes are defined by the Company in CDP (e.g. recency, frequency, average cart, purchase counters). In JSON they appear as customer.calculated_attributes.ca_id, where ca_id`` is the internal attribute identifier (usual format: ca_125, ca_119).

Example clause (master JSON):

{
"key": "client_calculated_attributes",
"field": "customer.calculated_attributes.ca_125",
"value": 12,
"operator": "neq"
}
{
"key": "client_calculated_attributes",
"field": "customer.calculated_attributes.ca_119",
"value": 122,
"operator": "gt"
}
fieldoperatorvalue / valuesInterpretation
customer.calculated_attributes.ca_125neq12Customer calculated attribute ca_125 is not 12 (numeric)
customer.calculated_attributes.ca_119gt122Attribute ca_119 is greater than 122
customer.calculated_attributes.ca_50gte5Minimum threshold (e.g. β€œat least 5 purchases in 90 days” if ca_50 is defined that way)
customer.calculated_attributes.ca_80in["gold","platinum"]Calculated attribute categorical value is in the list (if the CA is text)
customer.calculated_attributes.ca_200lte"2024-06-01"Date comparison (if the CA is date type; ISO in value)
customer.calculated_attributes.ca_30eqtrueCalculated attribute boolean flag

How to interpret when integrating:

  1. Identify the full **field**: customer.calculated_attributes.ca_XXX.
  2. Look up in the Company what **ca_XXX** means (business name of the calculated attribute in CDP / Company documentation).
  3. Apply **operator** and **value**/values like any numeric, text, or date condition.
  4. Do not confuse with customer.attributes.* (configured profile properties) or line/cart attributes.

If the customer β€œshould” qualify per CRM but the campaign does not apply, verify the calculated attribute is materialized for that customer at purchase time.


Catalog β€” cart conditions​

Conditions on the cart. field does not start with customer. (except cart attributes under attributes.*).

fieldarray_fieldkey (informational)What it validates
countryβ€”countryCountry of the purchase / transaction store. Do not confuse with customer.location.country (registration country)
totalβ€”total_cartCart total; compares the cart’s total field
total_cart_without_additional_costsβ€”total_cart_without_additional_costsDerived total: original_total βˆ’ sum of additional_costs (see below)
original_totalβ€”original_totalOriginal cart total (before campaign discounts in evaluation)
typepaymentspaymentPayment method: evaluates payments[].type against values
attributes.name``β€”cart_attributesTicket attribute (e.g. attributes.customer_notes)

Cart totals: total, original_total, and total_cart_without_additional_costs​

fieldWhat the condition compares
totalThe cart’s current total (total in the purchase payload).
original_totalThe cart’s original total (original_total), useful when you do not want discounts already reflected in total to affect the campaign threshold.
total_cart_without_additional_costsValue calculated by the engine from the cart (not a fixed threshold the integrator sends).

How the system calculates total_cart_without_additional_costs:

It takes the cart’s original_total and subtracts the sum of all values in the additional_costs object:

total_cart_without_additional_costs = original_total βˆ’ Ξ£ (values in additional_costs)

Example cart:

{
"original_total": 100.00,
"additional_costs": {
"cost1": 1.17,
"cost2": 2.99
}
}

Calculation: 100.00 βˆ’ (1.17 + 2.99) = 95.84

If the campaign has:

{
"key": "total_cart_without_additional_costs",
"field": "total_cart_without_additional_costs",
"value": 90,
"operator": "gt"
}

β†’ 95.84 > 90 β†’ condition satisfied (threshold is evaluated on total without those extra costs).

Interpretation:

  • Check original_total and the additional_costs object on the cart (may have one or several keys: cost1, cost2, shipping, insurance, etc.).
  • Do not confuse with total: that is the net total as sent by the integration.
  • If the condition does not match, manually sum additional_costs values and subtract from original_total before comparing with the campaign value.

Catalog β€” store (location)​

fieldkey (informational)What it validatesAuxiliaries
location_idlocation_idSpecific store(s) by IDvalues with numeric IDs
location_codelocation_codeSpecific store(s) by codevalues with store codes (strings)
location_categorieslocation_categoriesStore categoryvalues = list of feature_pk (`taxonomy_slug

location_id vs location_code​

Check **field** (and matching **key**) to know whether values carries store IDs or store codes β€” the same pattern as product_id vs product_code on lines.

field / keyvalues contentExample
location_idNumeric store IDs[4, 5, 3]
location_codeStore external codes (strings)["001966", "002100"]

Example β€” stores by code:

{
"key": "location_code",
"field": "location_code",
"values": ["001966"],
"operator": "in"
}

Interpretation: the cart must be at a store whose code is in values (here 001966).

note

Company identifier logic (Owner save β€” not a GET field)

When the campaign is saved from Owner App, the Company setting location_identifier_logic controls whether location conditions are persisted as location_id or location_code (location_id if unset). Integrations reading GET /discounts only need to honor whatever field / values shape is already in rule_conditions (or rule_application). This setting is not returned on the discount GET payload.

Do not confuse a condition with field: location_code with the top-level GET helper arrays locations_ids / location_codes (POS coupon-server expansion from category taxonomies). Those live on the campaign object when default_apply_discounts is false β€” see POS helper fields.


Catalog β€” line conditions​

Always with **array_field: lines. **field indicates which line property is evaluated.

fieldkey (informational)What it validatesAuxiliaries
product_categoriescart_item_product_categoryProduct categories on the linevalues = list of feature_pk (`taxonomy_slug
product_id / product_codecart_item_product / cart_product_idProduct by line ID or catalogconditions[]
attributes.name``cart_item_attributesCustom line attributeE.g. attributes.color, attributes.product_condition

Line subconditions (conditions[]) β€” in rule_conditions​

In **rule_conditions**, nested subconditions may use line **quantity** and **total**.

In **rule_application**, subconditions only support quantity (not total). See rule_application.

field in subconditionIn rule_conditionsIn rule_application
quantityItem count (gte, lte, …)βœ“ (only subcondition available)
totalItem amount (sum)Not configurable

If the parent clause includes bundle or grouped, those are internal fields β€” do not use them when integrating (do not confuse with effect rule_group).

values format for location_categories and product_categories​

For **field: location_categories** (store) and **field: product_categories** (lines with array_field: lines), each values entry is a feature_pk:

taxonomy_slug|external_id
PartMeaningExample
taxonomy_slugTaxonomy / category slug in the catalogangular_diez, tiendas_mate, frutas
external_idExternal feature ID in that taxonomy64, 123111111, 17852

values examples:

  • Store: ["tiendas_mate|123111111"] with field: location_categories
  • Product on line: ["angular_diez|64", "frutas|17852"] with array_field: lines, field: product_categories

Interpretation: compare the JSON values list with feature_pk values on the cart or in the Company catalog. The auxiliary feature_ids field (numeric) is complementary; the business condition is expressed in **values as feature_pk**, not only by the readable slug.

external_values (feature codes)​

Only product_categories clauses (lines with array_field: lines) may include an external_values array. It does not apply to location_categories. Each entry maps a taxonomy slug to the feature external code (not the numeric external ID used in values):

taxonomy_slug|external_code
PartMeaningExample
taxonomy_slugSame taxonomy slug as in valuesfrutas
external_codeFeature code for external / POS systemscode_1, code_2

Example β€” product categories with codes for external systems:

{
"key": "cart_item_product_category",
"field": "product_categories",
"bundle": 1,
"values": ["frutas|17852"],
"grouped": true,
"operator": "in",
"conditions": [
{
"field": "quantity",
"value": 12,
"operator": "gte"
}
],
"array_field": "lines",
"feature_ids": [17852],
"external_values": [
"frutas|code_1",
"frutas|code_2"
]
}

How to read it:

  • Engine evaluation still uses **values** (feature_pk) and auxiliaries such as **feature_ids**. external_values is additive for external systems that work with feature codes; it does not replace values.
  • The same auxiliary can appear on a matching product_categories clause in **rule_application** (same grammar). Never expect it on location_categories.
  • One feature in values / feature_ids may map to one or more external_values entries (same slug, different codes).

Products on lines: cart_item_product vs cart_product_id​

Always with array_field: lines. **key** indicates how products were configured in Owner App; **field** indicates whether the Company uses product IDs or codes.

key (informational)Origin of products in the campaign
cart_item_productSelection from the Company catalog
cart_product_idManual entry of IDs or codes (without catalog)
fieldvalues content
product_idList of numeric product IDs (e.g. [1, 2, 3, 10045])
product_codeList of product codes/SKUs (e.g. ["CC-33CL-LATA", "SKU-99"])

Example β€” catalog (cart_item_product) + IDs:

{
"key": "cart_item_product",
"field": "product_id",
"array_field": "lines",
"operator": "in",
"values": [1, 2, 3],
"product_ids": ["1", "2", "3"]
}

Interpretation: the campaign requires line items with catalog products whose IDs are in values.

Example β€” catalog + codes:

{
"key": "product_id",
"field": "product_code",
"array_field": "lines",
"operator": "in",
"values": ["CC-33CL-LATA", "AGUA-50CL"]
}

Example β€” manual without catalog (cart_product_id) + exclusion by ID:

{
"key": "product_id",
"field": "product_id",
"array_field": "lines",
"operator": "not_in",
"values": [1, 5, 4]
}

Interpretation: products entered manually in the rule; the cart must not include those product_id values on lines (not_in in the master JSON example).

Example β€” manual + codes:

{
"key": "product_id",
"field": "product_code",
"array_field": "lines",
"operator": "in",
"values": ["PROMO-2024", "OUTLET-X"]
}

Quick rules:

  1. Check **field** (product_id vs product_code) to know what type of list values carries.
  2. Check **key** to know whether selection was catalog (cart_item_product) or manual (cart_product_id).

Common mistakes when reading rule_conditions​

ConfusionHow to resolve it
country vs customer.location.countryfield: country = cart (purchase country); field: customer.location.country = customer (registration country)
β€œCustomer” condition without customer. prefixIf field does not start with customer., it is not a customer condition (e.g. country is cart)
total vs original_total vs total_cart_without_additional_coststotal = cart field; original_total = base without campaign discounts; total_cart_without_additional_costs = original_total βˆ’ sum(additional_costs)
bundle / grouped (numeric value)Internal JSON flags; ignore value. With rule_group: true, do read **quantity** in subconditions
Bundle / 2-for-1 misreadReview trio: rule_conditions (group qty) + rule_application (discounted qty) + rule_effects.rule_group + limits
Relying only on keyEvaluated datum is defined by **field** (+ array_field); key is informational
cart_item_product vs cart_product_idCatalog vs manual entry; same field/values (id or code), different configuration origin
Mixing flags with rule_groupbundle/grouped in JSON β‰  enabling grouping; grouping is marked by **rule_group: true** on the effect
location_code vs top-level location_codesCondition field: location_code = store filter in rule_*; campaign-level location_codes[] = POS helper array (see POS helper fields)
Treating external_values as the win conditionEngine evaluates values / feature_ids; external_values is for external systems only
Operator incompatible with typeE.g. contains on a numeric field makes no sense; check attribute definition
Unparsed JSONIf rule_conditions arrives as a string, deserialize before reading conditions.and
Nested subgroupsOne failure in a single { "and": [ … ] } fails the whole campaign even if the rest of the cart looks correct

Appendix: master JSON map (all options)​

The following reference JSON groups most condition families supported in discounts. When reading a real campaign, identify each clause by its **field** (and array_field if present); use key only as a visual aid.

Master reference JSON​

{
"conditions": {
"and": [
{
"and": [
{ "key": "country", "field": "country", "values": ["ES", "IL", "AF"], "operator": "in" },
{ "key": "client_attributes", "field": "customer.attributes.tags", "values": ["657567"], "operator": "in" },
{ "key": "client_attributes", "field": "customer.attributes.interests", "values": ["electronics"], "operator": "not_in" },
{ "key": "client_attributes", "field": "customer.attributes.vip_status", "value": true, "operator": "eq" },
{ "key": "client_attributes", "field": "customer.attributes.loyalty_tier", "value": "silver", "operator": "eq" },
{ "key": "client_attributes", "field": "customer.attributes.referral_code", "value": "77777", "operator": "contains" },
{ "key": "client_attributes", "field": "customer.attributes.customer_score", "value": 676, "operator": "gt" },
{ "key": "client_attributes", "field": "customer.attributes.preferred_store_ids", "values": [1, 2, 3, 4], "operator": "all_in" },
{ "key": "client_attributes", "field": "customer.attributes.preferred_communication", "value": "push", "operator": "starts_with" },
{ "key": "client_attributes", "field": "customer.attributes.membership_start_date", "value": "2023-10-27", "operator": "lte" },
{ "key": "client_calculated_attributes", "field": "customer.calculated_attributes.ca_125", "value": 12, "operator": "neq" },
{ "key": "client_calculated_attributes", "field": "customer.calculated_attributes.ca_119", "value": 122, "operator": "gt" },
{ "key": "customer_created_at", "field": "customer.created_at", "value": "2023-10-27", "operator": "gte" },
{ "key": "customer_id", "field": "customer.id", "values": [1, 4, 5555, 67777, 88888, 99999], "operator": "in" },
{ "key": "tier", "field": "customer.tier_achievements", "values": [553, 190], "operator": "in" },
{ "key": "customer_registration_countries", "field": "customer.location.country", "values": ["ES", "UY"], "operator": "in" },
{ "key": "total_cart", "field": "total", "value": 40000, "operator": "gt" },
{ "key": "total_cart_without_additional_costs", "field": "total_cart_without_additional_costs", "value": 3500, "operator": "gt" },
{ "key": "original_total", "field": "original_total", "value": 6000, "operator": "gt" },
{ "key": "payment", "field": "type", "values": ["Tarjeta OH!", "Agora Pay Web"], "operator": "in", "array_field": "payments", "payment_method_ids": [95, 92] }
]
},
{
"and": [
{ "key": "location_categories", "field": "location_categories", "values": ["tiendas_mate|123111111"], "operator": "in", "location_ids": [208] },
{ "key": "location_id", "field": "location_id", "values": [4, 5, 3], "operator": "not_in" },
{ "key": "location_code", "field": "location_code", "values": ["001966", "002100"], "operator": "in" },
{ "key": "cart_attributes", "field": "attributes.customer_notes", "value": "testtt", "operator": "contains" },
{ "key": "cart_item_product_category", "field": "product_categories", "bundle": 2, "values": ["angular_diez|64", "0913|68"], "grouped": true, "operator": "in", "conditions": [{ "field": "quantity", "value": 1, "operator": "gte" }, { "field": "total", "value": 100, "operator": "gte" }], "array_field": "lines", "feature_ids": [17817, 17852], "external_values": ["angular_diez|AD-64", "0913|CAT-68"] },
{ "key": "cart_item_product", "field": "product_id", "bundle": 1, "values": [1, 2, 3], "grouped": true, "operator": "in", "conditions": [{ "field": "quantity", "value": 1, "operator": "gte" }], "array_field": "lines", "product_ids": ["1", "2", "3"] },
{ "key": "cart_product_id", "field": "product_id", "bundle": 1, "values": [1, 5, 4], "grouped": true, "operator": "not_in", "conditions": [{ "field": "quantity", "value": 1, "operator": "gte" }], "array_field": "lines" },
{ "key": "cart_item_attributes", "field": "attributes.color", "value": "azuk", "operator": "neq", "array_field": "lines" },
{ "key": "cart_item_attributes", "field": "attributes.bundle_id", "values": ["1222"], "operator": "not_in", "array_field": "lines" }
]
}
]
}
}

Subgroup 1 β€” customer, cart, and payment (quick read)​

#field (reference)One-line read
1countryCart: purchase in ES, IL, or AF (not a customer condition)
2–10customer.attributes.*Customer: filters by properties (tags, tier, VIP, score, …)
11–12customer.calculated_attributes.ca_*Customer: calculated attributes ca_125, ca_119
13customer.created_atCustomer: registered on or after 2023-10-27
14customer.idCustomer: only those IDs (mini-segmentation)
15customer.tier_achievementsCustomer: tier 553 or 190
16customer.location.countryCustomer: enrolled in ES or UY (registration country)
17totalCart: total > 40000
18total_cart_without_additional_costsCart: original_total βˆ’ additional_costs > 3500
19original_totalCart: original total > 6000
20payments[].typeCart: payment Tarjeta OH! or Agora Pay Web (array_field: payments, field: type)

Subgroup 2 β€” store, cart, and lines (quick read)​

#field / contextOne-line read
1location_categoriesStore with feature_pk `tiendas_mate
2location_idStore cannot be 4, 5, or 3
3location_codeStore code must be 001966 or 002100
4attributes.customer_notesCart notes contain testtt
5lines β†’ product_categoriesListed categories, qtyβ‰₯1 and line totalβ‰₯100; optional external_values for codes
6–7lines β†’ product_categoriesOther category rules with different qty subconditions of qty
8lines β†’ product_id, key cart_item_productCatalog: IDs 1–5 in values, qtyβ‰₯1
9lines β†’ product_id, key cart_product_idManual (no catalog): not_in IDs 1,5,4, qtyβ‰₯1
10–12lines β†’ attributes.*Line attributes (color, bundle_id, product condition)


Next: Application (rule_application)