Workflows
Un workflow enchaîne plusieurs applications en un seul flux : un déclencheur, puis les applications qui s'exécutent l'une après l'autre, avec des conditions qui aiguillent selon la réponse de l'étape précédente. L'API est la surface de création — vous créez le flux, vous dessinez ou décrivez ses étapes, vous relisez s'il peut réellement s'exécuter, vous l'activez et vous le publiez. C'est le même objet que celui que l'espace de travail dessine sur sa zone de travail : un flux écrit ici s'ouvre dans l'éditeur de flux, et un flux dessiné là-bas se lit ici.
Les appels
| Méthode | Chemin | Droit requis |
|---|---|---|
| POST | /v1/workflow/create | workflow:write |
| GET | /v1/workflow/list | workflow:read |
| GET | /v1/workflow/detail/<workflow_id> | workflow:read |
| PATCH | /v1/workflow/detail/<workflow_id> | workflow:write |
| DELETE | /v1/workflow/detail/<workflow_id> | workflow:write |
<workflow_id> est un identifiant de workflow, préfixé wkfl_.
Important — Aucun appel ne lance un workflow. Une exécution est avancée par l'espace de travail, une étape par chargement de page : une exécution créée de l'extérieur resterait en attente et n'avancerait jamais. Lancez un flux depuis sa page dans l'espace de travail. Pour lancer une seule application depuis l'API, utilisez plutôt Exécutions.
L'objet workflow
| Champ | Type | Description |
|---|---|---|
id | chaîne | L'identifiant du workflow, préfixé wkfl_. |
object | chaîne | Toujours workflow. |
name | chaîne | Le nom du flux. |
description | chaîne | Ce que fait le flux. |
type | chaîne | private ou public. public signifie que le flux est proposé dans le catalogue. |
status | chaîne | draft ou activated. Seul un flux activé peut être lancé. |
trigger | chaîne | Ce qui démarre le flux. Toujours manual aujourd'hui. |
counts | objet | app et condition : combien le dessin en compte. |
apps | tableau | Une entrée { "id", "name" } par application distincte enchaînée, dans l'ordre du dessin. |
graph | objet | Le dessin : nodes et edges. Uniquement en consultation et en écriture. |
ready | booléen | Vaut true lorsque le flux est valide et peut s'exécuter. Uniquement en consultation et en écriture. |
issues | tableau | Une phrase par règle que le dessin enfreint. Vide lorsque ready vaut true. Uniquement en consultation et en écriture. |
runs | objet | total, private (les exécutions du projet) et public (celles faites par la copie publiée). |
created_at | entier | Date de création, en secondes Unix. |
updated_at | entier | Dernière modification, en secondes Unix. |
Le dessin
Le dessin est un ensemble de nœuds (nodes) reliés par des liens (edges).
| Champ de nœud | Type | Description |
|---|---|---|
key | chaîne | Le nom du nœud dans le dessin, de 1 à 40 caractères parmi A-Z a-z 0-9 _ -. |
type | chaîne | trigger, app ou condition. |
x, y | entier | La position de la case sur la zone de travail. Facultatif — un nœud sans coordonnées est placé sur la grille. |
config | objet | Dépend du type, voir ci-dessous. |
| Type de nœud | config |
|---|---|
trigger | event, qui vaut manual. Toute autre valeur est lue comme manual. |
app | app_ident, l'application que l'étape exécute, et éventuellement fields (voir ci-dessous). |
condition | operator et value. Les opérateurs sont contains, not_contains, equals, not_empty. |
| Champ de lien | Type | Description |
|---|---|---|
from | chaîne | Le nœud d'où part la flèche. |
to | chaîne | Le nœud où arrive la flèche. |
branch | chaîne | Vide pour une flèche simple. Sur une condition, true ou false indique la branche empruntée. |
Un flux est prêt à s'exécuter lorsqu'il porte exactement un déclencheur, au moins une application, que chaque étape applicative nomme une application activée de ce projet dotée d'un modèle utilisable, que chaque champ obligatoire est alimenté, qu'aucune condition n'est en tête de chaîne, qu'aucune flèche ne referme une boucle et que chaque nœud est atteignable depuis le déclencheur. Lorsqu'une règle est enfreinte, issues la nomme — une règle rattachée à un nœud se lit Step 'n2': ….
Un dessin porte au plus 60 nœuds et 7200 liens.
Note — Tout ce que la zone de travail ne saurait pas dessiner est abandonné, non refusé : un type de nœud inconnu, une coordonnée hors grille, une flèche vers un nœud inexistant, une flèche d'un nœud vers lui-même, une flèche en double. Le
graphde la réponse est le dessin tel qu'il a été enregistré : relisez-le pour voir exactement ce qui a été conservé.
Fixer les champs d'une étape
Par défaut, une étape applicative est alimentée par l'étape qui la précède. config.fields remplace ce choix, une entrée par champ, indexée par le name du champ ou par son identifiant madi_.
| Nature du champ | Forme | Sources |
|---|---|---|
| Texte | { "source", "value" } — source vaut previous, input ou static | previous reprend la réponse de l'étape précédente, input la demande à qui lance le flux, static envoie toujours value. |
| Document ou image | { "source", "file" } — source vaut input ou static, et file est un identifiant file_… | input demande un fichier au lancement, static envoie toujours celui qui est nommé. |
Une valeur seule est un raccourci pour static : "tone": "formal" équivaut à "tone": { "source": "static", "value": "formal" }. Un objet vide prend la valeur par défaut — previous pour un texte, input pour un fichier.
Créer un workflow
POST /v1/workflow/create accepte soit un dessin, soit une liste ordonnée d'étapes.
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
name | chaîne | oui | Le nom du flux, 190 caractères au plus. |
description | chaîne | oui | Ce que fait le flux. |
graph | objet | non | Un dessin, tel que décrit ci-dessus. Également accepté sous forme de chaîne JSON. |
steps | tableau | non | Une liste ordonnée d'étapes, reliées pour vous. 59 au plus. |
status | chaîne | non | draft ou activated. Vaut activated par défaut. |
type | chaîne | non | private ou public. Vaut private par défaut. |
Envoyez graph lorsque vous disposez déjà d'un dessin, steps lorsque vous voulez simplement que les applications s'exécutent dans l'ordre. Chaque étape s'écrit { "app": "mapp_… ou un nom", "fields": {…} } ou { "condition": { "operator": "contains", "value": "urgent" } }. Les étapes sont reliées entre elles dans l'ordre où vous les envoyez, un déclencheur est créé en tête, et une condition passe à l'étape suivante sur sa branche true. Ajoutez "on_false" à une condition, en nommant une autre étape par son numéro, pour relier l'autre branche.
curl -X POST https://api.think.ultineo.com/v1/workflow/create \
-H "Authorization: Bearer sk-project-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Triage then answer",
"description": "Sort the incoming message, then draft the reply.",
"steps": [
{ "app": "mapp_0ceacb46e5b3a99e91b6" },
{ "condition": { "operator": "contains", "value": "urgent" } },
{ "app": "mapp_7d3f81b0c25e94a6f01d" }
]
}' {
"code": 200,
"title": "OK",
"response": {
"id": "wkfl_4a91c7e0d25b83f6a1cd",
"object": "workflow",
"name": "Triage then answer",
"description": "Sort the incoming message, then draft the reply.",
"type": "private",
"status": "activated",
"trigger": "manual",
"counts": { "app": 2, "condition": 1 },
"apps": [
{ "id": "mapp_0ceacb46e5b3a99e91b6", "name": "Message triage" },
{ "id": "mapp_7d3f81b0c25e94a6f01d", "name": "Reply drafter" }
],
"graph": {
"nodes": [
{ "key": "n1", "type": "trigger", "x": 60, "y": 220, "config": {} },
{ "key": "n2", "type": "app", "x": 360, "y": 220, "config": { "app_ident": "mapp_0ceacb46e5b3a99e91b6" } },
{ "key": "n3", "type": "condition", "x": 660, "y": 220, "config": { "operator": "contains", "value": "urgent" } },
{ "key": "n4", "type": "app", "x": 960, "y": 220, "config": { "app_ident": "mapp_7d3f81b0c25e94a6f01d" } }
],
"edges": [
{ "from": "n1", "to": "n2", "branch": "" },
{ "from": "n2", "to": "n3", "branch": "" },
{ "from": "n3", "to": "n4", "branch": "true" }
]
},
"ready": true,
"note": null,
"created_at": 1754209200
}
} La création est le seul endroit où un flux invalide est refusé : le dessin n'existe pas encore, il n'y a donc rien à perdre à le redemander.
| Code | Message | Cause |
|---|---|---|
| 400 | Missing required field: name. | Aucun nom n'a été envoyé. |
| 400 | Missing required field: description. | Aucune description n'a été envoyée. |
| 422 | The graph could not be read: send it as a JSON object (or a JSON string) carrying 'nodes' and 'edges'. | graph n'était pas un objet lisible. |
| 422 | The flow is not valid: <issues> | Le dessin enfreint une ou plusieurs des règles ci-dessus. |
| 422 | steps must be a non-empty ordered array of steps. | steps était vide ou n'était pas une liste. |
| 422 | steps must contain at most 59 steps. | Trop d'étapes pour la zone de travail. |
| 422 | Step <n> names an app that does not exist, is not activated, or is not available to this project: name one of this project's activated apps by id (mapp_…) or by name. | L'étape nomme une application inutilisable. |
| 422 | Step <n> uses an unknown condition operator: accepted operators are contains, not_contains, equals, not_empty. | L'opérateur n'est pas l'un des quatre. |
| 422 | status must be 'draft' or 'activated'. | Un statut inconnu. |
| 422 | type must be 'public' or 'private'. | Un type inconnu. |
| 402 | The current billing plan does not allow workflow creation for this project. | L'abonnement ne prévoit aucun workflow. |
| 402 | The current billing plan workflow limit has been reached for this project. | Le projet porte déjà autant de flux que l'abonnement l'autorise. |
Envoyer à la fois graph et steps n'est pas une erreur : le dessin l'emporte, et la réponse le dit dans note : Both 'graph' and 'steps' were provided: 'graph' was used and 'steps' ignored.
Note — Une étape ne peut nommer qu'une application de votre propre projet, même publiée par un autre : l'éditeur de flux ne sait pas dessiner une étape sur une application qui ne lui appartient pas, et l'étape serait effacée à la première ouverture du flux. Copiez d'abord l'application dans votre projet.
Lister vos workflows
GET /v1/workflow/list renvoie les flux du projet, du plus récent au plus ancien. Les flux supprimés en sont exclus.
| Paramètre | Type | Description |
|---|---|---|
limit | entier | Entre 1 et 100. Vaut 50 par défaut. |
offset | entier | Le nombre de lignes à passer. Vaut 0 par défaut. |
curl "https://api.think.ultineo.com/v1/workflow/list?limit=2" \
-H "Authorization: Bearer sk-project-YOUR_KEY" {
"code": 200,
"title": "OK",
"response": {
"object": "list",
"data": [
{
"id": "wkfl_4a91c7e0d25b83f6a1cd",
"object": "workflow",
"name": "Triage then answer",
"description": "Sort the incoming message, then draft the reply.",
"type": "private",
"status": "activated",
"trigger": "manual",
"counts": { "app": 2, "condition": 1 },
"apps": [
{ "id": "mapp_0ceacb46e5b3a99e91b6", "name": "Message triage" },
{ "id": "mapp_7d3f81b0c25e94a6f01d", "name": "Reply drafter" }
],
"runs": { "total": 12, "private": 12, "public": 0 },
"created_at": 1754209200,
"updated_at": 1754212800
}
],
"total": 7
}
} Une ligne de liste ne porte ni graph, ni ready, ni issues : une page de dessins fait une réponse volumineuse, et la validité coûte plusieurs requêtes par flux. Consultez un flux pour obtenir les trois.
Consulter un workflow
GET /v1/workflow/detail/<workflow_id> renvoie le flux entier, dessin compris.
curl https://api.think.ultineo.com/v1/workflow/detail/wkfl_4a91c7e0d25b83f6a1cd \
-H "Authorization: Bearer sk-project-YOUR_KEY" Le graph que vous relisez est le dessin normalisé — celui que la zone de travail et le moteur lisent réellement, débarrassé de tout ce qui n'a pas été reconnu. Le flux d'un autre projet répond 404 et Workflow not found., qu'il existe ou non.
Modifier un workflow
PATCH /v1/workflow/detail/<workflow_id> ne change que les champs présents dans le corps de la requête.
| Paramètre | Type | Description |
|---|---|---|
name | chaîne | Un nouveau nom. |
description | chaîne | Une nouvelle description. |
graph | objet | Un nouveau dessin. Il remplace l'ancien. |
status | chaîne | draft ou activated. |
type | chaîne | private ou public. |
curl -X PATCH https://api.think.ultineo.com/v1/workflow/detail/wkfl_4a91c7e0d25b83f6a1cd \
-H "Authorization: Bearer sk-project-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Triage, then answer" }' Important — Un PATCH qui porte un
graphenregistre toujours le dessin, même lorsque le flux n'est pas valide. Il n'est pas refusé : le flux repasse endraftdans la même écriture et la réponse reste un200, avec"ready": false, les règles enfreintes sousissues, etnotequi indiqueThe graph was saved but does not validate, so the workflow was set back to draft.C'est ce que fait la zone de travail — un flux à moitié dessiné est conservé pour que vous puissiez y revenir. Après un PATCH, lisez doncreadyetissues, jamais le code HTTP, pour savoir si le flux peut s'exécuter.
L'activation et la publication, elles, sont des verrous. "status": "activated" et "type": "public" sont tous deux refusés lorsque le dessin final n'est pas valide, et publier un flux exige en plus qu'il soit activé et que chaque application qu'il enchaîne soit elle-même publiée.
| Code | Message | Cause |
|---|---|---|
| 404 | Workflow not found. | Flux inconnu, supprimé, ou appartenant à un autre projet. |
| 422 | Missing required field: name. | name était présent mais vide. |
| 422 | Missing required field: description. | description était présent mais vide. |
| 422 | The flow is not valid: <issues> | Une activation ou une publication a été demandée sur un dessin qui n'est pas valide. |
| 422 | The workflow must be activated before it can be published. | type: public sur un brouillon. |
| 422 | Every app this workflow chains must be published before the workflow can be published: '<name>' is not. | Une application enchaînée est encore privée. |
Une association de champ qui ne nomme aucun champ de son application est un 422 lorsque vous l'envoyez par steps, mais à l'intérieur d'un graph dessiné à la main elle est abandonnée et signalée dans note — le dessin est conservé dans les deux cas.
Supprimer un workflow
DELETE /v1/workflow/detail/<workflow_id> retire le flux des listes, du catalogue s'il était publié, et de l'espace de travail.
curl -X DELETE https://api.think.ultineo.com/v1/workflow/detail/wkfl_4a91c7e0d25b83f6a1cd \
-H "Authorization: Bearer sk-project-YOUR_KEY" {
"code": 200,
"title": "OK",
"response": { "deleted": true, "id": "wkfl_4a91c7e0d25b83f6a1cd" }
} La suppression est douce : les exécutions que le flux a déjà produites sont conservées et restent consultables. Supprimer un flux déjà supprimé répond 404 et Workflow not found.