Skip to Content

Automatizaciones

Lo que recibe tu propio sistema de una automatización, la solicitud API como usuario Workflow y la estructura de un flujo

Última actualización el

Las automatizaciones hacen que Tillor ejecute acciones por sí mismo, como crear tareas o llamar a tu sistema. La explicación para usuarios está en Automatizaciones. Esta página describe lo que ve un integrador: el mensaje del paso Enviar webhook, la Solicitud API a una URL propia o a la API de Tillor, y cómo está construido un flujo si lo gestionas mediante la API.

Enviar webhook

El paso Enviar webhook entrega un mensaje propio a uno de los webhooks de la organización. Es la misma entrega que con los eventos de webhook normales, con la misma firma.

El mensaje

El paso hace un POST con Content-Type: application/json y estas cabeceras:

CabeceraContenido
X-Webhook-Event-IDUn ID único para esta entrega. En los reintentos el valor se mantiene igual, así que puedes deduplicar con él
X-Webhook-Signaturesha256=<hex>, el HMAC-SHA256 del cuerpo con el signing secret del webhook

El cuerpo tiene el mismo sobre que la carga útil del webhook:

{
  "event": "automation.invoice_unpaid",
  "data": {
    "invoice": "2026-0042",
    "amountOutstanding": 125.5
  },
  "timestamp": 1735689600000,
  "traceId": "0b0f7c0e-5d3c-4c1e-9b8a-7f1e2a3b4c5d",
  "triggeredBy": null
}
CampoDescripción
eventEl Nombre del evento que rellenaste en el paso. Se permite cualquier texto, el nombre no tiene que estar en la lista de claves de evento
dataLa Carga útil del paso, una vez rellenadas las variables, como JSON
timestampHora Unix en milisegundos de la entrega
traceIdUn UUID aleatorio por entrega. A diferencia de los eventos del sistema, no es el ID de traza de una acción de Tillor
triggeredBySiempre null

No hay spanId. El webhook no tiene que estar suscrito a una clave de evento: un mensaje de una automatización siempre se entrega en el endpoint elegido, mientras exista y esté activado.

Cómo verificar la firma está en Verificar la firma.

Intentos y resultado

Dentro del paso, Tillor hace hasta 5 intentos, con 1, 2, 4 y 8 segundos de espera entre ellos. Un intento cuenta como correcto con un estado 2xx. También un destino bloqueado, por ejemplo una dirección interna, cuenta como intento fallido.

  • Si uno de los intentos tiene éxito, el flujo continúa por la salida Correcto
  • Si los cinco fallan, el flujo continúa por Fallido. Después, el mensaje se sigue reintentando en segundo plano según el calendario de Comportamiento de entrega y reintentos. Si uno de esos intentos posteriores tiene éxito, ya no se refleja en la ejecución, porque esta ya ha continuado

Si el webhook ya no existe o está desactivado, el paso no sale por Fallido. La ejecución se detiene entonces con el estado Fallido.

Solicitud API a una URL propia

Con Solicitud API y Enviar a en URL personalizada, una automatización envía una solicitud HTTP a tu servidor.

ParteComportamiento
MétodoGET, POST, PUT, PATCH o DELETE
URLDebe empezar por https://. Las variables se rellenan codificadas
CuerpoJSON. No se envía con GET y DELETE. Con cuerpo, Tillor pone Content-Type: application/json
CabecerasLibres. Los valores pueden contener variables. Host, Content-Length, Transfer-Encoding y Connection se ignoran
DestinoLas direcciones privadas e internas se rechazan, incluso si un nombre de dominio normal apunta a ellas
RedireccionesNo se siguen. Una respuesta 3xx cuenta como fallida
Tiempo de espera15 segundos

Sin firma

A diferencia de Enviar webhook, Tillor no firma esta solicitud. Si quieres comprobar que una solicitud procede de tu automatización, pon un secreto en una cabecera y compruébalo por tu lado. Las cabeceras se guardan cifradas, así que una clave o un token ahí dentro está seguro.

Una respuesta con estado 2xx continúa por Correcto, cualquier otro estado por Fallido. Si no se puede alcanzar el servidor, o supera el tiempo de espera, la ejecución se detiene con el estado Fallido.

Solicitud API a la API de Tillor

Con Enviar a en Tillor API, la automatización llama a la API de la propia organización. Solo indicas una ruta, por ejemplo /tasks, y Tillor la coloca detrás de /api/orgs/{orgId}. Tu referencia de API está en OpenAPI.

  • Identidad: la solicitud se ejecuta como el usuario Workflow de la organización. Tiene todos los permisos dentro de esa organización y en ningún otro sitio. Los cambios figuran, pues, a nombre de Workflow
  • No hace falta clave: Tillor ejecuta la llamada por sí mismo, sin clave de API y sin pasar por internet
  • Ruta: debe empezar por una sola /. No se permiten //, .. ni \. Se admite una cadena de consulta, por ejemplo /tasks?terrainId=…&limit=1. Las variables en la ruta se rellenan codificadas
  • Bloqueado: las rutas /automations y /automation-runs se rechazan, también con cadena de consulta, mayúsculas, una / final o codificación porcentual. Una automatización no puede gestionar automatizaciones
  • Cuerpo: JSON, para POST, PUT y PATCH. Con GET y DELETE no se envía
  • Menú de selección: en el editor figura Elige un endpoint de la API con las operaciones de la especificación OpenAPI. Las operaciones internas no aparecen. Si eliges una, Tillor rellena el método, la ruta y un cuerpo de ejemplo
  • Fallos: una respuesta 2xx continúa por Correcto. Un estado de error, también un 404 para una ruta que no existe, sale por Fallido

La respuesta en pasos posteriores

Tras la solicitud están disponibles estas variables:

VariableContenido
{response.status}El código de estado HTTP
{response.body}Los primeros 4000 caracteres de la respuesta como texto
{response.data}La respuesta como JSON. null si no es JSON, o si tiene más de 100.000 caracteres. Las listas se direccionan con un índice, por ejemplo {response.data.items.0.id}

Una segunda solicitud API en el mismo flujo sustituye a response. Las variables funcionan como en Variables y plantillas.

La estructura de un flujo

También puedes crear y modificar automatizaciones mediante la API. Las operaciones están en OpenAPI bajo la etiqueta automations. Leer requiere el permiso automations:read, crear y modificar automations:write (o todos los permisos). El propio usuario Workflow nunca puede llamarlas. Puede ser más práctico construir un flujo en el editor y leerlo como ejemplo.

Una automatización nueva siempre está desactivada. Activarla mediante enabled no funciona mientras el flujo tenga problemas abiertos, y un flujo activado no se puede guardar con problemas.

La definition consta de pasos (nodes), líneas (edges) y, opcionalmente, notas (notes). Máximo 100 pasos, 200 líneas y 50 notas.

{
  "nodes": [
    {
      "id": "trigger",
      "type": "trigger",
      "label": "",
      "position": { "x": 0, "y": 0 },
      "config": { "source": "event", "eventKey": "occupation:ended" }
    },
    {
      "id": "task",
      "type": "taskCreate",
      "label": "",
      "position": { "x": 0, "y": 190 },
      "config": { "title": "Controleer {occupation.terrain.name}", "priority": "HIGH" }
    }
  ],
  "edges": [
    { "id": "trigger:out:task", "source": "trigger", "target": "task", "sourceHandle": "out" }
  ],
  "notes": [
    {
      "id": "note_1",
      "text": "Maakt na elk vertrek een controletaak.",
      "position": { "x": 340, "y": 0 },
      "width": 240,
      "height": 140
    }
  ]
}

Una nota (notes) es una explicación en el lienzo. Nunca se ejecuta y no tiene líneas. text tiene como máximo 2000 caracteres, width y height están en píxeles.

Una línea tiene un sourceHandle: la salida del paso de la que parte.

Paso (type)Salidas (sourceHandle)
trigger, delay, waitUntilOpen, waitUntilClosed, taskCreate, taskSetStatus, taskSetPriority, taskUpdate, invoiceReminderSend, invoiceSend, invoicePrint, occupationExtendInvoice, staffNotify, commentCreate, inboxReply, inboxTag, customerUpdate, accessMethodCreate, accessMethodUpdate, accessMethodSendQr, accessPointControl, meterSwitch, nfcTagUpdate, deviceCommand, deviceDisplay, deviceSlideshow, controllerRelay, controllerCommandout
customerMessageSend, reservationSetStatus, invoiceBook, paymentLinkCreate, mandateRequest, mandateCollect, consumptionInvoiceout, skipped
conditionyes, no
switchEl id de cada rama, más default
openingHoursopen, closed
throttlepass, blocked
taskFind, documentFind, recordLookupfound, notFound
forEacheach, done
waitUntilmet, timeout
waitForEventreceived, timeout
approvalapproved, rejected, timeout
webhookSend, httpRequestsuccess, failed

Cada acción, salvo webhookSend y httpRequest, recibe una salida adicional error en cuanto continueOnError está en true en el config. Sin ese ajuste, una acción fallida detiene la ejecución. Con él, el flujo continúa por error, con {error.message} y {error.step} como variables para los pasos siguientes. La salida skipped se usa cuando un paso no tenía nada que hacer, y out es entonces la salida normal.

En forEach, la salida each inicia por cada elemento una ejecución propia para los pasos siguientes, y la salida done es el camino normal de continuación del propio flujo.

Una salida puede llevar a varios pasos. La ejecución sigue por sí misma con la primera línea e inicia, por cada otra línea, una ejecución propia con los mismos datos, que corre en paralelo (como la salida each de forEach). Las líneas que forman un bucle se rechazan en el editor. Un flujo tiene exactamente un trigger.

Ajustes por paso

Los campos de config son los campos del editor. Los campos de texto aceptan variables entre llaves.

PasoCampos en config
triggersource (event, webhook, invoiceOverdue, dateReached, daily o cron), webhookVersion (con webhook: texto, auméntalo para sustituir la dirección), eventKey, date (con dateReached: una ruta record.campo a una columna DateTime de un modelo que envía un evento completo, como reservation.checkIn o contact.birthday, o a una clave de fecha declarada en una columna JSON, como document.userMetadata.insuranceExpiryDate; los nombres antiguos como reservationCheckIn siguen funcionando), dateOffset ({ "amount", "unit" }), dateDirection (before o after), dateTime (exact: la hora de la fecha, o fixed: el día natural de la fecha en la zona horaria de la organización, con dateHour y dateMinute, texto como "9" y "0"; el desplazamiento cuenta en el reloj, es decir, atravesando el horario de verano e invierno), repeatYearly (booleano: solo cuentan día y mes, cada año), hour y minute (texto, por ejemplo "8" y "0", minuto de 0 a 59), cron (cinco campos; el día de la semana puede ser 1#2 o 1L, un sexto campo W2:2026-10-05 repite cada dos semanas), conditions, oncePerRecord (booleano)
conditionconditions
switchfield (una ruta de variable sin llaves), cases: una lista de { "id", "key", "value" } con key como nombre de la rama y value como valor al que debe ser igual el campo. Máximo 8 ramas
delaymode (duration o untilDate), duration y offset como { "amount", "unit" } con unit igual a seconds, minutes, hours, days o weeks, dateField (ruta de variable), direction (before o after)
taskCreatetitle, description, assigneeIds, labelIds, assignActor, priority (LOW, MEDIUM, HIGH o URGENT), viewId, laneId, subtasks (una por línea), dueIn ({ "amount", "unit" }), linkRecords
taskSetStatustaskId, status (PENDING, IN_PROGRESS, WAITING o COMPLETED)
taskFindtitle (título exacto), linkedToRecords, onlyOpen, onlyTopLevel (booleanos)
documentFindcustomerId (plantilla), documentType (INSURANCE_POLICY, INSURANCE_PAYMENT_PROOF, IDENTITY_CARD, SEPA_MANDATE, OTHER o vacío), onlyActive, onlyValid (booleanos). Resultado bajo foundDocument
documentUpdatedocumentId (plantilla), documentType (vacío mantiene el tipo), status (ACTIVE, ARCHIVED o vacío)
taskSetPrioritytaskId, mode (raise, lower o set), priority (con set), maxPriority (con raise)
taskUpdatetaskId, title, assigneeIds, assignActor, assigneeMode (add o replace), labelIds, dueIn ({ "amount", "unit" } con unit igual a minutes, hours, days o weeks)
invoiceReminderSend, invoiceSend, invoiceBookinvoiceId
invoicePrintinvoiceId, printer (a4, pos o tablet)
paymentLinkCreateinvoiceId, method (any, BANCONTACT, IDEAL, CREDITCARD o PAYCONIQ)
mandateRequestcustomerId, mode (request o reminder)
mandateCollectinvoiceId, delayDays (texto, predeterminado "0", como máximo 7)
consumptionInvoicecustomerId, sendEmail, sendSms
occupationExtendInvoiceoccupationId, includeConsumption
customerMessageSendcustomerId, subject, body, sendEmail, sendSms, sendWhatsApp
staffNotifyuserIds, notifyActor, title, body, sendPush, sendEmail
commentCreatecontent, target (event o task), taskId (con task)
inboxReplythreadId, body, keepAssistant
inboxTagthreadId, tagIds, archive
customerUpdatecustomerId, status (keep, DEFAULT, PREFERRED, VIP, WARNING o BLACKLISTED), notes
reservationSetStatusreservationId, action (checkIn, checkOut o cancel)
accessMethodCreatecustomerId, type (QR_CODE, LPR, PIN_CODE o NFC), value, periodFrom, periodTo (variables con una fecha, vacío significa sin límite)
accessMethodUpdatescope (one o customer), accessMethodId (con one), customerId (con customer), status (keep, ACTIVE, SOFT_BLOCKED, BLOCKED o INACTIVE), periodTo
accessMethodSendQraccessMethodId, sendEmail, sendSms, sendWhatsApp, print (none, label o thermal)
accessPointControlaccessPointId, action (open o close)
meterSwitchtarget (terrain o meter), terrainId (con terrain), meterId (con meter), state (on u off)
nfcTagUpdatecustomerId, action (block, unblock, topUp o lowBalance), amount (con topUp, en euros por tag)
deviceCommanddeviceId, command (wake, sleep, reload, identify, testSound o playSound), url (con playSound: la ruta de un sonido subido, tal como la rellena el editor, o un enlace https a un archivo mp3, wav o m4a)
deviceDisplaykind (pdf o image), url (enlace https). Aparece en cada tableta configurada como pantalla, como un PDF de factura
controllerRelaytarget (controller o event: el controlador del evento controller:input:changed que inició el flujo), controllerId (con controller), relay (texto "1" a "6"), action (pulse, on u off), durationSeconds (con pulse, texto, de 0.001 a 3600 con decimales como "0.5"; el relé vuelve a soltarse solo)
controllerCommandtarget y controllerId como en controllerRelay, command (reboot, rebootExtension, otaUpdate, forceOtaUpdate, extensionOtaUpdate o refreshSettings)
deviceSlideshowscope (displays o device), mode (screensaver o background), source (feed o urls). Con feed: itemsPath, imageField, opcionalmente campos de filtro y ordenación
openingHours, waitUntilOpen, waitUntilClosedSin campos
throttlewindow ({ "amount", "unit" } con unit igual a minutes, hours, days o weeks), key (vacío es por registro que inició el flujo)
recordLookupmodel (Customer, Reservation, Occupation, Invoice, Payment, Terrain, Task, Document, AccessMethod, NfcTag, Meter, InboxThread o InboxMessage), recordId. El resultado está bajo found más el modelo, como foundCustomer
forEachsource (customerAccessMethods, customerNfcTags, customerOpenInvoices, customerUpcomingReservations, customerOccupations, customerDocuments (solo ACTIVE) o terrainMeters), parentId (id del cliente o del terreno). Como máximo 100 elementos, el elemento está bajo item
waitUntilconditions, interval y timeout ({ "amount", "unit" } con unit igual a minutes, hours, days o weeks; el intervalo es de al menos 5 minutos)
waitForEventeventKey, sameRecord (booleano), timeout ({ "amount", "unit" })
approvaltitle, description, assigneeIds, timeout ({ "amount", "unit" }). La tarea está bajo approvalTask.id
Cada acción salvo webhookSend y httpRequestcontinueOnError (booleano)
webhookSendwebhookId, event, payload (JSON como texto)
httpRequesttarget (tillor o custom), method, path (con tillor), url (con custom), headers (lista de { "id", "key", "value" }), body (JSON como texto)

conditions tiene la forma { "match": "all" o "any", "rules": [...] }. Cada regla es { "id", "field", "operator", "value", "values" }. operator es is, isNot, contains, greaterThan, lessThan, isOneOf, isEmpty o isNotEmpty. values solo se usa con isOneOf. Una lista de reglas vacía deja pasar todo.

Iniciar una automatización con un webhook

Una automatización con trigger webhook se inicia con un POST a su propia dirección:

curl -X POST "https://tillor.eu/api/orgs/org_abc123/automation-hooks/aut_xxx/<token>?bron=website" \
  -H "Content-Type: application/json" \
  -d '{"email":"jan@voorbeeld.nl","aankomst":"2026-07-14"}'
  • La dirección completa está en el editor, en el trigger, o mediante GET /automations/{id}/webhook-url (con automations:read). El token es el secreto; no hace falta una cabecera para autenticar
  • El cuerpo JSON pasa a ser la variable body, la cadena de consulta query y el momento receivedAt
  • Respuesta 200 con { "accepted": true } en cuanto se inicia la ejecución. Una dirección incorrecta, sustituida o desactivada da 404, un cuerpo de más de 100 KB da 400
  • Muchas llamadas seguidas en poco tiempo no se rechazan: cada llamada válida inicia una ejecución. Usa Ignorar repeticiones en el trigger si la misma llamada puede llegar dos veces, consulta Ignorar repeticiones

Una automatización no puede llamar a su propio webhook mediante una Solicitud API a la API de Tillor.

Elegir una decisión mediante la API

La tarea de un paso Pedir una decisión tiene una acción por cada opción que configuraste en el paso. Obtén la tarea para ver las actions con su id, y elige una con POST /tasks/{id}/actions/{actionId}/choose. Si la opción pide una nota, envíala como { "note": "..." }. La elección es definitiva: cierra la tarea y continúa la automatización por la salida de esa opción. Pueden elegir los compañeros asignados (también mediante un grupo) y los administradores. Consulta OpenAPI para los detalles.

Leer más

¿Te ha resultado útil esta página?

En esta página