Automatisations
Ce que reçoit votre système depuis une automatisation, la requête API en tant qu'utilisateur Workflow et la structure d'un flux
Dernière mise à jour le
Les automatisations permettent à Tillor d'exécuter lui-même des actions, comme créer des tâches ou appeler votre système. Le mode d'emploi pour les utilisateurs se trouve dans Automatisations. Cette page décrit ce que voit un intégrateur : le message de l'étape Envoyer un webhook, la Requête API vers une URL personnalisée ou vers l'API Tillor, et la structure d'un flux lorsque vous le gérez via l'API.
Envoyer un webhook
L'étape Envoyer un webhook livre un message personnalisé à l'un des webhooks de l'organisation. C'est la même livraison que pour les événements de webhook ordinaires, avec la même signature.
Le message
L'étape effectue un POST avec Content-Type: application/json et ces en-têtes :
| En-tête | Contenu |
|---|---|
X-Webhook-Event-ID | Un identifiant unique pour cette livraison. En cas de nouvelles tentatives, la valeur reste identique, vous pouvez donc dédoublonner dessus |
X-Webhook-Signature | sha256=<hex>, le HMAC-SHA256 du corps avec le secret de signature du webhook |
Le corps a la même enveloppe que la charge utile d'un webhook :
{
"event": "automation.invoice_unpaid",
"data": {
"invoice": "2026-0042",
"amountOutstanding": 125.5
},
"timestamp": 1735689600000,
"traceId": "0b0f7c0e-5d3c-4c1e-9b8a-7f1e2a3b4c5d",
"triggeredBy": null
}| Champ | Description |
|---|---|
event | Le Nom de l'événement que vous avez saisi dans l'étape. N'importe quel texte est autorisé, le nom n'a pas besoin de figurer dans la liste des clés d'événement |
data | La Charge utile de l'étape, une fois les variables remplacées, au format JSON |
timestamp | Heure Unix en millisecondes de la livraison |
traceId | Un UUID aléatoire par livraison. Contrairement aux événements du système, ce n'est pas l'identifiant de trace d'une action Tillor |
triggeredBy | Toujours null |
Il n'y a pas de spanId. Le webhook n'a pas besoin d'être abonné à une clé d'événement : un message issu d'une automatisation est toujours livré au endpoint choisi, tant qu'il existe et qu'il est activé.
La vérification de la signature est décrite dans Vérifier la signature.
Tentatives et résultat
Tillor effectue jusqu'à 5 tentatives dans l'étape, avec 1, 2, 4 et 8 secondes d'attente entre elles. Une tentative est réussie avec un statut 2xx. Une cible bloquée, par exemple une adresse interne, compte aussi comme tentative échouée.
- Si l'une des tentatives réussit, le flux continue par la sortie Réussi
- Si les cinq échouent, le flux continue par Échec. Le message est ensuite encore réessayé en arrière-plan selon le calendrier décrit dans Comportement de livraison et nouvelles tentatives. Si une tentative ultérieure réussit, cela ne se reflète plus dans l'exécution, car celle-ci a déjà continué
Si le webhook n'existe plus ou est désactivé, l'étape ne passe pas par Échec. L'exécution s'arrête alors avec le statut Échec.
Requête API vers une URL personnalisée
Avec Requête API et Envoyer à sur URL personnalisée, une automatisation envoie une requête HTTP vers votre serveur.
| Élément | Comportement |
|---|---|
| Méthode | GET, POST, PUT, PATCH ou DELETE |
| URL | Doit commencer par https://. Les variables sont insérées encodées |
| Corps | JSON. Non envoyé pour GET et DELETE. Avec un corps, Tillor définit Content-Type: application/json |
| En-têtes | Libres. Les valeurs peuvent contenir des variables. Host, Content-Length, Transfer-Encoding et Connection sont ignorés |
| Cible | Les adresses privées et internes sont refusées, même si un nom de domaine ordinaire y renvoie |
| Redirections | Non suivies. Une réponse 3xx compte comme un échec |
| Délai d'expiration | 15 secondes |
Pas de signature
Contrairement à Envoyer un webhook, Tillor ne signe pas cette requête. Si vous voulez vérifier qu'une requête provient de votre automatisation, placez un secret dans un en-tête et contrôlez-le de votre côté. Les en-têtes sont stockés chiffrés, une clé ou un jeton qui s'y trouve est donc en sécurité.
Une réponse avec un statut 2xx continue par Réussi, tout autre statut par Échec. Si le serveur est injoignable ou dépasse le délai d'expiration, l'exécution s'arrête avec le statut Échec.
Requête API vers l'API Tillor
Avec Envoyer à sur Tillor API, l'automatisation appelle l'API de sa propre organisation. Vous indiquez seulement un chemin, par exemple /tasks, et Tillor le place derrière /api/orgs/{orgId}. Votre référence d'API se trouve sur OpenAPI.
- Identité : la requête est exécutée en tant qu'utilisateur Workflow de l'organisation. Celui-ci a toutes les permissions au sein de cette organisation et nulle part ailleurs. Les modifications sont donc enregistrées au nom de Flux de travail
- Pas de clé nécessaire : Tillor effectue l'appel lui-même, sans clé API et sans passer par Internet
- Chemin : doit commencer par un seul
/.//,..et\ne sont pas autorisés. Une chaîne de requête est permise, par exemple/tasks?terrainId=…&limit=1. Les variables dans le chemin sont insérées encodées - Bloqué : les chemins
/automationset/automation-runssont refusés, même avec une chaîne de requête, des majuscules, un/final ou un codage en pourcentage. Une automatisation ne peut pas gérer des automatisations - Corps : JSON, pour
POST,PUTetPATCH. PourGETetDELETE, il n'est pas envoyé - Menu de choix : dans l'éditeur figure Choisissez un endpoint API avec les opérations de la spécification OpenAPI. Les opérations internes n'y figurent pas. Si vous en choisissez une, Tillor remplit la méthode, le chemin et un exemple de corps
- Échec : une réponse 2xx continue par Réussi. Un statut d'erreur, y compris un 404 pour un chemin inexistant, passe par Échec
La réponse dans les étapes suivantes
Après la requête, ces variables sont disponibles :
| Variable | Contenu |
|---|---|
{response.status} | Le code de statut HTTP |
{response.body} | Les 4000 premiers caractères de la réponse sous forme de texte |
{response.data} | La réponse au format JSON. null si ce n'est pas du JSON, ou si elle dépasse 100 000 caractères. Vous adressez les listes par un index, par exemple {response.data.items.0.id} |
Une deuxième requête API dans le même flux remplace response. Les variables fonctionnent comme dans Variables et modèles.
La structure d'un flux
Vous pouvez aussi créer et modifier des automatisations via l'API. Les opérations figurent dans OpenAPI sous le tag automations. La lecture requiert la permission automations:read, la création et la modification automations:write (ou toutes les permissions). L'utilisateur Workflow lui-même ne peut jamais les appeler. Il peut être plus pratique de construire un flux dans l'éditeur et de le lire comme exemple.
Une nouvelle automatisation est toujours désactivée. L'activer via enabled échoue tant que le flux a des problèmes ouverts, et vous ne pouvez pas enregistrer un flux activé qui a des problèmes.
La definition se compose d'étapes (nodes), de liens (edges) et, en option, de remarques (notes). Maximum 100 étapes, 200 liens et 50 remarques.
{
"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
}
]
}Une remarque (notes) est une explication sur le canevas. Elle n'est jamais exécutée et n'a pas de liens. text fait 2000 caractères maximum, width et height sont en pixels.
Un lien a un sourceHandle : la sortie de l'étape dont il part.
Étape (type) | Sorties (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 | L'id de chaque branche, 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 |
Toute action sauf webhookSend et httpRequest reçoit une sortie supplémentaire error dès que continueOnError est à true dans la config. Sans ce réglage, une action échouée arrête l'exécution. Avec ce réglage, le flux continue par error, avec {error.message} et {error.step} comme variables pour les étapes suivantes. La sortie skipped est utilisée lorsqu'une étape n'avait rien à faire, et out est alors la sortie ordinaire.
Pour forEach, la sortie each démarre une exécution propre par élément pour les étapes suivantes, et la sortie done est la suite ordinaire du flux lui-même.
Une sortie peut mener à plusieurs étapes. L'exécution continue elle-même avec le premier lien et démarre pour chaque autre lien une exécution propre avec les mêmes données, qui tourne en parallèle (comme la sortie each de forEach). Les liens qui forment une boucle sont refusés dans l'éditeur. Un flux a exactement un trigger.
Réglages par étape
Les champs sous config sont les champs de l'éditeur. Les champs de texte acceptent des variables entre accolades.
| Étape | Champs dans config |
|---|---|
trigger | source (event, webhook, invoiceOverdue, dateReached, daily ou cron), webhookVersion (pour webhook : texte, à incrémenter pour remplacer l'adresse), eventKey, date (pour dateReached : un chemin record.veld vers une colonne DateTime d'un modèle dont un événement envoie l'intégralité, comme reservation.checkIn ou contact.birthday, ou vers une clé de date déclarée dans une colonne JSON, comme document.userMetadata.insuranceExpiryDate ; les anciens noms comme reservationCheckIn continuent de fonctionner), dateOffset ({ "amount", "unit" }), dateDirection (before ou after), dateTime (exact : l'heure dans la date, ou fixed : le jour calendaire de la date dans le fuseau horaire de l'organisation, avec dateHour et dateMinute, du texte comme "9" et "0" ; le décalage compte sur l'horloge, donc à travers l'heure d'été et d'hiver), repeatYearly (booléen : seuls le jour et le mois comptent, chaque année), hour et minute (texte, par exemple "8" et "0", minute de 0 à 59), cron (cinq champs ; le jour de la semaine peut être 1#2 ou 1L, un sixième champ W2:2026-10-05 répète toutes les deux semaines), conditions, oncePerRecord (booléen) |
condition | conditions |
switch | field (un chemin de variable sans accolades), cases : une liste de { "id", "key", "value" } avec key comme nom de la branche et value comme valeur à laquelle le champ doit être égal. 8 branches maximum |
delay | mode (duration ou untilDate), duration et offset sous la forme { "amount", "unit" } avec unit valant seconds, minutes, hours, days ou weeks, dateField (chemin de variable), direction (before ou after) |
taskCreate | title, description, assigneeIds, labelIds, assignActor, priority (LOW, MEDIUM, HIGH ou URGENT), viewId, laneId, subtasks (une par ligne), dueIn ({ "amount", "unit" }), linkRecords |
taskSetStatus | taskId, status (PENDING, IN_PROGRESS, WAITING ou COMPLETED) |
taskFind | title (titre exact), linkedToRecords, onlyOpen, onlyTopLevel (booléens) |
documentFind | customerId (modèle), documentType (INSURANCE_POLICY, INSURANCE_PAYMENT_PROOF, IDENTITY_CARD, SEPA_MANDATE, OTHER ou vide), onlyActive, onlyValid (booléens). Résultat sous foundDocument |
documentUpdate | documentId (modèle), documentType (vide conserve le type), status (ACTIVE, ARCHIVED ou vide) |
taskSetPriority | taskId, mode (raise, lower ou set), priority (pour set), maxPriority (pour raise) |
taskUpdate | taskId, title, assigneeIds, assignActor, assigneeMode (add ou replace), labelIds, dueIn ({ "amount", "unit" } avec unit valant minutes, hours, days ou weeks) |
invoiceReminderSend, invoiceSend, invoiceBook | invoiceId |
invoicePrint | invoiceId, printer (a4, pos ou tablet) |
paymentLinkCreate | invoiceId, method (any, BANCONTACT, IDEAL, CREDITCARD ou PAYCONIQ) |
mandateRequest | customerId, mode (request ou reminder) |
mandateCollect | invoiceId, delayDays (texte, "0" par défaut, 7 au plus) |
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 ou task), taskId (pour task) |
inboxReply | threadId, body, keepAssistant |
inboxTag | threadId, tagIds, archive |
customerUpdate | customerId, status (keep, DEFAULT, PREFERRED, VIP, WARNING ou BLACKLISTED), notes |
reservationSetStatus | reservationId, action (checkIn, checkOut ou cancel) |
accessMethodCreate | customerId, type (QR_CODE, LPR, PIN_CODE ou NFC), value, periodFrom, periodTo (variables contenant une date, vide signifie aucune limite) |
accessMethodUpdate | scope (one ou customer), accessMethodId (pour one), customerId (pour customer), status (keep, ACTIVE, SOFT_BLOCKED, BLOCKED ou INACTIVE), periodTo |
accessMethodSendQr | accessMethodId, sendEmail, sendSms, sendWhatsApp, print (none, label ou thermal) |
accessPointControl | accessPointId, action (open ou close) |
meterSwitch | target (terrain ou meter), terrainId (pour terrain), meterId (pour meter), state (on ou off) |
nfcTagUpdate | customerId, action (block, unblock, topUp ou lowBalance), amount (pour topUp, en euros par badge) |
deviceCommand | deviceId, command (wake, sleep, reload, identify, testSound ou playSound), url (pour playSound : le chemin d'un son téléversé, tel que l'éditeur le remplit, ou un lien https vers un fichier mp3, wav ou m4a) |
deviceDisplay | kind (pdf ou image), url (lien https). Apparaît sur chaque tablette configurée comme écran d'affichage, comme un PDF de facture |
controllerRelay | target (controller ou event : le contrôleur de l'événement controller:input:changed qui a démarré le flux), controllerId (pour controller), relay (texte "1" à "6"), action (pulse, on ou off), durationSeconds (pour pulse, texte, de 0.001 à 3600 avec des décimales comme "0.5" ; le relais retombe de lui-même) |
controllerCommand | target et controllerId comme pour controllerRelay, command (reboot, rebootExtension, otaUpdate, forceOtaUpdate, extensionOtaUpdate ou refreshSettings) |
deviceSlideshow | scope (displays ou device), mode (screensaver ou background), source (feed ou urls). Pour feed : itemsPath, imageField, champs de filtre et de tri facultatifs |
openingHours, waitUntilOpen, waitUntilClosed | Aucun champ |
throttle | window ({ "amount", "unit" } avec unit valant minutes, hours, days ou weeks), key (vide signifie par enregistrement qui a démarré le flux) |
recordLookup | model (Customer, Reservation, Occupation, Invoice, Payment, Terrain, Task, Document, AccessMethod, NfcTag, Meter, InboxThread ou InboxMessage), recordId. Le résultat se trouve sous found plus le modèle, comme foundCustomer |
forEach | source (customerAccessMethods, customerNfcTags, customerOpenInvoices, customerUpcomingReservations, customerOccupations, customerDocuments (uniquement ACTIVE) ou terrainMeters), parentId (identifiant du client ou du terrain). 100 éléments au plus, l'élément se trouve sous item |
waitUntil | conditions, interval et timeout ({ "amount", "unit" } avec unit valant minutes, hours, days ou weeks ; l'intervalle est d'au moins 5 minutes) |
waitForEvent | eventKey, sameRecord (booléen), timeout ({ "amount", "unit" }) |
approval | title, description, assigneeIds, timeout ({ "amount", "unit" }). La tâche se trouve sous approvalTask.id |
Toute action sauf webhookSend et httpRequest | continueOnError (booléen) |
webhookSend | webhookId, event, payload (JSON sous forme de texte) |
httpRequest | target (tillor ou custom), method, path (pour tillor), url (pour custom), headers (liste de { "id", "key", "value" }), body (JSON sous forme de texte) |
conditions a la forme { "match": "all" ou "any", "rules": [...] }. Chaque règle est { "id", "field", "operator", "value", "values" }. operator vaut is, isNot, contains, greaterThan, lessThan, isOneOf, isEmpty ou isNotEmpty. Vous n'utilisez values que pour isOneOf. Une liste de règles vide laisse tout passer.
Démarrer une automatisation avec un webhook
Une automatisation avec le déclencheur webhook démarre à la suite d'un POST vers sa propre adresse :
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"}'- L'adresse complète figure dans l'éditeur, au niveau du déclencheur, ou via
GET /automations/{id}/webhook-url(avecautomations:read). Le jeton est le secret ; un en-tête d'authentification n'est pas nécessaire - Le corps JSON devient la variable
body, la chaîne de requêtequery, et l'heurereceivedAt - Réponse
200avec{ "accepted": true }dès que l'exécution a démarré. Une adresse erronée, remplacée ou désactivée renvoie404, un corps de plus de 100 Ko renvoie400 - De nombreux appels rapprochés ne sont pas refusés : chaque appel valide démarre une exécution. Utilisez Ignorer les répétitions sur le déclencheur si le même appel peut arriver deux fois, voir Ignorer les répétitions
Une automatisation ne peut pas appeler son propre webhook via une Requête API vers l'API Tillor.
Choisir une décision via l'API
La tâche d'une étape Demander une décision a une action par option que vous avez définie dans l'étape. Récupérez la tâche pour voir les actions avec leur id, et choisissez-en une avec POST /tasks/{id}/actions/{actionId}/choose. Si l'option demande une note, envoyez-la avec { "note": "..." }. Le choix est définitif : il clôt la tâche et poursuit l'automatisation par la sortie de cette option. Les collègues assignés (y compris via un groupe) et les administrateurs peuvent choisir. Voir OpenAPI pour les détails.
Pour en savoir plus
- Webhooks pour la signature, les nouvelles tentatives et la liste des événements
- API HTTP pour l'authentification et le contexte d'organisation
- Variables et modèles pour le mode d'emploi utilisateur