API de Automatizaciones
API de Automatizaciones
Las automatizaciones ejecutan acciones automáticas cuando ocurren eventos en tus cotizaciones. Puedes enviar correos, cambiar estados, disparar webhooks y más — todo basado en condiciones configurables.
Todos los endpoints requieren plan PRO y permiso config:manage (solo Owner).
Listar Automatizaciones
GET /api/automations
Lista todas las automatizaciones del tenant, incluyendo el conteo de ejecuciones.
Respuesta 200 OK:
[
{
"id": "clxyz...",
"name": "Notificar al aceptar",
"trigger": "QUOTE_ACCEPTED",
"isActive": true,
"conditions": [
{ "field": "total", "operator": "gt", "value": 5000 }
],
"actions": [
{ "type": "send_email", "to": "owner", "subject": "Cotización aceptada", "body": "..." }
],
"delayMinutes": 0,
"createdAt": "2026-04-01T10:00:00.000Z",
"_count": { "logs": 12 }
}
]Crear Automatización
POST /api/automations
Permiso: config:manage | Plan: PRO
Cuerpo de la solicitud:
{
"name": "Email al enviar cotización grande",
"trigger": "QUOTE_SENT",
"conditions": [
{ "field": "total", "operator": "gt", "value": 10000 },
{ "field": "client.companyName", "operator": "is_not_empty" }
],
"actions": [
{
"type": "send_email",
"to": "client",
"subject": "Tu cotización está lista",
"body": "Gracias por tu interés. Adjuntamos tu cotización."
}
],
"delayMinutes": 5
}| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| name | string | Sí | Nombre (1-100 caracteres) |
| trigger | string | Sí | Evento que dispara la automatización (ver tabla abajo) |
| conditions | array | No | Condiciones que deben cumplirse (lógica AND) |
| actions | array | Sí | Al menos una acción a ejecutar |
| delayMinutes | number | No | Minutos de retraso antes de ejecutar (predeterminado: 0) |
Respuesta 201 Created: Devuelve la automatización creada.
Triggers (Eventos)
| Trigger | Descripción |
|---|---|
QUOTE_CREATED |
Se creó una nueva cotización |
QUOTE_SENT |
Se envió una cotización al cliente |
QUOTE_VIEWED |
El cliente vio la cotización en el portal |
QUOTE_ACCEPTED |
El cliente aceptó la cotización |
QUOTE_REJECTED |
El cliente rechazó la cotización |
QUOTE_WON |
La cotización se marcó como ganada |
QUOTE_LOST |
La cotización se marcó como perdida |
QUOTE_EXPIRING |
La cotización está por vencer (dentro de 24 horas) |
Condiciones
Las condiciones filtran cuándo se ejecuta la automatización. Todas las condiciones deben cumplirse (lógica AND).
{ "field": "total", "operator": "gt", "value": 5000 }| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| field | string | Sí | Campo a evaluar (ver campos disponibles) |
| operator | string | Sí | Operador de comparación |
| value | string/number | Depende | Valor a comparar (no requerido para is_empty/is_not_empty) |
Operadores
| Operador | Descripción | Tipos compatibles |
|---|---|---|
eq |
Es igual a | todos |
neq |
No es igual a | todos |
gt |
Mayor que | number |
lt |
Menor que | number |
gte |
Mayor o igual a | number |
lte |
Menor o igual a | number |
contains |
Contiene texto | text |
starts_with |
Comienza con | text |
is_empty |
Está vacío (sin valor) | text |
is_not_empty |
No está vacío | text |
Campos disponibles
Cotización
| Campo | Tipo | Operadores |
|---|---|---|
status |
select | eq, neq |
currency |
select | eq, neq |
total |
number | eq, neq, gt, lt, gte, lte |
subtotal |
number | eq, neq, gt, lt, gte, lte |
tax |
number | eq, neq, gt, lt, gte, lte |
shippingCost |
number | eq, neq, gt, lt, gte, lte |
viewCount |
number | eq, neq, gt, lt, gte, lte |
quoteNumber |
number | eq, neq, gt, lt, gte, lte |
notes |
text | eq, neq, contains, starts_with, is_empty, is_not_empty |
Cliente
| Campo | Tipo | Operadores |
|---|---|---|
client.contactName |
text | eq, neq, contains, starts_with |
client.companyName |
text | eq, neq, contains, starts_with, is_empty, is_not_empty |
client.email |
text | eq, neq, contains, starts_with |
client.phone |
text | eq, neq, contains, is_empty, is_not_empty |
Producto
Los campos con prefijo items.* evalúan si algún producto de la cotización cumple la condición.
| Campo | Tipo | Operadores |
|---|---|---|
items.productName |
text | eq, neq, contains, starts_with |
items.model |
text | eq, neq, contains, is_empty, is_not_empty |
items.unitPrice |
number | eq, neq, gt, lt, gte, lte |
items.quantity |
number | eq, neq, gt, lt, gte, lte |
items.discountPct |
number | eq, neq, gt, lt, gte, lte |
Los campos items.* usan lógica "alguno coincide" — la condición se cumple si al menos un producto de la cotización coincide.
Acciones
Cada automatización debe tener al menos una acción. Se ejecutan en orden.
send_email
Envía un correo electrónico.
{
"type": "send_email",
"to": "client",
"subject": "Tu cotización está lista",
"body": "Hemos preparado una cotización personalizada para ti."
}| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| to | string | Sí | "client", "owner" o "custom" |
| customEmail | string | Condicional | Email destino (requerido si to es "custom") |
| subject | string | Sí | Asunto del correo |
| body | string | Sí | Cuerpo del correo |
send_notification
Crea una notificación en la app para el owner.
{
"type": "send_notification",
"title": "Cotización aceptada",
"body": "El cliente ha aceptado la cotización COT-0042"
}change_status
Cambia el estado de la cotización.
{
"type": "change_status",
"newStatus": "SENT"
}Valores válidos: GENERATED, SENT, WON, LOST, ACCEPTED, REJECTED
add_label
Agrega una etiqueta a la cotización.
{
"type": "add_label",
"labelId": "clxyz..."
}create_reminder
Crea un recordatorio para dar seguimiento.
{
"type": "create_reminder",
"delayMinutes": 1440,
"message": "Dar seguimiento a esta cotización"
}fire_webhook
Envía un POST a una URL externa con los datos de la cotización. Ideal para conectar con Zapier, Slack, o cualquier servicio externo.
{
"type": "fire_webhook",
"url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
"headers": {
"Authorization": "Bearer mi-token-secreto"
},
"includeItems": true
}| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| url | string | Sí | URL del webhook (debe ser válida) |
| headers | object | No | Headers HTTP adicionales (ej: Authorization) |
| includeItems | boolean | No | Incluir productos en el payload (predeterminado: true) |
El payload enviado tiene esta estructura:
{
"event": "QUOTE_SENT",
"timestamp": "2026-04-09T14:30:00.000Z",
"data": {
"quote": {
"id": "clxyz...",
"quoteNumber": 42,
"status": "SENT",
"total": 15000,
"subtotal": 13000,
"currency": "MXN",
"notes": "...",
"client": {
"id": "...",
"contactName": "María López",
"companyName": "Acme Corp",
"email": "maria@acme.com"
},
"items": [
{
"productName": "Servicio premium",
"model": "SRV-001",
"unitPrice": 13000,
"quantity": 1,
"discountPct": 0
}
]
}
}
}El webhook tiene un timeout de 5 segundos. Si el servidor no responde a tiempo, la acción se registra como fallida.
Obtener una Automatización
GET /api/automations/:id
Permiso: config:manage | Plan: PRO
Obtiene una automatización con sus últimas 10 ejecuciones.
Respuesta 200 OK: Devuelve la automatización con el array logs.
Actualizar Automatización
PATCH /api/automations/:id
Permiso: config:manage | Plan: PRO
Actualiza una automatización. Todos los campos son opcionales. Incluye isActive para activar o desactivar.
{
"isActive": false
}Respuesta 200 OK: Devuelve la automatización actualizada.
Eliminar Automatización
DELETE /api/automations/:id
Permiso: config:manage
Elimina permanentemente una automatización y todo su historial de ejecución.
Respuesta 200 OK:
{
"ok": true
}Esta operación no se puede deshacer. Se eliminan también todos los registros de ejecución.
Historial de Ejecuciones
GET /api/automations/:id/logs
Permiso: config:manage | Plan: PRO
Lista las ejecuciones de una automatización con paginación.
Parámetros de consulta:
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
| page | number | 1 | Número de página |
| limit | number | 20 | Resultados por página (máximo 100) |
Respuesta 200 OK:
{
"logs": [
{
"id": "clxyz...",
"automationId": "...",
"quoteId": "...",
"tenantId": "...",
"status": "COMPLETED",
"triggeredAt": "2026-04-09T14:30:00.000Z",
"completedAt": "2026-04-09T14:30:01.000Z",
"error": null
}
],
"total": 47,
"page": 1,
"totalPages": 3
}Estados posibles: TRIGGERED, COMPLETED, FAILED.