ULTINEO REASONING

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éthodeCheminDroit requis
POST/v1/workflow/createworkflow:write
GET/v1/workflow/listworkflow: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

ChampTypeDescription
idchaîneL'identifiant du workflow, préfixé wkfl_.
objectchaîneToujours workflow.
namechaîneLe nom du flux.
descriptionchaîneCe que fait le flux.
typechaîneprivate ou public. public signifie que le flux est proposé dans le catalogue.
statuschaînedraft ou activated. Seul un flux activé peut être lancé.
triggerchaîneCe qui démarre le flux. Toujours manual aujourd'hui.
countsobjetapp et condition : combien le dessin en compte.
appstableauUne entrée { "id", "name" } par application distincte enchaînée, dans l'ordre du dessin.
graphobjetLe dessin : nodes et edges. Uniquement en consultation et en écriture.
readybooléenVaut true lorsque le flux est valide et peut s'exécuter. Uniquement en consultation et en écriture.
issuestableauUne phrase par règle que le dessin enfreint. Vide lorsque ready vaut true. Uniquement en consultation et en écriture.
runsobjettotal, private (les exécutions du projet) et public (celles faites par la copie publiée).
created_atentierDate de création, en secondes Unix.
updated_atentierDerniè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œudTypeDescription
keychaîneLe nom du nœud dans le dessin, de 1 à 40 caractères parmi A-Z a-z 0-9 _ -.
typechaînetrigger, app ou condition.
x, yentierLa position de la case sur la zone de travail. Facultatif — un nœud sans coordonnées est placé sur la grille.
configobjetDépend du type, voir ci-dessous.
Type de nœudconfig
triggerevent, qui vaut manual. Toute autre valeur est lue comme manual.
appapp_ident, l'application que l'étape exécute, et éventuellement fields (voir ci-dessous).
conditionoperator et value. Les opérateurs sont contains, not_contains, equals, not_empty.
Champ de lienTypeDescription
fromchaîneLe nœud d'où part la flèche.
tochaîneLe nœud où arrive la flèche.
branchchaîneVide 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 graph de 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 champFormeSources
Texte{ "source", "value" } — source vaut previous, input ou staticprevious 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ètreTypeObligatoireDescription
namechaîneouiLe nom du flux, 190 caractères au plus.
descriptionchaîneouiCe que fait le flux.
graphobjetnonUn dessin, tel que décrit ci-dessus. Également accepté sous forme de chaîne JSON.
stepstableaunonUne liste ordonnée d'étapes, reliées pour vous. 59 au plus.
statuschaînenondraft ou activated. Vaut activated par défaut.
typechaînenonprivate 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
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" }
    ]
  }'
json
{
  "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.

CodeMessageCause
400Missing required field: name.Aucun nom n'a été envoyé.
400Missing required field: description.Aucune description n'a été envoyée.
422The 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.
422The flow is not valid: <issues>Le dessin enfreint une ou plusieurs des règles ci-dessus.
422steps must be a non-empty ordered array of steps.steps était vide ou n'était pas une liste.
422steps must contain at most 59 steps.Trop d'étapes pour la zone de travail.
422Step <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.
422Step <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.
422status must be 'draft' or 'activated'.Un statut inconnu.
422type must be 'public' or 'private'.Un type inconnu.
402The current billing plan does not allow workflow creation for this project.L'abonnement ne prévoit aucun workflow.
402The 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ètreTypeDescription
limitentierEntre 1 et 100. Vaut 50 par défaut.
offsetentierLe nombre de lignes à passer. Vaut 0 par défaut.
curl
curl "https://api.think.ultineo.com/v1/workflow/list?limit=2" \
  -H "Authorization: Bearer sk-project-YOUR_KEY"
json
{
  "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
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ètreTypeDescription
namechaîneUn nouveau nom.
descriptionchaîneUne nouvelle description.
graphobjetUn nouveau dessin. Il remplace l'ancien.
statuschaînedraft ou activated.
typechaîneprivate ou public.
curl
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 graph enregistre toujours le dessin, même lorsque le flux n'est pas valide. Il n'est pas refusé : le flux repasse en draft dans la même écriture et la réponse reste un 200, avec "ready": false, les règles enfreintes sous issues, et note qui indique The 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 donc ready et issues, 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.

CodeMessageCause
404Workflow not found.Flux inconnu, supprimé, ou appartenant à un autre projet.
422Missing required field: name.name était présent mais vide.
422Missing required field: description.description était présent mais vide.
422The flow is not valid: <issues>Une activation ou une publication a été demandée sur un dessin qui n'est pas valide.
422The workflow must be activated before it can be published.type: public sur un brouillon.
422Every 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
curl -X DELETE https://api.think.ultineo.com/v1/workflow/detail/wkfl_4a91c7e0d25b83f6a1cd \
  -H "Authorization: Bearer sk-project-YOUR_KEY"
json
{
  "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.