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 - Custom event conditions
- What they do
- Two formats for the same concept
- Logical structure (AND, OR, and subgroups)
- How to tell what each clause evaluates
- Structural fields (clauses inside
rule_conditions) - Operators by data type
- Catalog — customer conditions
- Catalog — cart conditions (ticket)
- Catalog — store (location)
- Catalog — line conditions
- Common mistakes when reading
rule_conditions - Appendix: master JSON map (all options)
Conditions by when
when | What 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).
fieldrule: inkey: "custom_event"clauses,fieldis alwaysdata.+ the attribute name (e.g.city→"field": "data.city",amount→"field": "data.amount"). Thedata.prefix is required; do not use bareamountorcityinfield.
| Rule | Detail |
|---|---|
| Fields | Any custom-entity attribute, numeric or not. |
field | Always data.<attribute_name>. |
| Clause | key: "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_application | Conditions = 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
| Format | Where it usually appears | Structure |
|---|---|---|
**conditions.and[] / conditions.or[]** | GET /points and GET /points/{id} → rule_conditions | Typed clauses with key, field, operator |
| Flat | POST /points examples in Campaigns API | lines[], 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.
| Root | Rule | If it fails… |
|---|---|---|
conditions.and[] | All must be satisfied | One failure → discarded |
conditions.or[] | At least one must be satisfied | All fail → discarded |
How to tell what each clause evaluates
| JSON field | Role 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 / pattern | Family |
|---|---|
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 |
field | How to read it |
|---|---|
customer.id | Customer ID (customer condition) |
country | Country of the purchase / transaction (cart condition, not customer) |
total | Cart total |
location_id | Store |
With array_field (datum inside a ticket list)
The condition iterates each element of the array and evaluates **field** in that context:
array_field | field | Meaning |
|---|---|---|
lines | product_categories | Product categories on cart line items |
lines | product_id | Product ID on line items |
lines | attributes.color | Line attribute (inside lines[].attributes) |
payments | type | **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).**
Thebundleandgroupedfields 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).
| Field | Description |
|---|---|
**field** | Evaluated field (data path). Primary reference for integrations |
key | Informational platform label; does not replace field |
operator | Comparison; depends on the data type of field |
value | Single value compared against field |
values | List compared against field (in, not_in, all_in, …) |
array_field | If present: ticket list where field is read (lines, payments) |
bundle | Only in **rule_conditions**: internal, ignore value when integrating |
grouped | Only in **rule_conditions**: internal, ignore value when integrating |
conditions | Nested subconditions (typical in clauses with array_field: lines) |
payment_method_ids | Internal 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.
| Type | Common operators | Example |
|---|---|---|
| Text (string) | eq, neq, in, not_in, contains, starts_with, ends_with, not_contains | loyalty_tier = "silver"; referral_code contains "77777" |
| Numeric | eq, neq, gt, gte, lt, lte, in,not_in | total > 40000; quantity >= 1 |
| Boolean | eq, neq | vip_status = true |
Date (ISO string YYYY-MM-DD) | eq, neq, gt, gte, lt, lte | customer.created_at >= "2023-10-27" |
| List on the customer | in, not_in, all_in | preferred_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
fieldthat always starts withcustomer.(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 validates | Notes |
|---|---|---|---|
customer.id | customer_id | Mini-segmentation: explicit customer list | operator: in with comma-separated IDs in values; maximum 500 IDs |
customer.created_at | customer_created_at | Customer registration date | Date operators |
customer.location.country | customer_registration_countries | Country of the customer’s registration store | in / not_in |
customer.tier_achievements | tier | Program tier(s) | values = tier IDs |
customer.attributes.name`` | client_attributes | Custom customer property | Operator depends on attribute type |
customer.calculated_attributes.id`` | client_calculated_attributes | Calculated attribute (CDP / Loyalty Insights) | id is usually ca_number`` (e.g. ca_125). Operator depends on attribute type |
Examples of customer.attributes (master JSON)
field | operator | Interpretation |
|---|---|---|
customer.attributes.tags | in | Customer has at least one of those tags |
customer.attributes.interests | not_in | Customer does not have those interests |
customer.attributes.vip_status | eq | VIP flag (boolean) |
customer.attributes.loyalty_tier | eq | Text tier (silver, …) |
customer.attributes.referral_code | contains | Code contains the substring |
customer.attributes.customer_score | gt | Numeric score greater than threshold |
customer.attributes.preferred_store_ids | all_in | All listed stores are in the customer’s preferred stores |
customer.attributes.preferred_communication | starts_with | Preferred channel starts with the given text |
customer.attributes.membership_start_date | lte | Membership 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"
}
field | operator | value / values | Interpretation |
|---|---|---|---|
customer.calculated_attributes.ca_125 | neq | 12 | Customer calculated attribute ca_125 is not 12 (numeric) |
customer.calculated_attributes.ca_119 | gt | 122 | Attribute ca_119 is greater than 122 |
customer.calculated_attributes.ca_50 | gte | 5 | Minimum threshold (e.g. “at least 5 purchases in 90 days” if ca_50 is defined that way) |
customer.calculated_attributes.ca_80 | in | ["gold","platinum"] | Calculated attribute categorical value is in the list (if the CA is text) |
customer.calculated_attributes.ca_200 | lte | "2024-06-01" | Date comparison (if the CA is date type; ISO in value) |
customer.calculated_attributes.ca_30 | eq | true | Calculated attribute boolean flag |
How to interpret when integrating:
- Identify the full
**field**:customer.calculated_attributes.ca_XXX. - Look up in the Company what
**ca_XXX**means (business name of the calculated attribute in CDP / Company documentation). - Apply
**operator**and**value**/valueslike any numeric, text, or date condition. - 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.*).
field | array_field | key (informational) | What it validates |
|---|---|---|---|
country | — | country | Country of the purchase / transaction store. Do not confuse with customer.location.country (registration country) |
total | — | total_cart | Cart total; compares the cart’s total field |
total_cart_without_additional_costs | — | total_cart_without_additional_costs | Derived total: original_total − sum of additional_costs (see below) |
original_total | — | original_total | Original ticket total (before campaign accruals in evaluation) |
type | payments | payment | Payment method: evaluates payments[].type against values |
attributes.name`` | — | cart_attributes | Ticket attribute (e.g. attributes.customer_notes) |
Cart totals: total, original_total, and total_cart_without_additional_costs
field | What the condition compares |
|---|---|
total | The ticket’s current total (total in the purchase payload). |
original_total | The 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_costs | Value 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_totaland theadditional_costsobject 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_costsvalues and subtract fromoriginal_totalbefore comparing with the campaignvalue.
Catalog — store (location)
field | key (informational) | What it validates | Auxiliaries |
|---|---|---|---|
location_id | location_id | Specific store(s) | values with IDs |
location_categories | location_categories | Store category | values = list of feature_pk (`taxonomy_slug |
Catalog — line conditions
Always with **array_field: lines**. **field** indicates which line property is evaluated.
field | key (informational) | What it validates | Auxiliaries |
|---|---|---|---|
product_categories | cart_item_product_category | Product categories on the line | values = list of feature_pk (`taxonomy_slug |
product_id / product_code | cart_item_product / cart_product_id | Product by line ID or catalog | conditions[] |
attributes.name`` | cart_item_attributes | Custom line attribute | E.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 subcondition | In rule_conditions | In rule_application |
|---|---|---|
quantity | Item count (gte, lte, …) | ✓ (only subcondition available) |
total | Item 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
| Part | Meaning | Example |
|---|---|---|
taxonomy_slug | Taxonomy / category slug in the catalog | angular_diez, tiendas_mate, frutas |
external_id | External feature ID in that taxonomy | 64, 123111111, 17852 |
values examples:
- Store:
["tiendas_mate|123111111"]withfield: location_categories - Product on line:
["angular_diez|64", "frutas|17852"]witharray_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_product | Selection from the Company catalog |
cart_product_id | Manual entry of IDs or codes (without catalog) |
field | values content |
|---|---|
product_id | List of numeric product IDs (e.g. [1, 2, 3, 10045]) |
product_code | List 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:
- Check
**field** (product_idvsproduct_code) to know what type of listvaluescarries. - Check
**key**to know whether selection was catalog (cart_item_product) or manual (cart_product_id).
Common mistakes when reading rule_conditions
| Confusion | How to resolve it |
|---|---|
country vs customer.location.country | field: country = cart (purchase country); field: customer.location.country = customer (registration country) |
“Customer” condition without customer. prefix | If 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_costs | total = 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 misread | Review trio: rule_conditions (group qty) + rule_application (accrualed qty) + rule_effects.rule_group + limits |
Relying only on key | Evaluated datum is defined by **field** (+ array_field); key is informational |
cart_item_product vs cart_product_id | Catalog vs manual entry; same field/values (id or code), different configuration origin |
Mixing flags with rule_group | bundle/grouped in JSON ≠ enabling grouping; grouping is marked by **rule_group: true** on the effect |
| Operator incompatible with type | E.g. contains on a numeric field makes no sense; check attribute definition |
| Unparsed JSON | If rule_conditions arrives as a string, deserialize before reading conditions.and |
| Nested subgroups | One 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 |
|---|---|---|
| 1 | country | Cart: purchase in ES, IL, or AF (not a customer condition) |
| 2–10 | customer.attributes.* | Customer: filters by properties (tags, tier, VIP, score, …) |
| 11–12 | customer.calculated_attributes.ca_* | Customer: calculated attributes ca_125, ca_119 |
| 13 | customer.created_at | Customer: registered on or after 2023-10-27 |
| 14 | customer.id | Customer: only those IDs (mini-segmentation) |
| 15 | customer.tier_achievements | Customer: tier 553 or 190 |
| 16 | customer.location.country | Customer: enrolled in ES or UY (registration country) |
| 17 | total | Cart: total > 40000 |
| 18 | total_cart_without_additional_costs | Cart: original_total − additional_costs > 3500 |
| 19 | original_total | Cart: original total > 6000 |
| 20 | payments[].type | Cart: payment Tarjeta OH! or Agora Pay Web (array_field: payments, field: type) |
Subgroup 2 — store, cart, and lines (quick read)
| # | field / context | One-line read |
|---|---|---|
| 1 | location_categories | Store with feature_pk `tiendas_mate |
| 2 | location_id | Store cannot be 4, 5, or 3 |
| 3 | attributes.customer_notes | Cart notes contain testtt |
| 4 | lines → product_categories | Listed categories, qty≥1 and line total≥100 |
| 5–6 | lines → product_categories | Other category rules with different qty subconditions of qty |
| 7 | lines → product_id, key cart_item_product | Catalog: IDs 1–5 in values, qty≥1 |
| 8 | lines → product_id, key cart_product_id | Manual (no catalog): not_in IDs 1,5,4, qty≥1 |
| 9–11 | lines → attributes.* | Line attributes (color, bundle_id, product condition) |