Automatyzacje
Co Twój własny system otrzymuje z automatyzacji, żądanie API jako użytkownik Przepływ pracy i budowa przepływu
Ostatnio zaktualizowano
Automatyzacje pozwalają Tillor samemu wykonywać działania, na przykład tworzyć zadania lub wywoływać Twój system. Opis dla użytkowników znajdziesz w Automatyzacje. Ta strona opisuje to, co widzi integrator: wiadomość z kroku Wyślij webhook, Żądanie API na własny URL lub do API Tillor oraz sposób zbudowania przepływu, gdy zarządzasz nim przez API.
Wysyłanie webhooka
Krok Wyślij webhook dostarcza własną wiadomość do jednego z webhooków organizacji. To to samo dostarczanie co przy zwykłych zdarzeniach webhooka, z tym samym podpisem.
Wiadomość
Krok wysyła POST z Content-Type: application/json i tymi nagłówkami:
| Header | Inhoud |
|---|---|
X-Webhook-Event-ID | Unikalny identyfikator tego dostarczenia. Przy kolejnych próbach wartość pozostaje taka sama, więc możesz po niej usuwać duplikaty |
X-Webhook-Signature | sha256=<hex>, HMAC-SHA256 treści z signing secret webhooka |
Treść ma tę samą kopertę co payload webhooka:
{
"event": "automation.invoice_unpaid",
"data": {
"invoice": "2026-0042",
"amountOutstanding": 125.5
},
"timestamp": 1735689600000,
"traceId": "0b0f7c0e-5d3c-4c1e-9b8a-7f1e2a3b4c5d",
"triggeredBy": null
}| Veld | Beschrijving |
|---|---|
event | Nazwa zdarzenia, którą wpisano w kroku. Dozwolony jest dowolny tekst, nazwa nie musi być na liście kluczy zdarzeń |
data | Ładunek z kroku, po uzupełnieniu zmiennych, jako JSON |
timestamp | Czas unixowy dostarczenia w milisekundach |
traceId | Losowy UUID dla każdego dostarczenia. W odróżnieniu od zdarzeń z systemu nie jest to identyfikator śladu działania Tillor |
triggeredBy | Zawsze null |
Nie ma spanId. Webhook nie musi być zapisany na klucz zdarzenia: wiadomość z automatyzacji jest zawsze dostarczana na wybrany endpoint, dopóki on istnieje i jest włączony.
Jak sprawdzić podpis, opisano w Weryfikacja podpisu.
Próby i wynik
Tillor wykonuje w ramach kroku do 5 prób, z oczekiwaniem 1, 2, 4 i 8 sekund między nimi. Próba jest udana przy statusie 2xx. Także zablokowany cel, na przykład adres wewnętrzny, liczy się jako nieudana próba.
- Jeśli któraś próba się powiedzie, przepływ kontynuuje wyjściem Powodzenie
- Jeśli wszystkie pięć się nie powiedzie, przepływ kontynuuje przez Niepowodzenie. Wiadomość jest potem jeszcze ponawiana w tle według harmonogramu z Zachowanie dostarczania i ponowienia. Jeśli taka późniejsza próba się powiedzie, nie wróci to już do wykonania, bo ono poszło już dalej
Jeśli webhook już nie istnieje lub jest wyłączony, krok nie przechodzi przez Niepowodzenie. Wykonanie kończy się wtedy ze statusem Niepowodzenie.
Żądanie API na własny URL
Przy Żądanie API i Wyślij do ustawionym na Własny URL automatyzacja wysyła żądanie HTTP na Twój serwer.
| Onderdeel | Gedrag |
|---|---|
| Metoda | GET, POST, PUT, PATCH lub DELETE |
| URL | Musi zaczynać się od https://. Zmienne są wstawiane w postaci zakodowanej |
| Treść | JSON. Przy GET i DELETE nie jest wysyłana. Z treścią Tillor ustawia Content-Type: application/json |
| Nagłówki | Dowolne. Wartości mogą zawierać zmienne. Host, Content-Length, Transfer-Encoding i Connection są ignorowane |
| Cel | Adresy prywatne i wewnętrzne są odrzucane, także gdy wskazuje na nie zwykła nazwa domeny |
| Przekierowania | Nie są śledzone. Odpowiedź 3xx liczy się jako nieudana |
| Limit czasu | 15 sekund |
Brak podpisu
W odróżnieniu od Wyślij webhook Tillor nie podpisuje tego żądania. Jeśli chcesz sprawdzać, że żądanie pochodzi z Twojej automatyzacji, umieść sekret w nagłówku i sprawdzaj go po swojej stronie. Nagłówki są zapisywane w postaci zaszyfrowanej, więc klucz lub token w nich jest bezpieczny.
Odpowiedź ze statusem 2xx kontynuuje przez Powodzenie, każdy inny status przez Niepowodzenie. Jeśli serwer jest nieosiągalny albo przekroczy limit czasu, wykonanie kończy się ze statusem Niepowodzenie.
Żądanie API do API Tillor
Przy Wyślij do ustawionym na Tillor API automatyzacja wywołuje API własnej organizacji. Podajesz tylko ścieżkę, na przykład /tasks, a Tillor umieszcza ją po /api/orgs/{orgId}. Dokumentacja API jest w OpenAPI.
- Tożsamość: żądanie jest wykonywane jako użytkownik Przepływ pracy organizacji. Ma on wszystkie uprawnienia w tej organizacji i nigdzie indziej. Zmiany są więc zapisane na nazwę Przepływ pracy
- Klucz niepotrzebny: Tillor sam wykonuje wywołanie, bez klucza API i bez przechodzenia przez internet
- Ścieżka: musi zaczynać się od jednego
/.//,..i\są niedozwolone. Dozwolony jest query string, na przykład/tasks?terrainId=…&limit=1. Zmienne w ścieżce są wstawiane w postaci zakodowanej - Zablokowane: ścieżki
/automationsi/automation-runssą odrzucane, także z query stringiem, wielkimi literami, końcowym/lub kodowaniem procentowym. Automatyzacja nie może zarządzać automatyzacjami - Treść: JSON, dla
POST,PUTiPATCH. PrzyGETiDELETEnie jest wysyłana - Menu wyboru: w edytorze jest Wybierz punkt końcowy API z operacjami ze specyfikacji OpenAPI. Operacji wewnętrznych tam nie ma. Gdy wybierzesz jedną, Tillor uzupełnia metodę, ścieżkę i przykładową treść
- Niepowodzenie: odpowiedź 2xx kontynuuje przez Powodzenie. Status błędu, także 404 dla nieistniejącej ścieżki, idzie przez Niepowodzenie
Odpowiedź w kolejnych krokach
Po żądaniu dostępne są te zmienne:
| Variabele | Inhoud |
|---|---|
{response.status} | Kod statusu HTTP |
{response.body} | Pierwsze 4000 znaków odpowiedzi jako tekst |
{response.data} | Odpowiedź jako JSON. null, jeśli to nie jest JSON albo jest dłuższa niż 100 000 znaków. Listy adresujesz indeksem, na przykład {response.data.items.0.id} |
Drugie żądanie API w tym samym przepływie zastępuje response. Zmienne działają tak jak w Zmienne i szablony.
Budowa przepływu
Automatyzacje możesz też tworzyć i zmieniać przez API. Operacje są w OpenAPI pod tagiem automations. Odczyt wymaga uprawnienia automations:read, tworzenie i zmiana automations:write (albo wszystkich uprawnień). Sam użytkownik Przepływ pracy nigdy nie może ich wywołać. Wygodniej może być zbudować przepływ w edytorze i odczytać go jako przykład.
Nowa automatyzacja jest zawsze wyłączona. Włączenie przez enabled nie uda się, dopóki przepływ ma otwarte problemy, a włączonego przepływu nie można zapisać z problemami.
definition składa się z kroków (nodes), linii (edges) i opcjonalnie uwag (notes). Maksymalnie 100 kroków, 200 linii i 50 uwag.
{
"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
}
]
}Uwaga (notes) to wyjaśnienie na kanwie. Nigdy nie jest wykonywana i nie ma linii. text ma maksymalnie 2000 znaków, width i height są w pikselach.
Linia ma sourceHandle: wyjście kroku, z którego wychodzi.
Stap (type) | Uitgangen (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, controllerCommand | out |
customerMessageSend, reservationSetStatus, invoiceBook, paymentLinkCreate, mandateRequest, mandateCollect, consumptionInvoice | out, skipped |
condition | yes, no |
switch | id każdej gałęzi, plus default |
openingHours | open, closed |
throttle | pass, blocked |
taskFind, documentFind, recordLookup | found, notFound |
forEach | each, done |
waitUntil | met, timeout |
waitForEvent | received, timeout |
approval | approved, rejected, timeout |
webhookSend, httpRequest | success, failed |
Każda akcja oprócz webhookSend i httpRequest dostaje dodatkowe wyjście error, gdy continueOnError w config jest ustawione na true. Bez tego ustawienia nieudana akcja zatrzymuje wykonanie. Z tym ustawieniem przepływ kontynuuje przez error, ze zmiennymi {error.message} i {error.step} dla kolejnych kroków. Wyjście skipped jest używane, gdy krok nie miał nic do zrobienia, a out jest wtedy zwykłym wyjściem.
Przy forEach wyjście each uruchamia dla każdego elementu osobne wykonanie dla kolejnych kroków, a wyjście done jest zwykłą dalszą drogą samego przepływu.
Wyjście może prowadzić do wielu kroków. Wykonanie samo idzie dalej pierwszą linią i dla każdej innej linii uruchamia osobne wykonanie z tymi samymi danymi, które działa równolegle (tak jak wyjście each w forEach). Linie tworzące pętlę są odrzucane w edytorze. Przepływ ma dokładnie jeden trigger.
Ustawienia kroków
Pola w config to pola z edytora. Pola tekstowe przyjmują zmienne w nawiasach klamrowych.
| Stap | Velden in config |
|---|---|
trigger | source (event, webhook, invoiceOverdue, dateReached, daily lub cron), webhookVersion (przy webhook: tekst, zwiększ, aby zastąpić adres), eventKey, date (przy dateReached: ścieżka record.veld do kolumny DateTime modelu, który zdarzenie przesyła w całości, takiego jak reservation.checkIn lub contact.birthday, albo do zadeklarowanego klucza daty w kolumnie JSON, takiego jak document.userMetadata.insuranceExpiryDate; stare nazwy, takie jak reservationCheckIn, nadal działają), dateOffset ({ "amount", "unit" }), dateDirection (before lub after), dateTime (exact: godzina w dacie, albo fixed: dzień kalendarzowy daty w strefie czasowej organizacji, o dateHour i dateMinute, tekst taki jak "9" i "0"; przesunięcie liczy się na zegarze, a więc także przez zmianę czasu letniego i zimowego), repeatYearly (boolean: liczy się tylko dzień i miesiąc, co roku), hour i minute (tekst, na przykład "8" i "0", minuta od 0 do 59), cron (pięć pól; dzień tygodnia może być 1#2 lub 1L, szóste pole W2:2026-10-05 powtarza co dwa tygodnie), conditions, oncePerRecord (boolean) |
condition | conditions |
switch | field (ścieżka zmiennej bez nawiasów klamrowych), cases: lista { "id", "key", "value" }, gdzie key to nazwa gałęzi, a value to wartość, której pole musi być równe. Maksymalnie 8 gałęzi |
delay | mode (duration lub untilDate), duration i offset jako { "amount", "unit" }, gdzie unit to seconds, minutes, hours, days lub weeks, dateField (ścieżka zmiennej), direction (before lub after) |
taskCreate | title, description, assigneeIds, labelIds, assignActor, priority (LOW, MEDIUM, HIGH lub URGENT), viewId, laneId, subtasks (jedno na wiersz), dueIn ({ "amount", "unit" }), linkRecords |
taskSetStatus | taskId, status (PENDING, IN_PROGRESS, WAITING lub COMPLETED) |
taskFind | title (dokładny tytuł), linkedToRecords, onlyOpen, onlyTopLevel (boolean) |
documentFind | customerId (szablon), documentType (INSURANCE_POLICY, INSURANCE_PAYMENT_PROOF, IDENTITY_CARD, SEPA_MANDATE, OTHER lub puste), onlyActive, onlyValid (boolean). Wynik pod foundDocument |
documentUpdate | documentId (szablon), documentType (puste zachowuje typ), status (ACTIVE, ARCHIVED lub puste) |
taskSetPriority | taskId, mode (raise, lower lub set), priority (przy set), maxPriority (przy raise) |
taskUpdate | taskId, title, assigneeIds, assignActor, assigneeMode (add lub replace), labelIds, dueIn ({ "amount", "unit" }, gdzie unit to minutes, hours, days lub weeks) |
invoiceReminderSend, invoiceSend, invoiceBook | invoiceId |
invoicePrint | invoiceId, printer (a4, pos lub tablet) |
paymentLinkCreate | invoiceId, method (any, BANCONTACT, IDEAL, CREDITCARD lub PAYCONIQ) |
mandateRequest | customerId, mode (request lub reminder) |
mandateCollect | invoiceId, delayDays (tekst, domyślnie "0", najwyżej 7) |
consumptionInvoice | customerId, sendEmail, sendSms |
occupationExtendInvoice | occupationId, includeConsumption |
customerMessageSend | customerId, subject, body, sendEmail, sendSms, sendWhatsApp |
staffNotify | userIds, notifyActor, title, body, sendPush, sendEmail |
commentCreate | content, target (event lub task), taskId (przy task) |
inboxReply | threadId, body, keepAssistant |
inboxTag | threadId, tagIds, archive |
customerUpdate | customerId, status (keep, DEFAULT, PREFERRED, VIP, WARNING lub BLACKLISTED), notes |
reservationSetStatus | reservationId, action (checkIn, checkOut lub cancel) |
accessMethodCreate | customerId, type (QR_CODE, LPR, PIN_CODE lub NFC), value, periodFrom, periodTo (zmienne z datą, puste oznacza brak limitu) |
accessMethodUpdate | scope (one lub customer), accessMethodId (przy one), customerId (przy customer), status (keep, ACTIVE, SOFT_BLOCKED, BLOCKED lub INACTIVE), periodTo |
accessMethodSendQr | accessMethodId, sendEmail, sendSms, sendWhatsApp, print (none, label lub thermal) |
accessPointControl | accessPointId, action (open lub close) |
meterSwitch | target (terrain lub meter), terrainId (przy terrain), meterId (przy meter), state (on lub off) |
nfcTagUpdate | customerId, action (block, unblock, topUp lub lowBalance), amount (przy topUp, w euro na tag) |
deviceCommand | deviceId, command (wake, sleep, reload, identify, testSound lub playSound), url (przy playSound: ścieżka przesłanego dźwięku, tak jak wstawia ją edytor, albo link https do pliku mp3, wav lub m4a) |
deviceDisplay | kind (pdf lub image), url (link https). Pojawia się na każdym tablecie ustawionym jako wyświetlacz, na przykład jako pdf faktury |
controllerRelay | target (controller lub event: kontroler ze zdarzenia controller:input:changed, które uruchomiło przepływ), controllerId (przy controller), relay (tekst od "1" do "6"), action (pulse, on lub off), durationSeconds (przy pulse, tekst, od 0.001 do 3600 z ułamkami dziesiętnymi, takimi jak "0.5"; przekaźnik sam wraca do stanu spoczynku) |
controllerCommand | target i controllerId jak przy controllerRelay, command (reboot, rebootExtension, otaUpdate, forceOtaUpdate, extensionOtaUpdate lub refreshSettings) |
deviceSlideshow | scope (displays lub device), mode (screensaver lub background), source (feed lub urls). Przy feed: itemsPath, imageField, opcjonalnie pola filtrowania i sortowania |
openingHours, waitUntilOpen, waitUntilClosed | Brak pól |
throttle | window ({ "amount", "unit" }, gdzie unit to minutes, hours, days lub weeks), key (puste oznacza na rekord, który uruchomił przepływ) |
recordLookup | model (Customer, Reservation, Occupation, Invoice, Payment, Terrain, Task, Document, AccessMethod, NfcTag, Meter, InboxThread lub InboxMessage), recordId. Wynik jest pod found plus model, na przykład foundCustomer |
forEach | source (customerAccessMethods, customerNfcTags, customerOpenInvoices, customerUpcomingReservations, customerOccupations, customerDocuments (tylko ACTIVE) lub terrainMeters), parentId (identyfikator klienta lub terenu). Najwyżej 100 elementów, element jest pod item |
waitUntil | conditions, interval i timeout ({ "amount", "unit" }, gdzie unit to minutes, hours, days lub weeks; interwał to co najmniej 5 minut) |
waitForEvent | eventKey, sameRecord (boolean), timeout ({ "amount", "unit" }) |
approval | title, description, assigneeIds, timeout ({ "amount", "unit" }). Zadanie jest pod approvalTask.id |
Każda akcja oprócz webhookSend i httpRequest | continueOnError (boolean) |
webhookSend | webhookId, event, payload (JSON jako tekst) |
httpRequest | target (tillor lub custom), method, path (przy tillor), url (przy custom), headers (lista { "id", "key", "value" }), body (JSON jako tekst) |
conditions ma postać { "match": "all" lub "any", "rules": [...] }. Każda reguła to { "id", "field", "operator", "value", "values" }. operator to is, isNot, contains, greaterThan, lessThan, isOneOf, isEmpty lub isNotEmpty. values używasz tylko przy isOneOf. Pusta lista reguł przepuszcza wszystko.
Uruchamianie automatyzacji webhookiem
Automatyzacja z triggerem webhook uruchamia się po POST na jej własny adres:
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"}'- Pełny adres jest w edytorze przy triggerze albo przez
GET /automations/{id}/webhook-url(zautomations:read). Token jest sekretem; nagłówek do uwierzytelniania nie jest potrzebny - Treść JSON staje się zmienną
body, query string zmiennąquery, a moment odebrania zmiennąreceivedAt - Odpowiedź
200z{ "accepted": true }, gdy tylko wykonanie zostanie uruchomione. Błędny, zastąpiony lub wyłączony adres zwraca404, treść powyżej 100 KB zwraca400 - Wiele wywołań w krótkim czasie nie jest odrzucanych: każde ważne wywołanie uruchamia wykonanie. Użyj Ignoruj powtórzenia przy triggerze, jeśli to samo wywołanie może przyjść dwa razy, zobacz Ignorowanie powtórzeń
Automatyzacja nie może wywołać własnego webhooka przez Żądanie API do API Tillor.
Wybór decyzji przez API
Zadanie kroku Poproś o decyzję ma jedną akcję na każdą opcję ustawioną w kroku. Pobierz zadanie, aby zobaczyć actions z ich id, i wybierz jedną przez POST /tasks/{id}/actions/{actionId}/choose. Jeśli opcja wymaga notatki, wyślij ją jako { "note": "..." }. Wybór jest ostateczny: kończy zadanie i prowadzi automatyzację dalej wyjściem tej opcji. Wybierać mogą przypisani współpracownicy (także przez grupę) i administratorzy. Szczegóły w OpenAPI.
Więcej do przeczytania
- Webhooki o podpisie, ponowieniach i liście zdarzeń
- HTTP API o uwierzytelnianiu i kontekście organizacji
- Zmienne i szablony jako opis dla użytkowników