Skip to main content

Guide: Reading from GET · ← GET response · Application →

rule_conditions — full reference

:::info Field in the GET response In GET /points and GET /points/{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​


Conditions by when​

whenWhat rule_conditions may include
Cart (after_create_activity)Same grammar as discounts: customer (tier, attributes, registration country), ticket (total, original_total, total_cart_without_additional_costs), lines (product, category, attributes), store / store category, payments (payment method in victory conditions), quantities for bundles.
Custom event (after_create_custom_entity)Filters on custom-entity attributes in the event payload — see Custom event conditions.
Trigger (configured slug)No ticket victory conditions: the API trigger is the condition.
Manual (manual)Required empty: {"conditions":{"and":[]}}.

Custom event conditions​

For when: "after_create_custom_entity", rule_conditions defines when the campaign may accrue based on fields in the event payload (POST /custom_events or equivalent). No cart grammar (lines, ticket, store).

field rule: in key: "custom_event" clauses, field is always data. + the attribute name (e.g. city → "field": "data.city", amount → "field": "data.amount"). The data. prefix is required; do not use bare amount or city in field.

RuleDetail
FieldsAny custom-entity attribute, numeric or not.
fieldAlways data.<attribute_name>.
Clausekey: "custom_event", field, operator (eq, gt, gte, …), value as appropriate; optional entity_attribute_key with the slug without data..
No conditions{"conditions":{"and":[]}} — campaign applies on every event of that type (audience, validity, and win limits still apply).
vs rule_applicationConditions = eligibility (e.g. amount > 100). Application = which numeric field drives the effect (e.g. amount with exists).

Example — event city:

{
"conditions": {
"and": [
{
"and": [
{
"key": "custom_event",
"field": "data.city",
"value": "Montevideo",
"operator": "eq"
}
]
}
]
}
}

Example — minimum amount (can combine with application on amount in the application section):

{
"conditions": {
"and": [
{
"key": "custom_event",
"field": "data.amount",
"operator": "gt",
"value": 100,
"entity_attribute_key": "amount"
}
]
}
}

See also Points Campaigns and Custom event application.

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/ticket, and line items (products, categories, attributes, store, payment, totals).

The question they answer at evaluation time: “Do this customer and this ticket qualify for the points campaign to apply, or should I discard it?”

Two formats for the same concept​

FormatWhere it usually appearsStructure
**conditions.and[] / conditions.or[]**GET /points and GET /points/{id} → rule_conditionsTyped clauses with key, field, operator
FlatPOST /points 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 ticket the field applies within.
**operator** + **value** / **values**How and against which threshold the field is compared.

Without array_field (ticket- 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_categories, attributes.* (without customer.)Cart / ticket / store condition
fieldHow to read it
customer.idCustomer ID (customer condition)
countryCountry of the purchase / transaction (cart condition, not customer)
totalCart total
location_idStore

With array_field (datum inside a ticket 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 ticket 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: ticket 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 ticket, 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/ticket 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 (ticket)​

Conditions on the purchase ticket. field does not start with customer. (except ticket 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 ticket total (before campaign accruals 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 ticket’s current total (total in the purchase payload).
original_totalThe ticket’s original total (original_total), useful when you do not want accruals already reflected in total to affect the campaign threshold.
total_cart_without_additional_costsValue calculated by the engine from the ticket (not a fixed threshold the integrator sends).

How the system calculates total_cart_without_additional_costs:

It takes the ticket’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 ticket:

{
"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 ticket (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)values with IDs
location_categorieslocation_categoriesStore categoryvalues = list of feature_pk (`taxonomy_slug

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

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": "cart_item_product",
"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": "cart_product_id",
"field": "product_id",
"array_field": "lines",
"operator": "not_in",
"values": [1, 5, 4]
}

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

Example — manual + codes:

{
"key": "cart_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 = ticket field; original_total = base without campaign accruals; 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 (accrualed 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
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 ticket looks correct

Appendix: master JSON map (all options)​

The following reference JSON groups most condition families supported in accruals. 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": "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] },
{ "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
3attributes.customer_notesCart notes contain testtt
4lines → product_categoriesListed categories, qty≥1 and line total≥100
5–6lines → product_categoriesOther category rules with different qty subconditions of qty
7lines → product_id, key cart_item_productCatalog: IDs 1–5 in values, qty≥1
8lines → product_id, key cart_product_idManual (no catalog): not_in IDs 1,5,4, qty≥1
9–11lines → attributes.*Line attributes (color, bundle_id, product condition)


Next: Application (rule_application)