API de Campañas
La Streaming API de Loyal Guru expone endpoints para crear, leer y actualizar campañas de forma programática. Las campañas se separan en dos endpoints según su tipo.
Endpoints
| Endpoint | Descripción |
|---|---|
POST /discounts | Crear una campaña de descuento |
PATCH /discounts/:id | Actualizar una campaña de descuento existente |
GET /discounts | Listar todas las campañas de descuento |
POST /points | Crear una campaña de puntos/wallet |
PATCH /points/:id | Actualizar una campaña de puntos existente |
GET /points | Listar todas las campañas de puntos. Soporta el filtro ?when=manual para recuperar exclusivamente las de Asignación directa. |
Crear una campaña de descuento (POST /discounts)
Campos siempre requeridos
| Campo | Tipo | Descripción |
|---|---|---|
name | string | Nombre único de la campaña |
when | string | Debe ser "after_create_activity" |
loyalty_rule_category_id | number | ID de una categoría de campaña existente |
currency | string | Código ISO de divisa (debe estar activa y tener score exchange definido) |
select_customers | string | "all_customers", "loyalty" o "targeted" |
rule_conditions | string (JSON) | Condiciones de victoria. Debe incluir al menos una condición de country |
rule_effects | string (JSON) | Definición del efecto (ver abajo) |
stackability_properties | string | "stackability" o "highest_discount" |
Campos con valores por defecto (opcionales)
| Campo | Por defecto | Notas |
|---|---|---|
active | false | Pon true para activar al crear |
recurrence_type | "daily" | "daily", "weekly", "monthly", "monthly_last" |
once | "always" | Límite de frecuencia: "always", "num_day", "num_month", "num_year", "num_total" |
coupon_required | false (o true si targeted) | Las campañas targeted siempre requieren cupón |
chance_to_accrue_period | "always" | Frecuencia de posibilidades de acumulación |
Estructura del efecto (rule_effects)
{
"key": "percentage",
"type": "percentage",
"value": 15,
"limits": 0,
"rule_group": false,
"distribution": "individual_items"
}
| Campo | Descripción |
|---|---|
type | Uno de: percentage, ratio, direct_value, strikethrough, combo_price, formula |
key | Debe ser igual a type |
value | Valor numérico del descuento. No requerido para strikethrough (usa strikethrough_data) |
limits | Entero ≥ 0. Veces máximas que este efecto puede aplicar por transacción (0 = sin límite) |
rule_group | Booleano. Activa modo bundle/grupo. Solo para percentage, combo_price, direct_value |
distribution | "total", "individual_items" o "individual_items_pro_rata" |
Para tipo ratio, incluye unit:
{
"key": "ratio",
"type": "ratio",
"value": 1,
"unit": 1,
"limits": 0,
"rule_group": false,
"distribution": "individual_items"
}
Para tipo strikethrough, incluye strikethrough_data en lugar de value. Las claves del mapa son product_id o product_code según use la compañía (deben coincidir con el identificador de producto en las líneas del ticket):
{
"key": "strikethrough",
"type": "strikethrough",
"strikethrough_data": {"123456": 19.99, "CC-33CL-LATA": 14.99},
"limits": 0,
"rule_group": false,
"distribution": "individual_items"
}
Para tipo formula, usa este valor exacto:
{
"key": "formula",
"type": "formula",
"value": "lines.total - lines.attributes.promoPrice",
"limits": 0,
"rule_group": false,
"distribution": "individual_items"
}
Apilamiento y prioridad
stackability_properties | Requiere |
|---|---|
"stackability" | Campo priority (entero ≥ 1) |
"highest_discount" | Sin prioridad |
Crear una campaña de puntos (POST /points)
Las campañas de puntos siguen la misma estructura con estas diferencias:
Campo when
Puede ser cualquier slug de momento válido, no solo after_create_activity:
after_create_activity(carrito)after_create_custom_entity(evento personalizado)- Cualquier slug de trigger personalizado
manual(asignación directa)
:::info Audiencia
En puntos no uses select_customers: "all_customers". Solo loyalty o targeted: hace falta un customer identificado para acreditar saldo.
:::
Campos adicionales para campañas de puntos
| Campo | Por defecto | Descripción |
|---|---|---|
transferable | false | Si los puntos acumulados se pueden transferir a otros clientes |
activation_period_type | "relative" | "relative" o "fixed" |
expiration_period_type | "relative" | "relative" o "fixed" |
Activación (relativa):
{
"activation_period_type": "relative",
"activation_delay": 0,
"activation_delay_unit": "days"
}
Caducidad (relativa):
{
"expiration_period_type": "relative",
"availability_duration": 3,
"availability_duration_unit": "months",
"availability_duration_natural": false
}
Restricciones de efecto según el when
Valor de when | Efectos permitidos | Notas |
|---|---|---|
after_create_activity (carrito) | percentage, ratio, direct_value, strikethrough, combo_price, formula | Las tres distribuciones según tipo de efecto; limits y rule_group en carrito — ver Integraciones — Efectos |
after_create_custom_entity | percentage, ratio, direct_value | Solo distribution: total; rule_group: false |
manual (Asignación directa) | Solo direct_value | distribution: total; rule_group: false; select_customers: "loyalty"; rule_conditions: {"conditions": {"and": []}}; apilamiento prioridad 1 |
| Cualquier otro slug de trigger | Solo direct_value | distribution: total; rule_group: false; select_customers: "loyalty" |
Parámetros del cupón (coupon_params)
coupon_params es obligatorio cuando coupon_required = true o select_customers = "targeted".
{
"coupon_params": {
"static_code": "VERANO25"
}
}
Para campañas targeted, campos adicionales:
| Campo | Por defecto | Descripción |
|---|---|---|
auto_select | false | Aplica automáticamente sin que el cliente presente el código |
available_days | null | Duración de validez del cupón (días desde el envío). Requiere available_delay_days |
available_delay_days | null | Retraso antes de que se active el cupón. Requiere available_days |
printable | false | Si el cupón es imprimible |
print_days | 0 | Días tras el envío durante los que el cupón es imprimible |
print_delay_days | 0 | Retraso antes de que el cupón sea imprimible |
priority | 1 | Prioridad de visualización al imprimir |
static_codedebe ser globalmente único. Intentar reutilizar un código existente devuelve un error 400.
Canjear cupones durante una compra
Pasa el código del cupón o voucher en coupons_desired:
{
"id": 5001,
"customer_id": 201,
"total": 120.00,
"currency": "EUR",
"coupons_desired": ["VERANO25"],
"lines": [...]
}
coupons_desiredacepta tanto códigos de cupón estáticos como códigos de voucher únicos. Reemplaza al campo obsoletovouchers_desired.
Respuesta — efectos aplicados
{
"effects": [
{
"rule_id": 2324,
"line": 2,
"rule_name": "Verano 25%",
"type": "discount",
"effectType": "percentage",
"distribution_type": "individual_items",
"select_customers": "loyalty",
"coupon_info": {
"voucher_id": null,
"voucher_code": "VERANO25",
"coupon_id": 122211,
"coupon_name": "Rebajas Verano"
}
}
]
}
coupon_info es null cuando no hay cupón involucrado.