Skip to Content

Automatizações

O que o seu próprio sistema recebe de uma automatização, o pedido à API como utilizador Fluxo de trabalho e a estrutura de um fluxo

Última atualização em

As automatizações permitem ao Tillor executar ações por si próprio, como criar tarefas ou chamar o seu sistema. A explicação para utilizadores está em Automatizações. Esta página descreve o que um integrador vê: a mensagem do passo Enviar webhook, o Pedido à API para um URL próprio ou para a API do Tillor, e como um fluxo é construído se o gerir através da API.

Enviar webhook

O passo Enviar webhook entrega uma mensagem própria a um dos webhooks da organização. É a mesma entrega que nos eventos de webhook normais, com a mesma assinatura.

A mensagem

O passo faz um POST com Content-Type: application/json e estes cabeçalhos:

CabeçalhoConteúdo
X-Webhook-Event-IDUm ID único para esta entrega. Em novas tentativas o valor mantém-se, por isso pode usá-lo para eliminar duplicados
X-Webhook-Signaturesha256=<hex>, o HMAC-SHA256 do corpo com o segredo de assinatura do webhook

O corpo tem o mesmo envelope que o payload do webhook:

{
  "event": "automation.invoice_unpaid",
  "data": {
    "invoice": "2026-0042",
    "amountOutstanding": 125.5
  },
  "timestamp": 1735689600000,
  "traceId": "0b0f7c0e-5d3c-4c1e-9b8a-7f1e2a3b4c5d",
  "triggeredBy": null
}
CampoDescrição
eventO Nome do evento que preencheu no passo. Qualquer texto é permitido, o nome não tem de constar da lista de chaves de evento
dataO Payload do passo, depois de as variáveis serem preenchidas, como JSON
timestampHora Unix em milissegundos da entrega
traceIdUm UUID aleatório por entrega. Ao contrário dos eventos do sistema, não é o id de rastreio de uma ação do Tillor
triggeredBySempre null

Não há spanId. O webhook não precisa de estar subscrito a uma chave de evento: uma mensagem de uma automatização é sempre entregue ao endpoint escolhido, enquanto este existir e estiver ativo.

Como verificar a assinatura está em Verificar a assinatura.

Tentativas e resultado

O Tillor faz até 5 tentativas dentro do passo, com 1, 2, 4 e 8 segundos de espera entre elas. Uma tentativa conta como bem-sucedida com um estado 2xx. Também um destino bloqueado, por exemplo um endereço interno, conta como tentativa falhada.

  • Se uma das tentativas resultar, o fluxo continua pela saída Sucesso
  • Se as cinco falharem, o fluxo continua por Falhou. A mensagem é depois ainda repetida em segundo plano segundo o calendário em Comportamento de entrega e repetições. Se uma dessas tentativas posteriores resultar, isso já não volta à execução, porque esta já seguiu em frente

Se o webhook já não existir ou estiver desativado, o passo não segue por Falhou. A execução pára então com o estado Falhou.

Pedido à API para um URL próprio

Com Pedido à API e Enviar para em URL personalizado, uma automatização envia um pedido HTTP para o seu servidor.

ElementoComportamento
MétodoGET, POST, PUT, PATCH ou DELETE
URLTem de começar por https://. As variáveis são preenchidas codificadas
CorpoJSON. Não é enviado em GET e DELETE. Com corpo, o Tillor define Content-Type: application/json
CabeçalhosLivres. Os valores podem conter variáveis. Host, Content-Length, Transfer-Encoding e Connection são ignorados
DestinoEndereços privados e internos são rejeitados, mesmo que um nome de domínio normal aponte para eles
RedirecionamentosNão são seguidos. Uma resposta 3xx conta como falhada
Tempo limite15 segundos

Sem assinatura

Ao contrário de Enviar webhook, o Tillor não assina este pedido. Se quiser verificar que um pedido vem da sua automatização, coloque um segredo num cabeçalho e verifique-o do seu lado. Os cabeçalhos são guardados cifrados, por isso uma chave ou um token aí é seguro.

Uma resposta com estado 2xx continua por Sucesso, qualquer outro estado por Falhou. Se o servidor não for alcançável ou exceder o tempo limite, a execução pára com o estado Falhou.

Pedido à API do Tillor

Com Enviar para em Tillor API, a automatização chama a API da própria organização. Indica apenas um caminho, por exemplo /tasks, e o Tillor coloca-o a seguir a /api/orgs/{orgId}. A sua referência da API está em OpenAPI.

  • Identidade: o pedido é executado como o utilizador Fluxo de trabalho da organização. Esse tem todas as permissões dentro dessa organização e em mais nenhuma. As alterações ficam, por isso, em nome de Fluxo de trabalho
  • Sem chave necessária: o Tillor faz a chamada por si próprio, sem chave de API e sem passar pela internet
  • Caminho: tem de começar com uma única /. //, .. e \ não são permitidos. Uma query string é permitida, por exemplo /tasks?terrainId=…&limit=1. As variáveis no caminho são preenchidas codificadas
  • Bloqueado: os caminhos /automations e /automation-runs são rejeitados, mesmo com query string, maiúsculas, uma / final ou codificação percentual. Uma automatização não pode gerir automatizações
  • Corpo: JSON, para POST, PUT e PATCH. Em GET e DELETE não é enviado
  • Menu de escolha: no editor há Escolha um endpoint da API com as operações da especificação OpenAPI. As operações internas não aparecem. Se escolher uma, o Tillor preenche o método, o caminho e um corpo de exemplo
  • Falhas: uma resposta 2xx continua por Sucesso. Um estado de erro, também um 404 para um caminho que não existe, segue por Falhou

A resposta nos passos seguintes

Depois do pedido, estas variáveis estão disponíveis:

VariávelConteúdo
{response.status}O código de estado HTTP
{response.body}Os primeiros 4000 carateres da resposta como texto
{response.data}A resposta como JSON. null se não for JSON, ou se tiver mais de 100.000 carateres. As listas endereça-as com um índice, por exemplo {response.data.items.0.id}

Um segundo pedido à API no mesmo fluxo substitui response. As variáveis funcionam como em Variáveis e modelos.

A estrutura de um fluxo

Pode também criar e alterar automatizações através da API. As operações estão no OpenAPI, na etiqueta automations. Ler exige a permissão automations:read, criar e alterar automations:write (ou todas as permissões). O próprio utilizador Fluxo de trabalho nunca as pode chamar. Pode ser mais prático construir um fluxo no editor e lê-lo como exemplo.

Uma nova automatização está sempre desativada. Ativá-la através de enabled não resulta enquanto o fluxo tiver problemas em aberto, e um fluxo ativado não pode ser guardado com problemas.

A definition é composta por passos (nodes), linhas (edges) e, opcionalmente, notas (notes). No máximo 100 passos, 200 linhas e 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
    }
  ]
}

Uma nota (notes) é uma explicação no ecrã de desenho. Nunca é executada e não tem linhas. text tem no máximo 2000 carateres, width e height são em píxeis.

Uma linha tem um sourceHandle: a saída do passo de onde parte.

Passo (type)Saídas (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
switchO id de cada ramo, mais default
openingHoursopen, closed
throttlepass, blocked
taskFind, documentFind, recordLookupfound, notFound
forEacheach, done
waitUntilmet, timeout
waitForEventreceived, timeout
approvalapproved, rejected, timeout
webhookSend, httpRequestsuccess, failed

Cada ação, exceto webhookSend e httpRequest, ganha uma saída extra error assim que continueOnError no config estiver em true. Sem essa definição, uma ação falhada pára a execução. Com ela, o fluxo continua por error, com {error.message} e {error.step} como variáveis para os passos seguintes. A saída skipped é usada quando um passo não tinha nada a fazer, e out é então a saída normal.

Em forEach, a saída each inicia, por item, uma execução própria para os passos seguintes, e a saída done é o caminho normal de continuação do próprio fluxo.

Uma saída pode levar a vários passos. A execução continua por si própria com a primeira linha e inicia, para cada outra linha, uma execução própria com os mesmos dados, que corre em paralelo (como a saída each de forEach). As linhas que formam um ciclo são rejeitadas no editor. Um fluxo tem exatamente um trigger.

Definições por passo

Os campos em config são os campos do editor. Os campos de texto aceitam variáveis entre chavetas.

PassoCampos em config
triggersource (event, webhook, invoiceOverdue, dateReached, daily ou cron), webhookVersion (em webhook: texto, aumente-o para substituir o endereço), eventKey, date (em dateReached: um caminho record.veld para uma coluna DateTime de um modelo que um evento envia por completo, como reservation.checkIn ou contact.birthday, ou para uma chave de data declarada numa coluna JSON, como document.userMetadata.insuranceExpiryDate; nomes antigos como reservationCheckIn continuam a funcionar), dateOffset ({ "amount", "unit" }), dateDirection (before ou after), dateTime (exact: a hora na data, ou fixed: o dia do calendário da data no fuso horário da organização, com dateHour e dateMinute, texto como "9" e "0"; o desvio conta no relógio, ou seja, também através da mudança de hora de verão e inverno), repeatYearly (booleano: só contam o dia e o mês, todos os anos), hour e minute (texto, por exemplo "8" e "0", minuto de 0 a 59), cron (cinco campos; o dia da semana pode ser 1#2 ou 1L, um sexto campo W2:2026-10-05 repete de duas em duas semanas), conditions, oncePerRecord (booleano)
conditionconditions
switchfield (um caminho de variável sem chavetas), cases: uma lista de { "id", "key", "value" } com key como nome do ramo e value como valor a que o campo tem de ser igual. No máximo 8 ramos
delaymode (duration ou untilDate), duration e offset como { "amount", "unit" } com unit igual a seconds, minutes, hours, days ou weeks, dateField (caminho de variável), direction (before ou after)
taskCreatetitle, description, assigneeIds, labelIds, assignActor, priority (LOW, MEDIUM, HIGH ou URGENT), viewId, laneId, subtasks (uma por linha), dueIn ({ "amount", "unit" }), linkRecords
taskSetStatustaskId, status (PENDING, IN_PROGRESS, WAITING ou COMPLETED)
taskFindtitle (título exato), linkedToRecords, onlyOpen, onlyTopLevel (booleanos)
documentFindcustomerId (modelo), documentType (INSURANCE_POLICY, INSURANCE_PAYMENT_PROOF, IDENTITY_CARD, SEPA_MANDATE, OTHER ou vazio), onlyActive, onlyValid (booleanos). Resultado em foundDocument
documentUpdatedocumentId (modelo), documentType (vazio mantém o tipo), status (ACTIVE, ARCHIVED ou vazio)
taskSetPrioritytaskId, mode (raise, lower ou set), priority (em set), maxPriority (em raise)
taskUpdatetaskId, title, assigneeIds, assignActor, assigneeMode (add ou replace), labelIds, dueIn ({ "amount", "unit" } com unit igual a minutes, hours, days ou weeks)
invoiceReminderSend, invoiceSend, invoiceBookinvoiceId
invoicePrintinvoiceId, printer (a4, pos ou tablet)
paymentLinkCreateinvoiceId, method (any, BANCONTACT, IDEAL, CREDITCARD ou PAYCONIQ)
mandateRequestcustomerId, mode (request ou reminder)
mandateCollectinvoiceId, delayDays (texto, predefinição "0", no máximo 7)
consumptionInvoicecustomerId, sendEmail, sendSms
occupationExtendInvoiceoccupationId, includeConsumption
customerMessageSendcustomerId, subject, body, sendEmail, sendSms, sendWhatsApp
staffNotifyuserIds, notifyActor, title, body, sendPush, sendEmail
commentCreatecontent, target (event ou task), taskId (em task)
inboxReplythreadId, body, keepAssistant
inboxTagthreadId, tagIds, archive
customerUpdatecustomerId, status (keep, DEFAULT, PREFERRED, VIP, WARNING ou BLACKLISTED), notes
reservationSetStatusreservationId, action (checkIn, checkOut ou cancel)
accessMethodCreatecustomerId, type (QR_CODE, LPR, PIN_CODE ou NFC), value, periodFrom, periodTo (variáveis com uma data, vazio é sem limite)
accessMethodUpdatescope (one ou customer), accessMethodId (em one), customerId (em customer), status (keep, ACTIVE, SOFT_BLOCKED, BLOCKED ou INACTIVE), periodTo
accessMethodSendQraccessMethodId, sendEmail, sendSms, sendWhatsApp, print (none, label ou thermal)
accessPointControlaccessPointId, action (open ou close)
meterSwitchtarget (terrain ou meter), terrainId (em terrain), meterId (em meter), state (on ou off)
nfcTagUpdatecustomerId, action (block, unblock, topUp ou lowBalance), amount (em topUp, em euros por etiqueta)
deviceCommanddeviceId, command (wake, sleep, reload, identify, testSound ou playSound), url (em playSound: o caminho de um som carregado, tal como o editor o preenche, ou uma ligação https para um ficheiro mp3, wav ou m4a)
deviceDisplaykind (pdf ou image), url (ligação https). Aparece em cada tablet definido como ecrã de apresentação, como um PDF de fatura
controllerRelaytarget (controller ou event: o controlador do evento controller:input:changed que iniciou o fluxo), controllerId (em controller), relay (texto "1" a "6"), action (pulse, on ou off), durationSeconds (em pulse, texto, 0.001 a 3600 com decimais como "0.5"; o relé volta a desligar-se sozinho)
controllerCommandtarget e controllerId como em controllerRelay, command (reboot, rebootExtension, otaUpdate, forceOtaUpdate, extensionOtaUpdate ou refreshSettings)
deviceSlideshowscope (displays ou device), mode (screensaver ou background), source (feed ou urls). Em feed: itemsPath, imageField, campos opcionais de filtro e ordenação
openingHours, waitUntilOpen, waitUntilClosedSem campos
throttlewindow ({ "amount", "unit" } com unit igual a minutes, hours, days ou weeks), key (vazio é por registo que iniciou o fluxo)
recordLookupmodel (Customer, Reservation, Occupation, Invoice, Payment, Terrain, Task, Document, AccessMethod, NfcTag, Meter, InboxThread ou InboxMessage), recordId. O resultado fica em found mais o modelo, como foundCustomer
forEachsource (customerAccessMethods, customerNfcTags, customerOpenInvoices, customerUpcomingReservations, customerOccupations, customerDocuments (apenas ACTIVE) ou terrainMeters), parentId (id do cliente ou do terreno). No máximo 100 itens, o item fica em item
waitUntilconditions, interval e timeout ({ "amount", "unit" } com unit igual a minutes, hours, days ou weeks; o intervalo é de pelo menos 5 minutos)
waitForEventeventKey, sameRecord (booleano), timeout ({ "amount", "unit" })
approvaltitle, description, assigneeIds, timeout ({ "amount", "unit" }). A tarefa fica em approvalTask.id
Cada ação, exceto webhookSend e httpRequestcontinueOnError (booleano)
webhookSendwebhookId, event, payload (JSON como texto)
httpRequesttarget (tillor ou custom), method, path (em tillor), url (em custom), headers (lista de { "id", "key", "value" }), body (JSON como texto)

conditions tem a forma { "match": "all" ou "any", "rules": [...] }. Cada regra é { "id", "field", "operator", "value", "values" }. operator é is, isNot, contains, greaterThan, lessThan, isOneOf, isEmpty ou isNotEmpty. values só se usa em isOneOf. Uma lista vazia de regras deixa passar tudo.

Iniciar uma automatização com um webhook

Uma automatização com o trigger webhook arranca com um POST para o seu próprio endereço:

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"}'
  • O endereço completo está no editor, no trigger, ou através de GET /automations/{id}/webhook-url (com automations:read). O token é o segredo; não é necessário um cabeçalho para autenticação
  • O corpo JSON passa a ser a variável body, a query string query e o momento receivedAt
  • Responde 200 com { "accepted": true } assim que a execução foi iniciada. Um endereço errado, substituído ou desativado devolve 404, um corpo acima de 100 KB devolve 400
  • Muitas chamadas seguidas não são rejeitadas: cada chamada válida inicia uma execução. Use Ignorar repetições no trigger se a mesma chamada puder chegar duas vezes, veja Ignorar repetições

Uma automatização não pode chamar o seu próprio webhook através de um Pedido à API à API do Tillor.

Escolher uma decisão através da API

A tarefa de um passo Pedir uma decisão tem uma ação por opção que definiu no passo. Obtenha a tarefa para ver as actions com o seu id e escolha uma com POST /tasks/{id}/actions/{actionId}/choose. Se a opção pedir uma nota, envie-a como { "note": "..." }. A escolha é definitiva: conclui a tarefa e a automatização continua pela saída dessa opção. Os colegas atribuídos (também através de um grupo) e os administradores podem escolher. Veja o OpenAPI para os detalhes.

Ler mais

  • Webhooks para a assinatura, as repetições e a lista de eventos
  • HTTP API para a autenticação e o contexto da organização
  • Variáveis e modelos para a explicação para utilizadores
Esta página foi útil?

Nesta página