Saltar al contenido principal

Guía: Lectura desde GET · ← Respuesta GET · Aplicación →

rule_conditions — referencia completa

info

Campo en la respuesta GET

En GET /discounts y GET /discounts/{id}, este bloque viene en **rule_conditions** (string JSON). Tras parsear, la estructura es conditions.and[] / conditions.or[] como en esta sección.

Índice​


Qué hacen​

Definen elegibilidad compleja para que la campaña pueda aplicar: combinan operadores lógicos (and, or) con datos del cliente, del carrito/ticket y de las líneas (productos, categorías, atributos, tienda, pago, totales).

Pregunta que responde al momento de evaluar: «¿Este cliente y este ticket cumplen para que la campaña de descuento entre en juego o la descarto?»

Dos formatos del mismo concepto​

FormatoDónde suele aparecerEstructura
**conditions.and[] / conditions.or[]**GET /discounts y GET /discounts/{id} → rule_conditionsCláusulas tipadas con key, field, operator
PlanoEjemplos POST /discounts en API de campañaslines[], total_cart, country[], payment_method[]

Prioriza el formato **conditions.and[]** al leer listados externos. Ambos expresan las mismas reglas con distinta serialización.

Estructura lógica (AND, OR y subgrupos)​

conditions
└── and[] → TODAS las entradas del array deben cumplirse
├── { key, field, operator… } → cláusula suelta
└── { and: [ … ] } → subgrupo: TODAS las cláusulas internas deben cumplirse

También puede existir conditions.or[] (al menos una cláusula del grupo). En la práctica, las campañas complejas usan varios { "and": [ … ] } en el and raíz (por ejemplo, un bloque de condiciones de cliente + otro de líneas/tienda).

Cuando el nodo raíz de rule_conditions es conditions.or[] (no un subgrupo or anidado dentro de un and raíz), la lectura es:

conditions
└── or[] → AL MENOS UNA entrada del array debe cumplirse
├── { key, field, operator… } → cláusula suelta
└── { or: [ … ] } → subgrupo: AL MENOS UNA cláusula interna debe cumplirse

Interpretación del diagrama OR: basta con que una cláusula o subgrupo cumpla para que la campaña pueda aplicar. Solo si ninguna cumple, la campaña queda descartada. Un subgrupo { "or": [ … ] } se interpreta igual: al menos una cláusula interna debe pasar.

RaízReglaSi falla…
conditions.and[]Todas deben cumplirUna sola falla → descartada
conditions.or[]Al menos una debe cumplirTodas fallan → descartada

Cómo identificar qué evalúa cada cláusula​

Campo JSONRol en interpretación del JSON
**field**Autoritativo. Indica qué dato se compara. Los value / values siempre se interpretan contra este campo.
**key**Solo informativo (etiqueta de la plataforma / Owner App). Puede ayudar a orientarse, pero no define qué se evalúa. Si key y field no coinciden en apariencia, manda **field**.
**array_field**Opcional. Indica dentro de qué lista del carrito se aplica el field.
**operator** + **value** / **values**Cómo y con qué umbral se compara el field.

Sin array_field (dato a nivel carrito o customer)​

El field apunta directamente al atributo evaluado.

Regla rápida de clasificación:

Prefijo / patrón del fieldFamilia
Empieza por customer.Condición de cliente
country, total, original_total, total_cart_without_additional_costs, location_id, location_categories, attributes.* (sin customer.)Condición de carrito / ticket / tienda
fieldLectura
customer.idID del customer (condición de cliente)
countryPaís de la compra / transacción (condición de carrito, no de cliente)
totalTotal del carrito
location_idTienda

Con array_field (dato dentro de una lista del carrito)​

La condición recorre cada elemento del array y evalúa el **field** dentro de ese contexto:

array_fieldfieldSignificado
linesproduct_categoriesCategorías de producto en las líneas del carrito
linesproduct_idID de producto en las líneas
linesattributes.colorAtributo de línea (dentro de lines[].attributes)
paymentstypeCampo **type** de cada entrada en el array de pagos (método de pago)

Ejemplo mental: array_field: lines + field: product_categories + values: ["frutas|17852"] (feature_pk) → «¿Hay líneas con esa categoría de producto?».

Ejemplo: array_field: payments + field: type + values: ["Tarjeta OH!"] → «¿El carrito tiene un pago cuyo type coincide?».


Campos estructurales (cláusulas dentro de rule_conditions)​

**bundle / grouped (flags) ≠ rule_group (agrupación en el efecto).**
Los campos bundle y grouped en el JSON de condiciones/aplicación son serialización interna de Owner App: ignora su valor numérico al integrar el GET.
La mecánica de bundle / 2x1 / combo agrupado se lee con **rule_effects.rule_group: true** y las subcondiciones **quantity** en **rule_conditions** (tamaño del grupo) y **rule_application** (cuántas unidades del grupo reciben el efecto). Detalle: Mecánica bundle (rule_group).

CampoDescripción
**field**Campo evaluado (ruta del dato). Es la referencia principal para integraciones
keyEtiqueta informativa de la plataforma; no sustituye a field
operatorComparación; depende del tipo de dato del field
valueValor único comparado contra field
valuesLista comparada contra field (in, not_in, all_in, …)
array_fieldSi existe: lista del carrito donde se lee el field (lines, payments)
bundleSolo en **rule_conditions**: interno, ignorar valor al integrar
groupedSolo en **rule_conditions**: interno, ignorar valor al integrar
conditionsSubcondiciones anidadas (típico en cláusulas con array_field: lines)
payment_method_idsIDs internos de método de pago (auxiliar; el criterio de negocio sigue siendo field: type + values)

Operadores por tipo de dato​

El operador válido depende del tipo del atributo o campo evaluado.

TipoOperadores habitualesEjemplo
Texto (string)eq, neq, in, not_in, contains, starts_with, ends_with, not_containsloyalty_tier = "silver"; referral_code contiene "77777"
Numéricoeq, neq, gt, gte, lt, lte, in,not_intotal > 40000; quantity >= 1
Booleanoeq, neqvip_status = true
Fecha (string ISO YYYY-MM-DD)eq, neq, gt, gte, lt, ltecustomer.created_at >= "2023-10-27"
Lista en el customerin, not_in, all_inpreferred_store_ids all_in [1,2,3,4] → todas esas tiendas deben estar en el atributo del customer

Catálogo — condiciones de cliente​

Usa **field** para identificar la condición. La columna key es solo referencia informativa.

Regla: las condiciones de cliente tienen field que siempre empieza por customer. (ej. customer.id, customer.attributes.tags, customer.location.country).
El field: country (sin prefijo) es condición de carrito, no de cliente — véase catálogo de carrito.

field (evaluar este)key (informativo)Qué validaNotas
customer.idcustomer_idMini-segmentación: lista explícita de clientesoperator: in con values de IDs separados por coma; máximo 500 IDs
customer.created_atcustomer_created_atFecha de registro del customerOperadores de fecha
customer.location.countrycustomer_registration_countriesPaís de la tienda de registro del customerin / not_in
customer.tier_achievementstierTier(s) del programavalues = IDs de tier
customer.attributes.nombre``client_attributesPropiedad personalizada del customerOperador según tipo del atributo
customer.calculated_attributes.id``client_calculated_attributesAtributo calculado (CDP / Loyalty Insights)El id suele ser ca_número`` (ej. ca_125). Operador según tipo del atributo

Ejemplos de customer.attributes (JSON maestro)​

fieldoperatorInterpretación
customer.attributes.tagsinEl customer tiene al menos uno de esos tags
customer.attributes.interestsnot_inEl customer no tiene esos intereses
customer.attributes.vip_statuseqFlag VIP (booleano)
customer.attributes.loyalty_tiereqTier textual (silver, …)
customer.attributes.referral_codecontainsEl código contiene el substring
customer.attributes.customer_scoregtPuntuación numérica mayor que el umbral
customer.attributes.preferred_store_idsall_inTodas las tiendas listadas están en las preferidas del customer
customer.attributes.preferred_communicationstarts_withCanal preferido empieza por el texto indicado
customer.attributes.membership_start_datelteFecha de inicio de membresía anterior o igual

Ejemplos de customer.calculated_attributes (atributos calculados)​

Los atributos calculados los define la Company en CDP (p. ej. recencia, frecuencia, ticket medio, contadores de compra). En el JSON aparecen como customer.calculated_attributes.ca_id, donde ca_id`` es el identificador interno del atributo (formato habitual: ca_125, ca_119).

Cláusula de ejemplo (JSON maestro):

{
"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 / valuesInterpretación
customer.calculated_attributes.ca_125neq12El atributo calculado ca_125 del customer no es 12 (numérico)
customer.calculated_attributes.ca_119gt122El atributo ca_119 es mayor que 122
customer.calculated_attributes.ca_50gte5Umbral mínimo (ej. “al menos 5 compras en 90 días” si así está definido ca_50)
customer.calculated_attributes.ca_80in["gold","platinum"]Valor categórico del atributo calculado está en la lista (si el CA es texto)
customer.calculated_attributes.ca_200lte"2024-06-01"Comparación de fecha (si el CA es tipo fecha; ISO en value)
customer.calculated_attributes.ca_30eqtrueFlag booleano del atributo calculado

Cómo interpretar en integración:

  1. Identifica el **field** completo: customer.calculated_attributes.ca_XXX.
  2. Consulta en la Company qué significa **ca_XXX** (nombre de negocio del atributo calculado en CDP / documentación de la Company).
  3. Aplica el **operator** y **value**/values como en cualquier condición numérica, texto o fecha.
  4. No confundir con customer.attributes.* (propiedades configuradas del perfil) ni con atributos de línea/ticket.

Si el customer “debería” cumplir según CRM pero la campaña no aplica, verifica que el atributo calculado esté materializado para ese customer en el momento de la compra.


Catálogo — condiciones de carrito (carrito)​

Condiciones sobre el carrito de compra. El field no empieza por customer. (salvo atributos del carrito bajo attributes.*).

fieldarray_fieldkey (informativo)Qué valida
country—countryPaís de la tienda de la compra / transacción. No confundir con customer.location.country (país de registro)
total—total_cartTotal del carrito, compara campo 'total' del carrito
total_cart_without_additional_costs—total_cart_without_additional_costsTotal derivado: original_total − suma de additional_costs (véase abajo)
original_total—original_totalTotal original del carrito (antes de descuentos de campaña en la evaluación)
typepaymentspaymentMétodo de pago: evalúa payments[].type contra values
attributes.nombre``—cart_attributesAtributo del carrito (ej. attributes.customer_notes)

Totales del carrito: total, original_total y total_cart_without_additional_costs​

fieldQué compara la condición
totalEl total actual del carrito (total en el payload de compra).
original_totalEl total original del carrito (original_total), útil cuando no quieres que descuentos ya reflejados en total afecten el umbral de la condición.
total_cart_without_additional_costsValor calculado por el motor a partir del carrito (no es un campo que envíe el integrador como umbral fijo).

Cómo calcula el sistema total_cart_without_additional_costs:

Toma el original_total del carrito y le resta la suma de todos los valores dentro del objeto additional_costs:

total_cart_without_additional_costs = original_total − Σ (valores en additional_costs)

Ejemplo de ticket:

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

Cálculo: 100.00 − (1.17 + 2.99) = 95.84

Si la campaña tiene:

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

→ 95.84 > 90 → cumple la condición (el umbral se evalúa sobre el total sin esos costes extra).

Interpretación:

  • Revisa en el carrito original_total y el objeto additional_costs (puede tener una o varias claves: cost1, cost2, envío, seguro, etc.).
  • No confundir con total: ese es el total ya neto/distinto según lo que envíe la integración.
  • Si la condición no cuadra, suma manualmente los valores de additional_costs y resta de original_total antes de comparar con el value de la campaña.

Catálogo — tienda (ubicación)​

fieldkey (informativo)Qué validaAuxiliares
location_idlocation_idTienda(s) concreta(s)values con IDs
location_categorieslocation_categoriesCategoría de tiendavalues = lista de feature_pk (`taxonomy_slug

Catálogo — condiciones en líneas​

Siempre con **array_field: lines**. El **field** indica qué propiedad de cada línea se evalúa.

fieldkey (informativo)Qué validaAuxiliares
product_categoriescart_item_product_categoryCategorías de producto en la líneavalues = lista de feature_pk (`taxonomy_slug
product_id / product_codecart_item_product / cart_product_idProducto por ID en línea o catálogoconditions[]
attributes.nombre``cart_item_attributesAtributo personalizado de líneaEj. attributes.color, attributes.product_condition

Subcondiciones en líneas (conditions[]) — en rule_conditions​

En **rule_conditions**, las subcondiciones anidadas pueden usar **quantity** y **total** de línea.

En **rule_application**, las subcondiciones solo admiten quantity (no total). Ver rule_application.

field en subcondiciónEn rule_conditionsEn rule_application
quantityCantidad de ítems (gte, lte, …)✓ (única subcondición disponible)
totalImporte de los ítems (suma)No configurable

Si la cláusula padre trae bundle o grouped, son campos internos — no usarlos al integrar (no confundir con rule_group del efecto).

Formato de values en location_categories y product_categories​

Para **field: location_categories** (tienda) y **field: product_categories** (líneas con array_field: lines), cada entrada de values es un feature_pk:

taxonomy_slug|external_id
ParteSignificadoEjemplo
taxonomy_slugSlug de la taxonomía / categoría en el catálogoangular_diez, tiendas_mate, frutas
external_idID externo del feature en esa taxonomía64, 123111111, 17852

Ejemplos de values:

  • Tienda: ["tiendas_mate|123111111"] con field: location_categories
  • Producto en línea: ["angular_diez|64", "frutas|17852"] con array_field: lines, field: product_categories

Interpretación: compara la lista values del JSON con los feature_pk que trae el carrito o el catálogo de la Company. El campo auxiliar feature_ids (numéricos) es complementario; la condición de negocio se expresa en **values como feature_pk**, no solo por el slug legible.

Productos en líneas: cart_item_product vs cart_product_id​

Siempre con array_field: lines. El **key** indica cómo se configuraron los productos en Owner App; el **field** indica si la Company trabaja con IDs o códigos de producto.

key (informativo)Origen de los productos en la campaña
cart_item_productSelección desde el catálogo de la Company
cart_product_idIngreso manual de IDs o códigos (sin catálogo)
fieldContenido de values
product_idLista de IDs numéricos de producto (ej. [1, 2, 3, 10045])
product_codeLista de códigos/SKU de producto (ej. ["CC-33CL-LATA", "SKU-99"])

Ejemplo — catálogo (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"]
}

Interpretación: la campaña exige líneas con productos del catálogo cuyos IDs están en values.

Ejemplo — catálogo + códigos:

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

Ejemplo — manual sin catálogo (cart_product_id) + exclusión por ID:

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

Interpretación: productos escritos a mano en la regla; el carrito no debe llevar esos product_id en líneas (operador not_in en el ejemplo del JSON maestro).

Ejemplo — manual + códigos:

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

Reglas rápidas:

  1. Mira **field** (product_id vs product_code) para saber qué tipo de lista trae values.
  2. Mira **key** para saber si la selección fue por catálogo (cart_item_product) o manual (cart_product_id).

Errores frecuentes al leer rule_conditions​

ConfusiónCómo resolverlo
country vs customer.location.countryfield: country = carrito (país de compra); field: customer.location.country = cliente (país de registro)
Condición “de cliente” sin prefijo customer.Si el field no empieza por customer., no es condición de cliente (ej. country es carrito)
total vs original_total vs total_cart_without_additional_coststotal = campo del carrito; original_total = base sin descuentos de campaña; total_cart_without_additional_costs = original_total − sum(additional_costs)
bundle / grouped (valor numérico)Flags internos en JSON; ignorar valor. Con rule_group: true, sí leer **quantity** en subcondiciones
Bundle / 2x1 mal interpretadoRevisar trío: rule_conditions (qty grupo) + rule_application (qty con dto.) + rule_effects.rule_group + limits
Confiar solo en keyEl dato evaluado lo define **field** (+ array_field); key es informativo
cart_item_product vs cart_product_idCatálogo vs ingreso manual; mismo field/values (id o code), distinto origen de configuración
Mezclar flags con rule_groupbundle/grouped en JSON ≠ activar agrupación; la agrupación la marca **rule_group: true** en el efecto
Operador incompatible con el tipoEj. contains en un campo numérico no tiene sentido; revisa definición del atributo
JSON sin parsearSi rule_conditions llega como string, deserializar antes de leer conditions.and
Subgrupos anidadosUn fallo en un solo { "and": [ … ] } hace fallar toda la campaña aunque el resto del carrito parezca correcto

Apéndice: mapa del JSON maestro (todas las opciones)​

El siguiente JSON de referencia agrupa la mayoría las familias de condiciones soportadas en descuentos. Al leer una campaña real, identifica cada cláusula por su **field** (y array_field si existe); usa key solo como ayuda visual.

JSON maestro de referencia​

{
"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" }
]
}
]
}
}

Subgrupo 1 — cliente, carrito y pago (lectura rápida)​

#field (referencia)Lectura en una frase
1countryCarrito: compra en ES, IL o AF (no es condición de cliente)
2–10customer.attributes.*Cliente: filtros por propiedades (tags, tier, VIP, score, …)
11–12customer.calculated_attributes.ca_*Cliente: atributos calculados ca_125, ca_119
13customer.created_atCliente: registrado desde el 2023-10-27
14customer.idCliente: solo esos IDs (mini-segmentación)
15customer.tier_achievementsCliente: tier 553 o 190
16customer.location.countryCliente: alta en ES o UY (país de registro)
17totalCarrito: total > 40000
18total_cart_without_additional_costsCarrito: original_total − additional_costs > 3500
19original_totalCarrito: total original > 6000
20payments[].typeCarrito: pago Tarjeta OH! o Agora Pay Web (array_field: payments, field: type)

Subgrupo 2 — tienda, carrito y líneas (lectura rápida)​

#field / contextoLectura en una frase
1location_categoriesTienda con feature_pk `tiendas_mate
2location_idTienda no puede ser 4, 5 ni 3
3attributes.customer_notesNotas del carrito contienen testtt
4lines → product_categoriesCategorías listadas, qty≥1 y total línea≥100
5–6lines → product_categoriesOtras reglas de categoría con distintas subcondiciones de qty
7lines → product_id, key cart_item_productCatálogo: IDs 1–5 en values, qty≥1
8lines → product_id, key cart_product_idManual (sin catálogo): not_in IDs 1,5,4, qty≥1
9–11lines → attributes.*Atributos de línea (color, bundle_id, condición producto)


Siguiente: Aplicación (rule_application)