Un workflow est un processus automatisé composé d'étapes : un déclencheur démarre une exécution, et les étapes qui le suivent appellent des outils, exécutent des assistants, créent des branches, bouclent, envoient des requêtes HTTP, attendent l'approbation d'une personne et définissent le résultat. L'API des workflows permet à votre application de lister les workflows, de les exécuter avec une progression en direct, de lire les exécutions passées, de décider des approbations, de modifier et publier des workflows, et de démarrer des workflows publiés depuis une URL de webhook publique.
Chaque appel s'exécute au nom de l'utilisateur propriétaire de la clé API, avec les permissions, les organisations et les crédits de cet utilisateur. Les exécutions démarrées via l'API exécutent le brouillon du workflow (la définition actuelle) ; les versions publiées sont exécutées par les plannings, les webhooks et les déclencheurs d'enregistrements booster.
Portées et accès
| Portée | Autorise |
|---|---|
ayeto.workflow |
Lister et lire les workflows, les exécuter (y compris en streaming), annuler des exécutions, lister et lire les exécutions, le catalogue, la validation, la prévisualisation de planning, l'historique des révisions, l'export, les approbations (lister, compter, lire, décider). |
ayeto.workflow.write |
Créer, mettre à jour et supprimer des workflows, supprimer des exécutions, les informations de déploiement (contiennent les secrets des webhooks), publier, activer, régénérer les secrets des webhooks, restaurer une révision, importer, copier, l'assistant builder. |
* |
Tout. |
Les portées ne s'incluent pas l'une l'autre : une clé qui doit à la fois lire et modifier des workflows a besoin
des deux. Une clé sans la portée requise reçoit 401 avec API key is invalid ; voir
authentification.
En plus de la portée, chaque workflow vérifie qui peut faire quoi :
| Qui | Peut |
|---|---|
| Propriétaire (le créateur, ou un membre du groupe propriétaire) | Tout. |
| Utilisateur avec qui il est partagé en écriture | Le lire, le modifier, l'exécuter, le publier, l'exporter, le copier et le supprimer. |
| Utilisateur avec qui il est partagé en lecture | Le lire, le valider, voir ses révisions. L'exécuter, l'exporter ou le copier uniquement si le partage accorde la permission workflow.run, workflow.export ou workflow.copy. |
Un workflow qui appartient à une organisation s'exécute dans cette organisation (ses crédits et son stockage), l'utilisateur doit donc y être membre avec un accès en écriture.
Concepts
Définition
La définition d'un workflow est un graphe orienté acyclique : une liste de nodes et une liste
d'edges.
{
"nodes": [
{
"id": "start",
"type": "trigger.manual",
"name": "Start",
"params": {
"input_schema": {
"type": "object",
"properties": {"customer": {"type": "string"}, "question": {"type": "string"}},
"required": ["question"]
}
},
"position": {"x": 0, "y": 0}
},
{
"id": "answer",
"type": "assistant.run",
"name": "Draft an answer",
"params": {
"assistant_id": "3f6c1a2e-8b4d-4e7a-9c1f-2d5e6a7b8c90",
"prompt": "Answer {{ input.customer }}: {{ input.question }}"
},
"position": {"x": 0, "y": 160}
},
{
"id": "result",
"type": "output",
"name": "Result",
"params": {"value": {"answer": "{{ steps.answer.output.text }}"}},
"position": {"x": 0, "y": 320}
}
],
"edges": [
{"source": "start", "target": "answer", "source_handle": null},
{"source": "answer", "target": "result", "source_handle": null}
]
}
| Champ | Type | Description |
|---|---|---|
nodes[].id |
chaîne | Identifiant du nœud, unique dans le workflow : lettres, chiffres et _, au plus 64 caractères, ne commençant pas par un chiffre. Les étapes suivantes font référence à son résultat par {{ steps.<id>.output }}. |
nodes[].type |
chaîne | Type de nœud, voir types de nœuds. |
nodes[].name |
chaîne | Libellé affiché dans l'éditeur. |
nodes[].params |
objet | Paramètres du type de nœud ; leur schéma JSON se trouve dans le catalogue. |
nodes[].position |
objet | {x, y} sur le canevas de l'éditeur, ou null. Sans effet sur les exécutions. |
edges[].source |
chaîne | Nœud dont part l'arête. |
edges[].target |
chaîne | Nœud dans lequel entre l'arête. |
edges[].source_handle |
chaîne | Sortie du nœud source dont part l'arête : null pour la sortie par défaut, une sortie nommée (true / false d'une condition, un cas d'un switch, item / done d'une boucle, approved / rejected / timeout d'une approbation), ou error pour continuer lorsque l'étape source échoue. |
Une définition comporte au plus 200 nœuds, au moins un déclencheur, aucun cycle et aucune arête entrant dans un déclencheur. Utilisez valider pour la vérifier.
Les paramètres de type chaîne sont des templates (syntaxe Jinja, évalués dans un bac à sable). Ils peuvent lire :
| Variable | Contenu |
|---|---|
input |
L'entrée de l'exécution (la sortie du déclencheur). |
steps.<id>.output |
Résultat d'une étape précédente ; également steps.<id>.success, .status, .text, .error, .file_ids. |
workflow |
{id, name}. |
run |
{id}. |
now |
Heure de début de l'exécution (ISO 8601, UTC). |
loop |
À l'intérieur du corps d'une boucle : item, index, count, parent. |
Un paramètre constitué d'une seule {{ expression }} conserve le type natif de la valeur (un
objet reste un objet) ; une variable non définie est une erreur de l'étape.
Types de nœuds
La liste complète, avec le schéma JSON des paramètres de chaque nœud et les outils qu'une étape tool.call
peut utiliser, est fournie par le catalogue. Vue d'ensemble :
| Type | Catégorie | Ce qu'il fait |
|---|---|---|
trigger.manual |
déclencheur | Démarre une exécution à la demande (application, API). Le paramètre facultatif input_schema décrit l'entrée de l'exécution. |
trigger.schedule |
déclencheur | Démarre le workflow publié selon un planning cron. |
trigger.webhook |
déclencheur | Démarre le workflow publié lorsque son URL de webhook est appelée. |
trigger.booster_record |
déclencheur | Démarre le workflow publié lorsqu'un enregistrement de la base de données d'un panneau Booster est créé, mis à jour ou supprimé. |
tool.call |
action | Appelle un outil d'IA avec les paramètres donnés. |
assistant.run |
action | Exécute une tâche sur un assistant dans une nouvelle conversation. |
http.request |
action | Envoie une requête HTTP à une URL publique. |
notify |
action | Envoie un e-mail à l'utilisateur au nom duquel l'exécution s'effectue. |
file.to_text |
action | Lit des fichiers (documents, images, audio) sous forme de texte. |
human.approval |
logique | Attend qu'une personne approuve ou rejette, éventuellement avec un formulaire. |
condition |
logique | Continue sur true ou false selon une expression. |
switch |
logique | Continue sur l'une de plusieurs sorties nommées, ou sur otherwise. |
ai.condition |
logique | Pose une question oui/non à un modèle de classification ; continue sur true ou false. |
ai.choice |
logique | Demande à un modèle de classification laquelle de plusieurs options convient. |
loop |
logique | Exécute les étapes situées derrière sa sortie item une fois par élément d'une liste, puis continue sur done. |
transform |
logique | Construit une valeur à partir des résultats précédents. |
output |
logique | Définit le résultat de l'exécution. N'a pas d'arêtes sortantes. |
Brouillon et version publiée
La definition enregistrée sur le workflow est le brouillon. Chacune de ses modifications est conservée sous forme de
révision. Les exécutions démarrées via l'API (et depuis l'application) exécutent le brouillon.
Publier copie le brouillon dans une nouvelle version immuable (1, 2,
...) et active le workflow. Tant que le workflow est actif, ses déclencheurs automatiques
(planning, webhook, enregistrement booster) démarrent des exécutions de la version publiée, au nom de l'utilisateur
qui l'a publiée ou activée en dernier (run_as). Modifier le brouillon par la suite ne change pas
ce qu'exécutent les déclencheurs tant que vous ne publiez pas à nouveau.
Statuts d'exécution
Une exécution enregistre l'entrée, l'état de chaque étape et le résultat. Son status :
| Statut | Signification |
|---|---|
queued |
Démarrée par un déclencheur, ou exécution en pause dont l'étape en attente a reçu son résultat ; attend un worker en arrière-plan. |
running |
En cours d'exécution. |
waiting |
En pause : une étape attend quelque chose d'extérieur à l'exécution (l'approbation d'une personne). Les autres branches sont terminées. L'exécution reprend en arrière-plan dès que l'étape reçoit son résultat. |
success |
Terminée. |
failed |
Une étape a échoué sans arête error, une limite a été dépassée, ou l'exécution n'a pas pu démarrer. |
cancelled |
Annulée alors qu'elle était waiting ou queued. |
Les étapes s'exécutent dès que toutes les étapes qui les précèdent sont terminées, de sorte que les branches indépendantes s'exécutent en
parallèle. Une étape dont toutes les arêtes entrantes sont inactives (une branche non empruntée) est skipped.
Une étape en échec qui a une arête error continue par celle-ci ; sans elle, l'exécution échoue (les étapes
déjà en cours se terminent d'abord).
Les exécutions sont supprimées après une période de rétention (90 jours par défaut), avec les conversations et les fichiers créés par leurs étapes. Les exécutions en pause sont conservées jusqu'à leur fin.
Processus d'approbation
Une étape human.approval ouvre une approbation et met l'exécution en pause. Les personnes qui peuvent en décider
sont l'utilisateur au nom duquel l'exécution s'effectue et les membres de l'organisation du workflow désignés dans l'étape ;
ils sont notifiés dans l'application et par e-mail. Une approbation affiche un titre, un message et
éventuellement un formulaire (un schéma JSON plat avec des valeurs préremplies). La décision (approuver avec les
données du formulaire, ou rejeter) devient la sortie de l'étape et l'exécution continue sur approved ou
rejected. Une approbation dont personne ne décide à temps expire : l'exécution continue sur timeout lorsque
cette sortie est connectée, sinon l'étape échoue. Voir approbations.
Fichiers dans l'entrée d'une exécution
Un champ de l'input_schema du déclencheur manuel déclaré comme
{"type": "object", "format": "file"} contient un fichier. Envoyez-le dans l'entrée de l'exécution soit
directement en base64 :
{
"invoice": {
"filename": "invoice-1042.pdf",
"mime_type": "application/pdf",
"data": "data:application/pdf;base64,JVBERi0xLjcKJcfsj6IKNSAwIG9iago8PC9MZW5ndGg..."
}
}
soit par l'id d'un fichier que l'utilisateur possède déjà ("invoice": "7b1e2c3d-..." ou
{"file_id": "7b1e2c3d-..."}). data est du base64 brut ou une data URL ; name peut être utilisé
à la place de filename et content_type à la place de mime_type. La limite de taille des uploads et
le quota de stockage s'appliquent.
Dans l'exécution, la valeur devient les métadonnées de pièce jointe du fichier, qui sont aussi la forme sous laquelle les étapes renvoient des fichiers :
{
"file_id": "7b1e2c3d-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
"filename": "invoice-1042.pdf",
"content_type": "application/pdf",
"file_url": "https://ayeto.ai/api/v1/public/file/read?id=7b1e2c3d-4a5b-4c6d-8e7f-9a0b1c2d3e4f&secret=...",
"size": 48213
}
file_url télécharge le fichier. Les fichiers envoyés en base64 appartiennent à l'exécution et sont supprimés avec
elle ; un fichier désigné par son id reste celui de l'utilisateur et n'est pas supprimé avec l'exécution. La même forme base64 est acceptée dans les champs fichier d'un
formulaire d'approbation et dans le corps des webhooks.
Limites
Les valeurs par défaut ci-dessous peuvent varier selon le déploiement.
| Limite | Valeur par défaut |
|---|---|
| Nœuds par workflow | 200 |
| Entrée d'une exécution | 200 000 caractères de JSON |
| Étapes exécutées par exécution (chaque élément de boucle compte) | 500 |
| Durée d'une exécution (les pauses pour approbation ne comptent pas) | 1 800 secondes |
| Étapes exécutées simultanément dans une exécution | 4 |
| Éléments par boucle | 100 |
| Sortie enregistrée d'une étape | 200 000 caractères de JSON (2 000 dans le corps d'une boucle) |
| Exécutions en file d'attente par workflow | 50 |
| Intervalle de planning le plus court | 5 minutes |
| Délai pour décider d'une approbation | 72 heures par défaut, au plus 720 |
| Rétention des exécutions | 90 jours |
| Révisions conservées par workflow | 100 |
Objet workflow
Le workflow renvoyé par les endpoints de lecture, de création et de mise à jour. Il comporte aussi les
champs communs (id, created, updated, permissions,
...).
| Champ | Type | Description |
|---|---|---|
name |
chaîne | Nom. |
description |
chaîne | Description. |
organization_id |
UUID | Organisation à laquelle appartient le workflow, null pour un workflow personnel. Fixée à la création. |
definition |
objet | La définition du brouillon. |
sharing |
tableau d'objets | Utilisateurs avec qui il est partagé : {user_email, write, scopes}. scopes peut accorder aux partages en lecture {"workflow.run": true, "workflow.export": true, "workflow.copy": true}. |
group_sharing |
tableau d'objets | Groupes avec qui il est partagé : {group_id, write, scopes}. |
last_run |
objet | Dernière exécution terminée ou en pause : {run_id, status, finished_at, credits}, ou null. Lecture seule. |
published_version |
entier | Dernière version publiée, null s'il n'a jamais été publié. Lecture seule. |
published_at |
horodatage | Date de la dernière publication. Lecture seule. |
active |
booléen | Les déclencheurs automatiques de la version publiée sont activés. Lecture seule ; voir activer. |
run_as |
UUID | Utilisateur au nom duquel s'effectuent les exécutions automatiques. Lecture seule. |
Lister et lire les workflows
| Endpoints | POST /api/v3/workflow/find<br>POST /api/v3/workflow/count<br>POST /api/v3/workflow/get?entity_id=<workflow id> |
| Portée | ayeto.workflow |
| Limite de débit | par défaut |
find renvoie les workflows dont l'utilisateur est propriétaire ou qui sont partagés avec lui, sous forme de tableau de
workflows, du plus récent au plus ancien sauf autre tri. count renvoie le
nombre de workflows correspondants sous forme d'entier. Les deux acceptent le
corps de requête habituel (filters, sort_key, sort_order,
limit_from, limit_to) ; envoyez {} pour tout obtenir. Chaque workflow est renvoyé avec sa
définition complète, paginez donc les longues listes.
get renvoie un workflow ; l'id est un paramètre de requête et le corps
est vide.
Filtres utiles : ["organization_id", "==", "<organization id>"],
["organization_id", "==", null] (personnels), ["active", "==", true],
["name", "regex", "invoice"].
curl -X POST "https://ayeto.ai/api/v3/workflow/find" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filters": [["active", "==", true]], "sort_key": "updated.timestamp", "sort_order": 1, "limit_from": 0, "limit_to": 20}'
curl -X POST "https://ayeto.ai/api/v3/workflow/get?entity_id=5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a" \
-H "uni-api-key: $AYETO_API_KEY"
{
"id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
"name": "Customer question",
"description": "Drafts an answer to a customer question",
"organization_id": null,
"definition": {"nodes": ["..."], "edges": ["..."]},
"sharing": [],
"group_sharing": [],
"last_run": {"run_id": "c2a1b0d9-8e7f-4a6b-9c5d-4e3f2a1b0c9d", "status": "success", "finished_at": 1759401234567, "credits": 0.42},
"published_version": 3,
"published_at": 1759300000000,
"active": true,
"run_as": "0f1e2d3c-4b5a-4968-8776-655443322110",
"created": {"timestamp": 1759000000000, "user_id": "0f1e2d3c-4b5a-4968-8776-655443322110"},
"updated": {"timestamp": 1759400000000, "user_id": "0f1e2d3c-4b5a-4968-8776-655443322110"}
}
Un workflow qui n'existe pas ou n'est pas visible pour l'utilisateur renvoie 404.
Créer un workflow
| Endpoint | POST /api/v3/workflow/create |
| Portée | ayeto.workflow.write |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
name |
chaîne | Oui | Nom. |
description |
chaîne | Non | Description. |
organization_id |
UUID | Non | Le créer dans cette organisation ; l'utilisateur doit y avoir un accès en écriture. À omettre pour un workflow personnel. |
definition |
objet | Non | La définition. Par défaut : un seul déclencheur manuel avec l'id start. |
sharing |
tableau d'objets | Non | Partages avec des utilisateurs, voir l'objet workflow. |
group_sharing |
tableau d'objets | Non | Partages avec des groupes. |
Renvoie le workflow créé. La définition est enregistrée telle quelle, même si elle n'est pas valide ; validez-la avant de l'exécuter. La création d'un workflow enregistre aussi sa première révision et crée l'assistant builder de l'utilisateur.
curl -X POST "https://ayeto.ai/api/v3/workflow/create" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Customer question", "description": "Drafts an answer to a customer question"}'
Mettre à jour un workflow
| Endpoint | POST /api/v3/workflow/update |
| Portée | ayeto.workflow.write |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
id |
UUID | Oui | Le workflow. |
name |
chaîne | Non | Nouveau nom. |
description |
chaîne | Non | Nouvelle description. |
definition |
objet | Non | Nouvelle définition du brouillon ; remplace toute la définition. |
sharing |
tableau d'objets | Non | Remplace les partages avec des utilisateurs. |
group_sharing |
tableau d'objets | Non | Remplace les partages avec des groupes. |
Seuls les champs que vous envoyez sont modifiés. L'organisation, l'état de publication et la dernière exécution ne peuvent pas être modifiés ici. Chaque modification de la définition est enregistrée comme révision ; la version publiée reste inchangée jusqu'à ce que vous publiiez à nouveau. Renvoie le workflow mis à jour.
Pour modifier un nœud, lisez le workflow, modifiez sa definition et renvoyez-la. Deux
clients qui mettent à jour le même workflow en même temps écrasent mutuellement leur définition.
Supprimer un workflow
| Endpoint | POST /api/v3/workflow/delete?entity_id=<workflow id> |
| Portée | ayeto.workflow.write |
| Limite de débit | par défaut |
Supprime le workflow avec toutes ses exécutions (et les conversations et fichiers qu'elles ont créés), ses révisions, ses versions publiées, ses déclencheurs et ses assistants builder. Renvoie l'id supprimé sous forme de chaîne JSON.
Catalogue
| Endpoint | POST /api/v3/workflow/catalog |
| Portée | ayeto.workflow |
| Limite de débit | par défaut |
Renvoie les éléments à partir desquels les workflows peuvent être construits : chaque type de nœud avec le schéma JSON de ses
paramètres, et les outils qu'une étape tool.call peut appeler. Pas de corps de requête.
| Champ | Type | Description |
|---|---|---|
node_types[].type |
chaîne | Type de nœud, par exemple http.request. |
node_types[].title |
chaîne | Nom affiché. |
node_types[].description |
chaîne | Ce que fait le nœud et à quoi ressemble sa sortie. |
node_types[].category |
chaîne | trigger, action ou logic. |
node_types[].is_trigger |
booléen | Le nœud démarre des exécutions. |
node_types[].terminal |
booléen | Le nœud termine une branche (pas d'arêtes sortantes). |
node_types[].handles |
tableau de chaînes | Sorties nommées ; vide signifie une seule sortie par défaut. Chaque nœud qui n'est pas un déclencheur a aussi la sortie error. Pour un switch, les sorties sont les noms de ses cas plus otherwise. |
node_types[].params_schema |
objet | Schéma JSON de params. |
tools[].name |
chaîne | Nom de l'outil pour le paramètre tool de tool.call. |
tools[].display_name |
chaîne | Nom affiché. |
tools[].description |
chaîne | Description. |
tools[].category |
chaîne | Catégorie. |
tools[].icon |
chaîne | Nom de l'icône. |
tools[].input_schema |
objet | Schéma JSON des params de l'outil. |
Valider un workflow
| Endpoint | POST /api/v3/workflow/validate |
| Portée | ayeto.workflow |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
workflow_id |
UUID | Oui | Le workflow. |
Valide le brouillon pour l'utilisateur appelant (y compris le fait que l'utilisateur puisse utiliser les assistants et les panneaux Booster auxquels il fait référence).
{
"valid": false,
"issues": [
{"severity": "error", "message": "Node 'answer' has no output 'true' (outputs: default, error)", "node_id": "answer", "edge": {"source": "answer", "target": "result", "source_handle": "true"}},
{"severity": "warning", "message": "Node 'draft' is not reachable from any trigger and never runs", "node_id": "draft", "edge": null}
]
}
valid vaut false lorsqu'il existe au moins un problème de sévérité error ; les erreurs bloquent les exécutions
et la publication, les avertissements non.
Exécuter un workflow
| Endpoint | POST /api/v3/workflow/run |
| Portée | ayeto.workflow |
| Limite de débit | par défaut |
Exécute le brouillon au nom de l'utilisateur appelant et répond lorsque l'exécution est terminée ou en pause.
Requête
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
workflow_id |
UUID | Oui | Le workflow. |
input |
objet | Non | L'entrée de l'exécution. Pour un déclencheur manuel, elle doit correspondre à son input_schema ; les clés listées dans required doivent être présentes. Au plus 200 000 caractères en JSON. |
trigger_node_id |
chaîne | Non | Déclencheur à partir duquel démarrer. Par défaut : le premier trigger.manual, sinon le premier déclencheur de n'importe quel type. |
Démarrer à partir d'un déclencheur de planning, de webhook ou d'enregistrement booster exécute le brouillon manuellement, ce qui est
utile pour les tests : passez l'entrée que le déclencheur produirait, par exemple
{"body": {...}, "query": {}, "headers": {}} pour un déclencheur webhook.
L'utilisateur a besoin du droit d'exécuter le workflow (voir portées et accès).
Avant le démarrage de l'exécution, le brouillon est validé ; un brouillon invalide est
rejeté avec 422. Une clé d'entrée obligatoire manquante ne rejette pas la requête : l'exécution est
créée et échoue à son étape de déclencheur (Missing input: <keys>).
La requête répond à la fin de l'exécution, ce qui peut prendre plusieurs minutes (jusqu'à la limite de durée d'exécution).
Pour les exécutions longues ou une progression en direct, utilisez le streaming. Lorsqu'une étape attend une
approbation, la réponse revient avec status: "waiting" ; suivez l'exécution avec
obtenir l'exécution.
Réponse
200 OK avec l'exécution.
Exemples
curl -X POST "https://ayeto.ai/api/v3/workflow/run" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workflow_id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
"input": {"customer": "Jana Novak", "question": "When will order 1042 be delivered?"}
}'
import json
import os
import requests
response = requests.post(
"https://ayeto.ai/api/v3/workflow/run",
headers={"uni-api-key": os.environ["AYETO_API_KEY"]},
json={
"workflow_id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
"input": {"customer": "Jana Novak", "question": "When will order 1042 be delivered?"},
},
timeout=1900,
)
response.raise_for_status()
run = response.json()
if run["status"] == "success":
print(json.loads(run["output_json"]) if run["output_json"] else None)
else:
print(run["status"], run["error"])
const response = await fetch("https://ayeto.ai/api/v3/workflow/run", {
method: "POST",
headers: {
"uni-api-key": process.env.AYETO_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
workflow_id: "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
input: { customer: "Jana Novak", question: "When will order 1042 be delivered?" },
}),
});
if (!response.ok) throw new Error((await response.json()).detail);
const run = await response.json();
const output = run.output_json ? JSON.parse(run.output_json) : null;
console.log(run.status, output ?? run.error);
Objet exécution
Une exécution comporte les champs communs, plus :
| Champ | Type | Description |
|---|---|---|
workflow_id |
UUID | Le workflow. |
organization_id |
UUID | Organisation dans laquelle l'exécution a eu lieu, ou null. |
version |
entier | Version publiée exécutée ; null pour une exécution du brouillon. |
trigger_node_id |
chaîne | Déclencheur à partir duquel l'exécution a démarré. |
trigger_type |
chaîne | Son type de nœud, par exemple trigger.manual, trigger.webhook. |
trigger_depth |
entier | Nombre d'exécutions déclenchées par des enregistrements booster qui précèdent celle-ci dans une chaîne. |
automatic |
booléen | Démarrée par un déclencheur (planning, webhook, enregistrement booster), et non par une personne. |
input_json |
chaîne | L'entrée de l'exécution sous forme de texte JSON. |
status |
chaîne | Voir statuts d'exécution. |
started_at |
horodatage | Moment où l'exécution a commencé ; null tant qu'elle est en file d'attente. |
active_since |
horodatage | Début de l'exécution en cours (après une pause, la reprise). |
finished_at |
horodatage | Moment où elle s'est terminée, ou null. |
steps |
tableau d'étapes | État de chaque étape démarrée ou ignorée, dans l'ordre d'exécution. |
output_json |
chaîne | Le résultat (valeur de la dernière étape output atteinte) sous forme de texte JSON ; vide s'il n'y en a pas. |
error |
chaîne | Raison de l'échec de l'exécution. |
credits |
nombre | Crédits dépensés par l'exécution jusqu'à présent. |
created.user_id est l'utilisateur au nom duquel l'exécution s'est effectuée.
Objet étape
| Champ | Type | Description |
|---|---|---|
node_id |
chaîne | Le nœud. |
node_type |
chaîne | Son type. |
status |
chaîne | running, waiting, success, failed ou skipped. |
started_at |
horodatage | Début, null pour une étape ignorée. |
finished_at |
horodatage | Fin. |
handle |
chaîne | Sortie sur laquelle l'exécution a continué : null (par défaut), une sortie nommée, ou error. |
output_json |
chaîne | Sortie de l'étape sous forme de texte JSON, plafonnée à 200 000 caractères (2 000 dans le corps d'une boucle). |
output_truncated |
booléen | La sortie a été coupée au plafond ; output_json n'est alors pas du JSON valide. |
text |
chaîne | Résultat lisible ou texte de statut. |
error |
chaîne | Raison de l'échec de l'étape. |
file_ids |
tableau d'UUID | Fichiers produits par l'étape. |
conversation_id |
UUID | Conversation créée par une étape assistant.run ; lisible via les conversations. |
iteration |
tableau d'entiers | Pour une étape dans le corps d'une boucle, les index des éléments, de la boucle la plus externe vers l'intérieur ; vide sinon. Une étape dans une boucle apparaît une fois par élément. |
Exemple :
{
"id": "c2a1b0d9-8e7f-4a6b-9c5d-4e3f2a1b0c9d",
"workflow_id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
"organization_id": null,
"version": null,
"trigger_node_id": "start",
"trigger_type": "trigger.manual",
"trigger_depth": 0,
"automatic": false,
"input_json": "{\"customer\": \"Jana Novak\", \"question\": \"When will order 1042 be delivered?\"}",
"status": "success",
"started_at": 1759401220011,
"active_since": 1759401220011,
"finished_at": 1759401234567,
"steps": [
{
"node_id": "start", "node_type": "trigger.manual", "status": "success",
"started_at": 1759401220020, "finished_at": 1759401220031, "handle": null,
"output_json": "{\"customer\": \"Jana Novak\", \"question\": \"When will order 1042 be delivered?\"}",
"output_truncated": false, "text": "", "error": "", "file_ids": [], "conversation_id": null, "iteration": []
},
{
"node_id": "answer", "node_type": "assistant.run", "status": "success",
"started_at": 1759401220040, "finished_at": 1759401234400, "handle": null,
"output_json": "{\"text\": \"Dear Jana, order 1042 ships on Friday ...\", \"data\": null, \"files\": []}",
"output_truncated": false, "text": "Dear Jana, order 1042 ships on Friday ...", "error": "",
"file_ids": [], "conversation_id": "8e2f4a6c-1b3d-4e5f-8a7b-9c0d1e2f3a4b", "iteration": []
},
{
"node_id": "result", "node_type": "output", "status": "success",
"started_at": 1759401234410, "finished_at": 1759401234420, "handle": null,
"output_json": "{\"answer\": \"Dear Jana, order 1042 ships on Friday ...\"}",
"output_truncated": false, "text": "", "error": "", "file_ids": [], "conversation_id": null, "iteration": []
}
],
"output_json": "{\"answer\": \"Dear Jana, order 1042 ships on Friday ...\"}",
"error": "",
"credits": 0.42,
"created": {"timestamp": 1759401220000, "user_id": "0f1e2d3c-4b5a-4968-8776-655443322110"}
}
Exécution en streaming
| Endpoint | POST /api/v3/workflow/run/stream |
| Portée | ayeto.workflow |
| Limite de débit | par défaut |
Même requête que pour exécuter un workflow, mais la réponse transmet en streaming les événements de l'exécution au fur et à mesure. L'exécution se poursuit sur le serveur jusqu'à son terme même si le client se déconnecte ; lisez ensuite le résultat avec obtenir l'exécution.
Les erreurs d'accès et de validation (pas d'accès, brouillon invalide, entrée trop volumineuse) sont renvoyées sous forme d'erreur HTTP normale avant le début du stream.
Format de transmission
La réponse (Content-Type: text/event-stream) est une suite d'objets JSON écrits
les uns à la suite des autres sans séparateurs (pas de lignes SSE data:) ; voir
streaming. Chaque objet est un chunk :
{"timestamp": 1759401220012, "data": {"type": "run_start", "run_id": "c2a1b0d9-8e7f-4a6b-9c5d-4e3f2a1b0c9d", "node_id": null, "node_type": null, "status": "running", "handle": null, "text": "", "error": "", "output_json": "", "iteration": []}, "error": null}
dataest un événement de l'exécution (ci-dessous).data: ""est un chunk de maintien de connexion (keep-alive), envoyé environ chaque seconde tant qu'il ne se passe rien. Ignorez-le.- Un chunk dont
errorest renseigné ({"status", "text", "detail"}) signale une erreur qui a mis fin au stream.
Événements
Chaque événement a les champs type, run_id, node_id, node_type, status, handle,
text, error, output_json et iteration ; ceux qui portent une valeur dépendent du
type.
type |
Signification | Champs renseignés |
|---|---|---|
run_start |
L'exécution a démarré. | status: "running" |
step_start |
Une étape a démarré. | node_id, node_type, status: "running", iteration |
step_progress |
Texte de progression d'une étape en cours (un outil ou un assistant au travail). | node_id, node_type, text, iteration |
step_waiting |
Une étape attend (une approbation). Les autres branches continuent. | node_id, node_type, status: "waiting", text, output_json (pour une approbation {approval_id, expires_at, assignees}) |
step_end |
Une étape s'est terminée ou a été ignorée. | node_id, node_type, status (success, failed, skipped), handle, text, error, output_json, iteration |
run_waiting |
L'exécution est en pause ; le stream se termine sans run_end. |
status: "waiting", text (ids des étapes en attente, séparés par des virgules) |
run_end |
L'exécution est terminée ; dernier événement. | status (success, failed), error, output_json |
Les événements des branches parallèles et des éléments de boucle s'entremêlent ; utilisez node_id et iteration pour
les distinguer.
Exemples
curl -N -X POST "https://ayeto.ai/api/v3/workflow/run/stream" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"workflow_id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a", "input": {"question": "When will order 1042 be delivered?"}}'
Python, en découpant le stream en objets JSON avec raw_decode :
import json
import os
import requests
decoder = json.JSONDecoder()
def events(response):
"""Yield the run events of a streamed response."""
buffer = ""
for piece in response.iter_content(chunk_size=None, decode_unicode=True):
buffer += piece
while True:
buffer = buffer.lstrip()
if not buffer:
break
try:
chunk, end = decoder.raw_decode(buffer)
except json.JSONDecodeError:
break # incomplete object, wait for more data
buffer = buffer[end:]
if chunk.get("error"):
raise RuntimeError(chunk["error"]["detail"])
if chunk.get("data"):
yield chunk["data"]
with requests.post(
"https://ayeto.ai/api/v3/workflow/run/stream",
headers={"uni-api-key": os.environ["AYETO_API_KEY"]},
json={"workflow_id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a", "input": {"question": "When will order 1042 be delivered?"}},
stream=True,
timeout=(10, 120),
) as response:
response.raise_for_status()
response.encoding = "utf-8"
for event in events(response):
if event["type"] == "step_end":
print(f"{event['node_id']}: {event['status']} {event['error']}")
elif event["type"] == "run_waiting":
print("paused, waiting for:", event["text"])
elif event["type"] == "run_end":
print("run", event["status"], event["output_json"] or event["error"])
JavaScript, en découpant le stream par le suivi des accolades hors des chaînes :
async function* runEvents(response) {
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
let buffer = "";
while (true) {
const { value, done } = await reader.read();
if (done) return;
buffer += value;
let depth = 0, inString = false, escaped = false, start = -1, consumed = 0;
for (let i = 0; i < buffer.length; i++) {
const c = buffer[i];
if (inString) {
if (escaped) escaped = false;
else if (c === "\\") escaped = true;
else if (c === '"') inString = false;
} else if (c === '"') inString = true;
else if (c === "{") { if (depth++ === 0) start = i; }
else if (c === "}" && --depth === 0) {
const chunk = JSON.parse(buffer.slice(start, i + 1));
consumed = i + 1;
if (chunk.error) throw new Error(chunk.error.detail);
if (chunk.data) yield chunk.data;
}
}
buffer = buffer.slice(consumed);
}
}
const response = await fetch("https://ayeto.ai/api/v3/workflow/run/stream", {
method: "POST",
headers: { "uni-api-key": process.env.AYETO_API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({
workflow_id: "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
input: { question: "When will order 1042 be delivered?" },
}),
});
if (!response.ok) throw new Error((await response.json()).detail);
for await (const event of runEvents(response)) {
if (event.type === "step_start") console.log("running", event.node_id);
if (event.type === "step_end") console.log(event.node_id, event.status, event.error);
if (event.type === "run_waiting") console.log("paused, waiting for", event.text);
if (event.type === "run_end") console.log("done", event.status, event.output_json || event.error);
}
Annuler une exécution
| Endpoint | POST /api/v3/workflow/run/cancel |
| Portée | ayeto.workflow |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
run_id |
UUID | Oui | L'exécution. |
Annule une exécution qui est waiting ou queued. Ses étapes en attente échouent et leurs approbations
en attente sont annulées. L'utilisateur au nom duquel l'exécution s'est effectuée et les utilisateurs ayant un accès en écriture au
workflow peuvent l'annuler. Une exécution running ne peut pas être annulée (422) ; elle se termine
d'elle-même ou à la limite de durée d'exécution. Renvoie l'exécution annulée.
Exécutions
| Endpoints | POST /api/v3/workflow/runs/find<br>POST /api/v3/workflow/runs/count<br>POST /api/v3/workflow/runs/get?entity_id=<run id> |
| Portée | ayeto.workflow |
| Limite de débit | par défaut |
| Endpoint | POST /api/v3/workflow/runs/delete?entity_id=<run id> |
| Portée | ayeto.workflow.write |
| Limite de débit | par défaut |
Ces endpoints voient les exécutions effectuées au nom de l'utilisateur de la clé API : les exécutions que l'utilisateur a démarrées, et les exécutions automatiques des workflows que l'utilisateur a publiés ou activés. Les exécutions des autres utilisateurs sont signalées comme introuvables.
find renvoie un tableau d'exécutions et count un entier ; les deux acceptent le
corps de requête. Les exécutions incluent toutes leurs étapes et sorties, paginez donc
toujours. get renvoie une exécution (corps vide). delete supprime une exécution avec les
conversations et fichiers créés par ses étapes ainsi que ses approbations, et renvoie son id ; supprimer une
exécution en pause y met fin.
Filtres utiles :
| Objectif | Filtre |
|---|---|
| Exécutions d'un workflow | ["workflow_id", "==", "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a"] |
| Exécutions en pause | ["status", "==", "waiting"] |
| Exécutions en échec | ["status", "==", "failed"] |
| Exécutions issues du webhook | ["trigger_type", "==", "trigger.webhook"] |
| Exécutions de la version publiée uniquement | ["version", "!=", null] |
| Démarrées depuis un instant donné | ["created.timestamp", ">=", 1759363200000] |
curl -X POST "https://ayeto.ai/api/v3/workflow/runs/find" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filters": [["workflow_id", "==", "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a"]], "sort_key": "created.timestamp", "sort_order": 1, "limit_from": 0, "limit_to": 10}'
Pour suivre une exécution en pause ou en file d'attente, interrogez get jusqu'à ce que son status soit success, failed ou
cancelled.
Approbations
Les endpoints d'approbation servent aux personnes qui décident : tout utilisateur désigné par une étape d'approbation peut
les utiliser, sans autre permission sur le workflow. La clé API doit tout de même avoir la portée
ayeto.workflow.
| Endpoints | POST /api/v3/workflow/approval/find<br>POST /api/v3/workflow/approval/get<br>POST /api/v3/workflow/approval/decide |
| Portée | ayeto.workflow |
| Limite de débit | par défaut |
| Endpoint | POST /api/v3/workflow/approval/count |
| Portée | ayeto.workflow |
| Limite de débit | élevée |
Objet approbation
Champs communs, plus :
| Champ | Type | Description |
|---|---|---|
workflow_id |
UUID | Le workflow. |
workflow_name |
chaîne | Son nom au moment de l'ouverture de l'approbation. |
run_id |
UUID | L'exécution en pause. |
node_id |
chaîne | L'étape d'approbation. |
organization_id |
UUID | Organisation du workflow, ou null. |
status |
chaîne | pending, approved, rejected, expired (personne n'a décidé à temps) ou cancelled (l'exécution s'est terminée avant). |
title |
chaîne | Ce qu'il faut décider. |
message |
chaîne | Détails (Markdown). |
form_schema |
objet | Schéma JSON du formulaire ({"type": "object", "properties": {...}, "required": [...]}) avec des champs plats de type string, number, integer, boolean, ou un fichier ({"type": "object", "format": "file"}) ; null lorsqu'il n'y a pas de formulaire. |
form_values |
objet | Valeurs préremplies, par nom de champ. |
allow_reject |
booléen | L'approbation peut être rejetée. Lorsque false, l'étape ne fait que recueillir le formulaire. |
assignee_user_ids |
tableau d'UUID | Utilisateurs qui peuvent décider. |
expires_at |
horodatage | Échéance. |
timeout_continues |
booléen | À l'expiration, l'exécution continue sur timeout ; sinon l'étape échoue. |
decision_data |
objet | Les données du formulaire de la décision. |
comment |
chaîne | Commentaire de la décision. |
decided_by |
objet | {id, email, name} de la personne qui a décidé, ou null. |
decided_at |
horodatage | Moment de la décision ou de l'expiration. |
Lister les approbations
Requête :
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
status |
chaîne | Non | Uniquement les approbations ayant ce statut, par exemple pending. |
limit_from |
entier | Non | Index du premier élément. Par défaut 0. |
limit_to |
entier | Non | Index suivant le dernier élément, de 1 à 200. Par défaut 50. |
Renvoie {"items": [<approval>, ...], "total": <number>} avec les approbations dont l'utilisateur peut
décider (ou a décidé), de la plus récente à la plus ancienne. total est le nombre de toutes les approbations correspondantes.
Compter les approbations en attente
Pas de corps de requête. Renvoie {"pending": 3}, le nombre d'approbations qui attendent la
décision de l'utilisateur. Adapté à l'interrogation périodique d'un badge.
Obtenir une approbation
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
approval_id |
UUID | Oui | L'approbation. |
Renvoie l'approbation. Les utilisateurs qui peuvent en décider et ceux qui peuvent lire son workflow peuvent l'obtenir.
Décider d'une approbation
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
approval_id |
UUID | Oui | L'approbation. |
decision |
chaîne | Oui | approve ou reject. |
data |
objet | Non | Données du formulaire (approbation uniquement). Les champs que vous n'envoyez pas conservent leurs valeurs préremplies ; les champs absents du formulaire sont ignorés. Au plus 20 000 caractères en JSON. Les champs fichier acceptent la forme base64 décrite dans fichiers dans l'entrée d'une exécution. |
comment |
chaîne | Non | Commentaire, au plus 2 000 caractères. |
Seuls les utilisateurs de assignee_user_ids peuvent décider, et uniquement tant que l'approbation est pending et
avant expires_at. Les données du formulaire sont validées par rapport à form_schema. La décision devient
la sortie de l'étape d'approbation :
{
"decision": "approved",
"data": {"amount": 1200, "note": "OK for this quarter"},
"comment": "Approved",
"decided_by": {"id": "0f1e2d3c-4b5a-4968-8776-655443322110", "email": "jana@example.com", "name": "Jana Novak"},
"decided_at": 1759405000000,
"approval_id": "e4d3c2b1-a0f9-4e8d-9c7b-6a5f4e3d2c1b"
}
L'exécution reprend en arrière-plan au nom de l'utilisateur au nom duquel elle s'effectuait (et non de celui qui a décidé) ; son
statut passe de waiting à queued puis à running. Renvoie l'approbation
décidée.
curl -X POST "https://ayeto.ai/api/v3/workflow/approval/decide" \
-H "uni-api-key: $AYETO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"approval_id": "e4d3c2b1-a0f9-4e8d-9c7b-6a5f4e3d2c1b",
"decision": "approve",
"data": {"amount": 1200, "note": "OK for this quarter"},
"comment": "Approved"
}'
Publication et déclencheurs
Ces endpoints nécessitent un accès en écriture au workflow.
Informations de déploiement
| Endpoint | POST /api/v3/workflow/deployment |
| Portée | ayeto.workflow.write |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
workflow_id |
UUID | Oui | Le workflow. |
Renvoie l'état de publication. Il contient les URL des webhooks avec leurs secrets, c'est pourquoi il nécessite la portée d'écriture.
| Champ | Type | Description |
|---|---|---|
published_version |
entier | Dernière version publiée, ou null. |
published_at |
horodatage | Date de publication. |
active |
booléen | Les déclencheurs automatiques sont activés. |
run_as |
UUID | Utilisateur au nom duquel s'effectuent les exécutions automatiques. |
draft_changed |
booléen | Le brouillon diffère de la version publiée (positions des nœuds mises à part) ; toujours true lorsque rien n'est publié. |
triggers |
tableau d'objets | Déclencheurs automatiques de la version publiée, voir ci-dessous. |
signing_secret |
chaîne | Clé qui signe les requêtes des étapes http.request avec sign: true ; vide lorsqu'aucune étape ne signe. |
Champs d'un déclencheur :
| Champ | Type | Description |
|---|---|---|
node_id |
chaîne | Le nœud déclencheur. |
type |
chaîne | trigger.schedule, trigger.webhook ou trigger.booster_record. |
active |
booléen | Le déclencheur se déclenche. |
next_run_at |
horodatage | Prochaine heure planifiée (déclencheurs de planning). |
last_fired_at |
horodatage | Dernière fois qu'il a démarré une exécution. |
url |
chaîne | URL du webhook, secret inclus (déclencheurs webhook). |
panel_id |
UUID | Panneau Booster (déclencheurs d'enregistrements booster). |
collection |
chaîne | Collection surveillée, * pour toutes (déclencheurs d'enregistrements booster). |
Une étape http.request signée envoie l'en-tête X-Ayeto-Signature: sha256=<hex HMAC-SHA256 of the request body> calculé avec signing_secret, afin que le service destinataire puisse le vérifier.
Publier un workflow
| Endpoint | POST /api/v3/workflow/publish |
| Portée | ayeto.workflow.write |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
workflow_id |
UUID | Oui | Le workflow. |
note |
chaîne | Non | Note de la version, au plus 500 caractères. |
Valide le brouillon pour l'appelant, l'enregistre comme version suivante, active le workflow
et fait de l'appelant l'utilisateur run_as des exécutions automatiques. Les URL de webhook des nœuds déclencheurs
qui existaient auparavant restent les mêmes. Renvoie les informations de déploiement. Un
brouillon invalide est rejeté avec 422.
Activer ou désactiver
| Endpoint | POST /api/v3/workflow/activate |
| Portée | ayeto.workflow.write |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
workflow_id |
UUID | Oui | Le workflow. |
active |
booléen | Oui | true active les déclencheurs automatiques, false les désactive. |
L'activation valide la version publiée pour l'appelant et fait de l'appelant l'utilisateur
run_as. Tant que le workflow est inactif, les appels de webhook renvoient 404 et les plannings ne se déclenchent pas.
Renvoie les informations de déploiement. Échoue avec 422 lorsque rien n'est publié.
Régénérer le secret d'un webhook
| Endpoint | POST /api/v3/workflow/trigger/regenerate |
| Portée | ayeto.workflow.write |
| Limite de débit | faible |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
workflow_id |
UUID | Oui | Le workflow. |
node_id |
chaîne | Oui | Le nœud déclencheur webhook de la version publiée. |
Attribue un nouveau secret au webhook ; l'ancienne URL cesse immédiatement de fonctionner. Renvoie les informations de déploiement avec la nouvelle URL.
Prévisualiser un planning
| Endpoint | POST /api/v3/workflow/schedule/preview |
| Portée | ayeto.workflow |
| Limite de débit | élevée |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
cron |
chaîne | Oui | Expression cron à cinq champs : minute, heure, jour du mois, mois, jour de la semaine (par exemple 0 8 * * 1-5). Au plus 200 caractères. |
timezone |
chaîne | Non | Fuseau horaire IANA, par exemple Europe/Prague. Par défaut UTC. |
Vérifie un planning pour un nœud trigger.schedule et liste ses prochaines occurrences :
{"valid": true, "error": "", "next_runs": [1759471200000, 1759730400000, 1759816800000, 1759903200000, 1759989600000]}
Un planning invalide renvoie 200 avec valid: false et la raison dans error (nombre de champs
incorrect, fuseau horaire inconnu, exécutions plus fréquentes que l'intervalle minimal autorisé).
Assistant builder
| Endpoint | POST /api/v3/workflow/assistant |
| Portée | ayeto.workflow.write |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
workflow_id |
UUID | Oui | Le workflow. |
Chaque utilisateur ayant un accès en écriture dispose de son propre assistant builder pour un workflow : un
assistant qui lit, modifie, exécute en test et explique le workflow au fil de la
conversation. Cet endpoint renvoie le builder de l'appelant (en le créant s'il n'existe pas) sous forme
d'assistant. Dialoguez avec lui via le chat en utilisant son id comme
assistant ; cela nécessite une clé avec la portée chat. Ses modifications sont enregistrées comme révisions d'origine
builder.
Révisions
Chaque modification de la définition est une révision. Les modifications qui ne font que déplacer des nœuds, effectuées par le même utilisateur en moins de trois minutes, sont fusionnées dans la dernière révision. Les révisions les plus récentes sont conservées (100 par défaut).
Lister les révisions
| Endpoint | POST /api/v3/workflow/revisions |
| Portée | ayeto.workflow |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
workflow_id |
UUID | Oui | Le workflow. |
Renvoie jusqu'à 100 révisions, de la plus récente à la plus ancienne, sans leurs définitions :
| Champ | Type | Description |
|---|---|---|
id |
UUID | La révision. |
created_at |
horodatage | Date de création. |
user_id |
UUID | Auteur. |
origin |
chaîne | created, editor (l'éditeur de l'application ou cette API), builder (l'assistant builder) ou restore. |
changes |
objet | {added_nodes, removed_nodes, changed_nodes, added_edges, removed_edges} : listes d'id de nœuds et nombres d'arêtes par rapport à la révision précédente. |
restored_from |
UUID | Pour une restauration, la révision qui a été rétablie. |
nodes |
entier | Nombre de nœuds. |
edges |
entier | Nombre d'arêtes. |
Obtenir une révision
| Endpoint | POST /api/v3/workflow/revision/get |
| Portée | ayeto.workflow |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
workflow_id |
UUID | Oui | Le workflow. |
revision_id |
UUID | Oui | La révision. |
Renvoie la révision avec sa définition complète : les champs communs plus workflow_id,
definition, origin, changes et restored_from.
Restaurer une révision
| Endpoint | POST /api/v3/workflow/revision/restore |
| Portée | ayeto.workflow.write |
| Limite de débit | par défaut |
Même requête que pour obtenir une révision. Rétablit la définition de la révision comme
brouillon ; la restauration est enregistrée comme nouvelle révision (origine restore), elle peut donc être annulée.
La version publiée ne change pas. Renvoie le workflow mis à jour.
Export et import
Un export est un document JSON contenant la définition du brouillon, le nom et la description. Les exécutions, les révisions, les versions publiées, l'état des déclencheurs (secrets des webhooks), le secret de signature, l'organisation et les partages ne sont pas exportés. Les assistants auxquels les étapes font référence sont exportés uniquement sous forme d'id.
Exporter un workflow
| Endpoint | POST /api/v3/workflow/export |
| Portée | ayeto.workflow |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
workflow_id |
UUID | Oui | Le workflow. |
strip_secrets |
booléen | Non | Ignoré sur cette API : les identifiants d'accès sont toujours supprimés. |
Via une clé API, les valeurs des en-têtes des étapes http.request dont le nom ressemble à un
identifiant d'accès (contient auth, token, secret, key, password, cookie, signature ou
session) sont toujours vidées ; les noms des en-têtes sont conservés. Les chemins vidés sont listés dans
secret_keys. L'utilisateur a besoin d'un accès en écriture, ou d'un partage en lecture avec la permission
workflow.export.
{
"version": "1.0",
"exported_at": 1759405000000,
"workflow": {
"name": "Customer question",
"description": "Drafts an answer to a customer question",
"definition": {"nodes": ["..."], "edges": ["..."]},
"from_id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
"secret_keys": ["notify_crm.headers.Authorization"]
}
}
Importer un workflow
| Endpoint | POST /api/v3/workflow/import |
| Portée | ayeto.workflow.write |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
data |
objet | Oui | Un document d'export, tel que renvoyé par l'export. |
new_name |
chaîne | Non | Nom du nouveau workflow, au plus 200 caractères. Par défaut : le nom exporté. |
organization_id |
UUID | Non | Le créer dans cette organisation (accès en écriture requis). Par défaut : personnel. |
Crée un nouveau workflow non publié appartenant à l'appelant et le valide. Les étapes qui font référence à des éléments que l'appelant ne peut pas utiliser (un assistant d'un autre compte, des identifiants d'accès vidés) ne bloquent pas l'import ; elles sont signalées afin de pouvoir être corrigées.
| Champ | Type | Description |
|---|---|---|
workflow |
objet | Le nouveau workflow. |
issues |
tableau d'objets | Problèmes de validation pour l'appelant, comme dans valider. |
secret_keys |
tableau de chaînes | Valeurs d'en-têtes à renseigner (<node id>.headers.<name>). |
Le format d'export doit avoir la même version majeure (1), et la définition au plus 200
nœuds.
Copier un workflow
| Endpoint | POST /api/v3/workflow/copy |
| Portée | ayeto.workflow.write |
| Limite de débit | par défaut |
| Champ | Type | Obligatoire | Description |
|---|---|---|---|
workflow_id |
UUID | Oui | Le workflow à copier. |
new_name |
chaîne | Non | Nom de la copie. Par défaut : le nom d'origine. |
organization_id |
UUID | Non | Organisation de la copie. Par défaut : personnel. |
Exporte le brouillon et l'importe comme nouveau workflow de l'appelant en un seul appel ; la réponse
est la même que pour l'import. L'utilisateur a besoin d'un accès en écriture ou d'un partage en lecture
avec la permission workflow.copy. Un utilisateur ayant un accès en écriture à l'original conserve les
identifiants d'accès des étapes HTTP ; une copie effectuée grâce à la permission workflow.copy les
omet.
Webhooks
| Endpoint | POST /api/v3/workflow/hook/{trigger_id}/{secret} |
| Portée | aucune : le secret contenu dans l'URL autorise l'appel |
| Limite de débit | webhook par IP, plus une limite par déclencheur (ci-dessous) |
Un nœud trigger.webhook d'un workflow publié et actif possède une URL publique. Obtenez-la depuis
triggers[].url des informations de déploiement :
https://ayeto.ai/api/v3/workflow/hook/9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d/Xq3v...secret...
Traitez l'URL comme un secret ; toute personne qui la détient peut démarrer des exécutions qui dépensent les crédits de
l'utilisateur run_as. En cas de fuite, régénérez-la.
Requête
Envoyez un POST avec un corps JSON et Content-Type: application/json. Un corps d'un autre
type de contenu est transmis sous forme de texte (ou analysé, s'il s'agit de JSON). Aucune clé API n'est nécessaire.
L'entrée de l'exécution (la sortie du déclencheur, disponible pour les étapes sous la forme {{ input }}) est :
| Champ | Type | Description |
|---|---|---|
body |
tout type | Le corps de la requête ; {} lorsqu'il est vide. |
query |
objet | Paramètres de la chaîne de requête de l'URL. |
headers |
objet | Uniquement ces en-têtes de requête, lorsqu'ils sont présents : content-type, user-agent, x-github-event, x-request-id. |
Les étapes la lisent sous la forme {{ input.body.order_id }}, {{ input.query.source }} et ainsi de suite. L'entrée
est limitée à 200 000 caractères de JSON.
Fichiers dans le corps
Des fichiers peuvent être envoyés dans le corps, à n'importe quelle profondeur (jusqu'à 32 niveaux) :
- un objet avec des
dataen base64 et unnameoufilename, et aucune autre clé quename,filename,content_type,mime_type,data,size; - une chaîne data URL
data:<type>;base64,....
Chaque fichier est enregistré comme fichier de l'exécution (appartenant à l'utilisateur run_as, soumis à la limite de taille
des uploads et au quota de stockage) et remplacé dans le corps par ses métadonnées de pièce jointe
({file_id, filename, content_type, file_url, size}). Au plus 10 fichiers par appel.
Réponse
200 OK dès que l'exécution est mise en file d'attente ; l'exécution s'effectue en arrière-plan :
{"run_id": "b7c6d5e4-f3a2-4b1c-9d8e-7f6a5b4c3d2e", "status": "queued"}
L'exécution exécute la version publiée au nom de l'utilisateur run_as, qui la voit via les
exécutions (trigger_type vaut trigger.webhook, automatic vaut true). Son entrée n'est pas
considérée comme fiable : une étape ne lit les fichiers de l'utilisateur que lorsque l'étape les désigne elle-même, jamais parce que
le corps du webhook les désigne.
Limitation de débit
Chaque déclencheur accepte au plus 60 appels par minute, 2 000 par heure et 20 000 par jour, quel que soit
le nombre d'expéditeurs. Une limite anti-saturation par IP s'applique en plus. Un workflow refuse aussi les nouvelles
exécutions tant qu'il a 50 exécutions en file d'attente (par défaut). Les deux répondent 429 ; une réponse de limite de débit
comporte Retry-After (en secondes).
Exemple
curl -X POST "https://ayeto.ai/api/v3/workflow/hook/9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d/$WEBHOOK_SECRET?source=shop" \
-H "Content-Type: application/json" \
-d '{
"order_id": 1042,
"customer": {"name": "Jana Novak", "email": "jana@example.com"},
"invoice": {"filename": "invoice-1042.pdf", "content_type": "application/pdf", "data": "JVBERi0xLjcKJcfsj6IK..."}
}'
Erreurs
Les erreurs ont le corps JSON {"detail": "..."}. Les erreurs d'authentification, de limite de débit et les erreurs serveur
sont décrites dans les conventions.
| Statut | Signification |
|---|---|
401 |
La clé API est absente, invalide ou n'a pas la portée requise (API key is invalid). |
403 |
L'utilisateur n'a pas accès au workflow, ou n'a pas la permission ou l'appartenance à l'organisation requise par l'opération. |
404 |
Le workflow, l'exécution, la révision, l'approbation ou le webhook n'existe pas ou n'est pas visible pour l'utilisateur. |
422 |
La requête est invalide, ou l'opération n'est pas possible dans l'état actuel (detail en indique la raison). |
423 |
Le workflow ou l'exécution est en cours de modification par une autre requête ; réessayez dans un instant. |
429 |
Trop de requêtes (avec Retry-After), ou trop d'exécutions en file d'attente. |
500 |
Erreur serveur. |
Erreurs propres aux workflows :
| Statut | detail |
Cause |
|---|---|---|
403 |
permission denied |
Le compte de l'utilisateur n'est pas autorisé à lire ou à écrire des workflows ou des exécutions. |
403 |
You do not have access to this workflow |
L'utilisateur n'est pas propriétaire et le workflow n'est pas partagé avec lui (ou il est partagé en lecture alors que l'écriture est nécessaire). |
403 |
This workflow is shared with you without the 'workflow.run' permission |
Partage en lecture sans la permission d'exécuter (de même pour workflow.export, workflow.copy). |
403 |
User is not a member of the organization |
Le workflow appartient à une organisation dont l'utilisateur ne fait pas partie. |
403 |
User does not have write permissions in the organization |
L'utilisateur ne peut pas travailler dans l'organisation du workflow. |
404 |
Workflow not found |
Le workflow n'existe pas (ou a été supprimé). |
404 |
entity not found |
get, update, delete CRUD d'un workflow ou d'une exécution qui n'existe pas ou n'appartient pas à l'utilisateur. |
404 |
Workflow run not found |
Exécution inconnue, ou exécution que l'utilisateur ne peut pas annuler. |
404 |
Revision not found |
La révision n'existe pas ou appartient à un autre workflow. |
404 |
Approval not found |
Approbation inconnue, ou l'utilisateur ne peut ni la voir ni en décider. |
404 |
The file of the input '<key>' was not found or is not accessible |
Un champ fichier désigne un fichier que l'utilisateur ne possède pas. |
404 |
The published workflow has no such webhook trigger |
Régénération avec un nœud qui n'est pas un déclencheur webhook de la version publiée. |
404 |
Webhook not found |
Id de déclencheur inconnu ou secret erroné. |
404 |
The workflow of this webhook is not active |
Le workflow est désactivé ou non publié, ou il a été supprimé. |
422 |
The workflow is not valid: <errors> |
Exécution, publication ou activation d'une définition comportant des erreurs de validation. |
422 |
'<id>' is not a trigger of the workflow |
trigger_node_id n'est pas un déclencheur. |
422 |
The workflow has no trigger |
Aucun déclencheur à partir duquel démarrer. |
422 |
The run input is too large (at most 200000 characters of JSON) |
Entrée d'exécution ou entrée de webhook au-delà de la limite. |
422 |
The input '<key>' must be one file |
Un champ fichier contient plusieurs fichiers ou autre chose. |
422 |
The file is not valid base64 data |
Fichier transmis directement avec un base64 invalide. |
422 |
Too many files (at most 10) |
Trop de fichiers dans le corps d'un webhook. |
422 |
A <status> run can not be cancelled |
Annulation d'une exécution qui n'est ni waiting ni queued. |
422 |
Publish the workflow first |
Activation sans version publiée. |
422 |
Unsupported workflow export format <version> |
Import d'un export ayant une autre version majeure. |
422 |
The workflow has too many steps (<n>, at most 200) |
Import d'une définition dépassant la limite de nœuds. |
422 |
The approval is <status> already |
Décision sur une approbation qui n'est plus en attente. |
422 |
The time to decide the approval is over |
Décision après expires_at. |
422 |
The approval can not be rejected |
reject alors que allow_reject vaut false. |
422 |
Step '<node id>' of the run does not wait |
L'exécution a cessé d'attendre (annulée, en échec) avant la décision. |
422 |
The form data is too large (at most 20000 characters of JSON) |
Données de décision au-delà de la limite. |
429 |
Too many requests |
Limite de débit, y compris la limite de webhook par déclencheur ; voir Retry-After. |
429 |
The workflow already has <n> runs waiting |
Appel de webhook alors que la file d'attente du workflow est pleine. |
L'échec d'une étape n'est pas une erreur HTTP : l'exécution revient avec status: "failed" et la
raison dans error ainsi que dans le champ error de l'étape en échec.