> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.goodflag.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.goodflag.com/_mcp/server.

# Créer le workflow

> Créer un workflow de signature

# Parapheurs (workflows)

## Qu'est-ce qu'un parapheur ?

Un **parapheur** (*workflow*) est un processus de signature et/ou de validation. Il est
créé **sous un utilisateur** — son **gestionnaire** — et porte un identifiant `wfl_`.

Un parapheur est composé d'**étapes** (*steps*), jouées **séquentiellement**. Chaque étape
réunit un ou plusieurs **destinataires** (*recipients*) qui agissent, eux, **en parallèle**.
C'est la combinaison des deux qui décrit l'ordre des signatures :

* plusieurs destinataires **dans une même étape** → ils signent/valident **en parallèle** ;
* plusieurs **étapes successives** → elles s'enchaînent dans l'ordre (**séquentiel**).

**Structure d'ensemble** — chaque niveau porte ses **propres champs** :

```
Parapheur (wfl_)                                   ← niveau 1 : le parapheur (section [*Le parapheur — champs de premier niveau (niveau 1)*](#le-parapheur-champs-de-premier-niveau-niveau-1))
├─ champs propres : name, description, workflowMode, notifiedEvents,
│                   allowConsolidation, layoutId + data1…16, templateId
│
├─ steps[]                                         ← niveau 2 : les étapes, séquentielles (section [*Les étapes — steps (niveau 2)*](#les-etapes-steps-niveau-2))
│   ├─ champs propres : stepType, requiredRecipients, validityPeriod,
│   │                   invitePeriod, maxInvites, sendDownloadLink,
│   │                   hideAttachments, faceToFaceSignature…
│   │
│   └─ recipients[]                                ← niveau 3 : les destinataires, en parallèle (section [*Les destinataires — recipients (niveau 3)*](#les-destinataires-recipients-niveau-3))
│        └─ champs propres : consentPageId, userId | contactId | (email+nom),
│                            phoneNumber, country, organizationId, preferredLocale
│
└─ watchers[]                                      ← niveau 4 : les observateurs, au niveau du parapheur (section [*Les observateurs — watchers (niveau 4) & les notifications*](#les-observateurs-watchers-niveau-4-les-notifications))
        userId (utilisateur) | email (contact)
```

Deux **modes** existent :

* **`FULL`** (par défaut) — toutes les possibilités : plusieurs étapes, observateurs,
  consolidation, création depuis un modèle…
* **`SINGLE_SIGNER`** — un parapheur à **une seule étape** (le plus simple).

Remarque importante : le mode SINGLE\_SIGNER ("signataire unique") permet en particulier de construire un parapheur avec des champs dynamiques qui sont à compléter par le signataire avant la signature. Cette fonctionnalité est prise en charge par le Workflow Manager mais pas par l'Evidence Manager et donc le processus de saisie de ces informations n'est pas géré par le fichier de preuve.

Du fait que son intérêt est surtout de permettre à un gestionnaire de parapheur d'autoriser une saisie préalable afin de faire compléter un ou plusieurs documents par le signataire avant sa signature, il est important de noter que dès lors qu'un développeur s'appuie sur l'API, il est préférable de faire effectuer cette saisie ainsi que tous ses contrôles associés par l'application métier. À noter d'ailleurs qu'aucun contrôle n'est effectué par le Workflow Manager sur les champs de saisie qui sont uniquement du texte libre. Par conséquent **le mode SINGLE\_SIGNER n'est pas abordé plus avant dans cette documentation**. On précise également que le mode signataire unique peut être désactivé au niveau du tenant.

## Créer un parapheur (à l'état brouillon)

```http
POST /api/users/{userId}/workflows
Authorization: Bearer act_<id>.<secret>
Content-Type: application/json

{
  "name": "Attestation d'emprunt de matériel",
  "workflowMode": "FULL",
  "notifiedEvents": [ "recipientFinished", "workflowStopped", "workflowFinished" ],
  "steps": [
    {
      "stepType": "signature",
      "requiredRecipients": 1,
      "recipients": [ { "consentPageId": "cop_…", "userId": "usr_…" } ]
    }
  ]
}
```

Le parapheur est **rattaché au gestionnaire** (`{userId}` dans l'URL) et créé à l'état
**brouillon** : **rien n'est envoyé** tant qu'il n'est pas lancé (section [*Cycle de vie & statuts*](#cycle-de-vie-statuts)). L'appel s'authentifie
avec un jeton d'API dont l'utilisateur a le droit de créer des parapheurs (fondation [*Groupes, rôles & droits*](/wm/api-reference/concepts/groupes-roles-droits)).

Le corps reflète les niveaux ci-dessus : les champs propres du parapheur, le tableau `steps[]`
(chaque étape contenant ses `recipients[]`) et, le cas échéant, `watchers[]`. Les quatre
sections suivantes détaillent chacun de ces niveaux.

## Le parapheur — champs de premier niveau (niveau 1)

| Champ                        | Rôle                                                                                                                                                                                                                                                                          |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                       | Nom du parapheur (requis).                                                                                                                                                                                                                                                    |
| `description`                | Description *(facultative)*. À noter que la description s'affiche au destinataire lors du processus de signature ou de validation.                                                                                                                                            |
| `workflowMode`               | `FULL` (défaut) ou `SINGLE_SIGNER`. Voir la remarque du section [*Qu'est-ce qu'un parapheur ?*](#quest-ce-quun-parapheur).                                                                                                                                                    |
| `notifiedEvents`             | Événements dont le **gestionnaire** est notifié (section [*Les observateurs — watchers (niveau 4) & les notifications*](#les-observateurs-watchers-niveau-4-les-notifications)).                                                                                              |
| `allowConsolidation`         | Autoriser la **consolidation**. *(Null en `SINGLE_SIGNER`)*. Ce champ autorise le destinataire à signer, en un seul processus d'authentification, tous les parapheurs pour lesquels la consolidation est activée, sous réserve que le mode d'authentification soit identique. |
| `layoutId`, `data1`…`data16` | **Disposition de métadonnées** (`layoutId`) et ses **valeurs** (`data1`…`data16`) — voir la fondation [*Métadonnées*](/wm/api-reference/concepts/metadonnees).                                                                                                                |
| `templateId`                 | Créer à partir d'un **modèle**. *(Null en `SINGLE_SIGNER`)*. Il est déconseillé d'utiliser un modèle — voir la fondation [*Positionnement et périmètre*](/wm/api-reference/introduction).                                                                                     |
| `steps`                      | Les **étapes** du parapheur — détaillées au section [*Les étapes — steps (niveau 2)*](#les-etapes-steps-niveau-2). *(Une seule autorisée en `SINGLE_SIGNER`)*.                                                                                                                |
| `watchers`                   | Les **observateurs** du parapheur — détaillés au section [*Les observateurs — watchers (niveau 4) & les notifications*](#les-observateurs-watchers-niveau-4-les-notifications). *(Null en `SINGLE_SIGNER`)*.                                                                  |

> **Cogestion.** La possibilité de faire **cogérer** un parapheur par d'autres utilisateurs
> (champs `allowedCoManagerUsers` / `coManagerNotifiedEvents` visibles sur l'objet parapheur)
> dépend entièrement des **modèles** : elle n'est disponible que pour un parapheur créé à partir
> d'un modèle. Les modèles étant hors périmètre d'une utilisation raisonnée de l'API (voir
> `templateId` ci-dessus et la fondation [*Positionnement et périmètre*](/wm/api-reference/introduction)), la cogestion n'est donc pas
> détaillée ici.

## Les étapes — `steps` (niveau 2)

Les étapes s'enchaînent **séquentiellement**. Champs propres à chaque étape :

| Champ                                                    | Rôle                                                                                                                                                                                                                                                             |
| -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `stepType`                                               | `signature` ou `approval` (validation).                                                                                                                                                                                                                          |
| `requiredRecipients`                                     | Nombre de destinataires notifiés en parallèle devant signer ou valider pour que l'étape s'achève. C'est un principe appelé « signatures ou validations suffisantes » par Goodflag. Ce principe est intéressant dès lors qu'une notion de "quorum" est présente.  |
| `validityPeriod`                                         | Durée de validité de l'étape, en **ms** (min 1 jour, max ≈ 99 jours).                                                                                                                                                                                            |
| `invitePeriod`                                           | Délai de **relance** des invitations, en ms (min 1 jour, max 30 jours).                                                                                                                                                                                          |
| `maxInvites`                                             | Nombre maximum d'invitations envoyées (0 à 99). Attention : en mettant 0, le destinataire ne sera jamais invité à signer / valider.                                                                                                                              |
| `sendDownloadLink`                                       | Envoyer au(x) destinataire(s) un lien de téléchargement des documents signés en fin de parapheur.                                                                                                                                                                |
| `hideAttachments`                                        | Cacher l'ensemble des pièces jointes au(x) signataire(s) ou validateur(s) de l'étape.                                                                                                                                                                            |
| `viewConfidentialAttachments`                            | Afficher les pièces jointes marquées confidentielles au(x) signataire(s) ou validateur(s) de l'étape.                                                                                                                                                            |
| `hideWorkflowRecipients`                                 | Masquer au(x) destinataire(s) de l'étape les autres destinataires.                                                                                                                                                                                               |
| `requireSupportingDocuments` / `supportingDocumentsList` | Exiger des pièces justificatives (liste, 5 max). Les pièces justificatives ne sont **pas** signées.                                                                                                                                                              |
| `allowComments`                                          | Autoriser les commentaires sur l'étape.                                                                                                                                                                                                                          |
| `disableMandatoryViewing`                                | Lever l'obligation pour le(s) destinataire(s) de visualiser le(s) document(s) avant de signer ou valider.                                                                                                                                                        |
| `faceToFaceSignature`                                    | Activer la signature **en face à face** (uniquement sur une étape configurée en série), dont la page de consentement est de type OTP mail ou SMS et le signataire est un **contact**. **Cette fonctionnalité n'a de sens qu'en mode interactif via le portail**. |

*(Toutes les durées sont en millisecondes — fondation [*Structure > Formats de données*](/wm/api-reference/structure#formats-de-donnees).)*

## Les destinataires — `recipients` (niveau 3)

Les destinataires d'une **même étape** agissent **en parallèle**. Chaque destinataire est
associé à une **page de consentement** (`consentPageId`), qui fixe le choix **d'un cachet ou
d'une signature des documents et le mode d'authentification du destinataire** (fondation [*Pages de consentement*](/wm/api-reference/concepts/pages-de-consentement)).
On l'identifie de l'une des manières suivantes :

* **par `userId`** — le destinataire est un **utilisateur** (recommandé : son identité est
  reprise de sa fiche, fondation [*Provisionnement des utilisateurs*](/wm/api-reference/concepts/provisionnement-des-utilisateurs)) ;
* **par `contactId`** — le destinataire est un **contact** (fondation [*Provisionnement des utilisateurs > Contacts : des signataires privés à un utilisateur*](/wm/api-reference/concepts/provisionnement-des-utilisateurs#contacts-des-signataires-prives-a-un-utilisateur)) ;
* **par identité en clair** — `email` + `firstName` + `lastName`.

> Contrairement au comportement du portail, qui permet de créer « à la volée » utilisateurs et/ou
> contacts lors de la création d'un parapheur, avec l'API, les utilisateurs et/ou contacts désignés
> doivent **exister au préalable** : l'API ne les crée pas automatiquement. L'**identité en clair**
> reste utilisable, mais elle produit un destinataire **ad hoc**, propre à ce parapheur : il n'est
> **pas enregistré** comme utilisateur ou contact réutilisable. Le détail des règles d'identification (et
> pourquoi `userId` est préférable) est traité dans les cas d'usage.

Autres champs propres au destinataire, utiles voire indispensables :

| Champ                                                                                                    | Rôle                                                                                                                                                                           |
| -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `consentPageId`                                                                                          | **(requis)** Page de consentement : cachet **ou** signature + mode d'authentification (fondation [*Pages de consentement*](/wm/api-reference/concepts/pages-de-consentement)). |
| `userId` / `contactId` / `email`+`firstName`+`lastName`                                                  | Identification du destinataire (voir ci-dessus). On rappelle qu'en mode API il est préférable de provisionner les destinataires en tant qu'utilisateurs.                       |
| `phoneNumber`                                                                                            | Indispensable pour une **signature avancée avec OTP SMS**.                                                                                                                     |
| `country`                                                                                                | Pour une **signature qualifiée** ou bien une **signature avancée avec vérification de pièce d'identité** , le **pays de naissance** est obligatoire.                           |
| `organizationId`                                                                                         | Signer **au nom d'une organisation**.                                                                                                                                          |
| `preferredLocale`                                                                                        | Langue des **e-mails de notification**. *(La langue de la page de consentement, comme celle du portail, est déterminée par la langue du navigateur.)*                          |
| **Très important : au sein d'une étape, il ne peut y avoir 2 destinataires ayant la même adresse mail**. |                                                                                                                                                                                |

## Les observateurs — `watchers` (niveau 4) & les notifications

Deux mécanismes de notification, tous deux **au niveau du parapheur** :

* **`notifiedEvents`** — la liste des événements dont le **gestionnaire** est notifié.
* **`watchers`** — des **observateurs** supplémentaires, chacun avec ses propres
  `notifiedEvents`. *(Null en `SINGLE_SIGNER`.)* Chaque observateur est **soit un utilisateur**
  (`watchers[].userId`), **soit un non-utilisateur désigné par son e-mail** (`watchers[].email`).
  Côté Portail, cela correspond aux deux boutons **« Ajouter un observateur »** (liste
  déroulante des **utilisateurs** → `userId`) et **« Ajouter un CC »** (liste déroulante des
  **contacts** du gestionnaire, **ou** une **adresse e-mail saisie librement**). Dans tous les
  cas, un CC arrive à l'API sous la forme d'un **e-mail** (`watchers[].email`) : le champ
  `contactId` **n'est pas pris en charge** pour un watcher (il est **ignoré silencieusement**,
  l'observateur n'étant alors pas enregistré).

Les valeurs de `notifiedEvents` (mêmes valeurs pour le gestionnaire et pour chaque observateur) sont les suivantes :

* `workflowStarted` : le parapheur est démarré ;
* `recipientFinished` : un destinataire a signé ou validé ;
* `recipientRefused` : un destinataire a refusé de signer ou de valider ;
* `workflowStopped` : le parapheur est arrêté ;
* `workflowFinished` : le parapheur est terminé ;
* `workflowFinishedDownloadLink` : le parapheur est terminé et un lien de téléchargement des fichiers signés avec les pièces jointes a été envoyé ;
* `workflowFinishedDownloadLinkNoAttachment` : le parapheur est terminé et un lien de téléchargement des fichiers signés sans les pièces jointes à été envoyé ;
* `commentCreated` : un commentaire a été déposé (les commentaires peuvent être désactivés au niveau du tenant) ;
* `coManagerAdded` : un cogestionnaire a été ajouté au parapheur (s'appuie sur les modèles) ;
* `coManagerRemoved` : un cogestionnaire a été retiré du parapheur (s'appuie sur les modèles).

Ce sont les mêmes `eventTypes` que les **webhooks** ; la liste exhaustive et la charge utile sont traitées dans la fondation [*Suivi & webhooks*](/wm/guides/integration/suivre-lavancement-du-parapheur).

> **Minimiser les e-mails.** Pour ne laisser au signataire que l'**invitation à signer** :
>
> * mettez **`notifiedEvents: []`** au niveau du parapheur → **aucune** notification e-mail au
>   gestionnaire (ni « un destinataire a signé », ni « parapheur terminé », etc.) ;
> * n'ajoutez **aucun `watchers`** (personne en copie/observateur) ;
> * laissez **`sendDownloadLink: false`** au niveau de l'étape → pas d'e-mail de lien de
>   téléchargement du document signé en fin de parapheur.
>
> L'**invitation** du signataire est, elle, **indépendante** de `notifiedEvents` : elle part au
> **lancement** et se règle via `invitePeriod` / `maxInvites` (section [*Les étapes — steps (niveau 2)*](#les-etapes-steps-niveau-2)). Pour une invitation
> **unique, sans relance**, mettez `maxInvites: 1`.

## Cycle de vie & statuts

Le statut d'un parapheur est porté par `workflowStatus`. Les valeurs **effectivement renvoyées
par l'API** sont :

| `workflowStatus` | Libellé Portail | État                                                                                                                                                                                                                                                                                                                                                                       |
| ---------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `draft`          | Brouillon       | le parapheur existe, mais **rien n'est envoyé** ; c'est ici qu'on **charge les documents** et pose les **champs de signature** (fondation [*Documents & champs de signature*](/wm/guides/integration/uploader-des-documents)). Tant que le parapheur n'est pas complet (au moins 1 étape de signature et au moins 1 document à signer), le parapheur ne peut être démarré. |
| `started`        | Démarré         | la première étape est lancée, les invitations partent, les étapes s'enchaînent.                                                                                                                                                                                                                                                                                            |
| `finished`       | Terminé         | toutes les étapes ont été accomplies — mais le parapheur **reste modifiable** (voir ci-dessous).                                                                                                                                                                                                                                                                           |
| `stopped`        | Arrêté          | le parapheur a été interrompu.                                                                                                                                                                                                                                                                                                                                             |
| `archived`       | Clôturé         | état **définitif et figé** : plus aucune modification n'est possible.                                                                                                                                                                                                                                                                                                      |

> **Deux pièges de vocabulaire à connaître.**
>
> * Le Portail affiche **« Clôturé »**, mais la valeur du champ utilisé en mode API est **`archived`** (pour
>   raisons historiques : ce statut, d'abord nommé « Archivé », a été renommé « Clôturé » côté
>   Portail lors de l'ajout des connecteurs d'archivage, sans changer la valeur de l'API).
> * **`closed` n'est pas un statut** : c'est un **horodatage** (date de clôture). Le statut d'un
>   parapheur clôturé est bien `archived`.

Les transitions `draft` → `started` → `stopped` se font par `PATCH /api/workflows/{id}` avec
`{ "workflowStatus": … }` (concurrence optimiste `If-Match` facultative, fondation [*Structure > Concurrence : l'en-tête conditionnel `If-Match`*](/wm/api-reference/structure#concurrence-len-tete-conditionnel-if-match)) :

1. **Lancer** — `draft` → `started` : la première étape démarre, les premières invitations partent.
2. **Arrêter** — `started` → `stopped`.
3. **Reprendre un cycle** — un parapheur **`finished` ou `stopped` peut être modifié** (par
   exemple pour **ajouter des étapes**) **puis redémarré**. `finished` n'est donc **pas**
   définitif.
4. **Clôturer** (`finished` → `archived`) — c'est le seul état **définitif** (le parapheur est
   figé). La clôture ne se fait **pas** par `PATCH workflowStatus` mais par l'endpoint dédié
   **`POST /api/workflows/{id}/archive`** :

* **archivage local** (par défaut) : l'appel suffit ; les documents sont conservés localement dans l'environnement du Workflow Manager ;
* **archivage externe** (optionnel) : dépose les documents chez un tiers ; nécessite un
  **archiveur** déclaré et l'activation sur le tenant (voir `activateExternalArchive` +
  `externalArchivingParameters`), l'avancement étant suivi via **`externalArchiveStatus`**.

La clôture renseigne l'horodatage `closed` et conditionne la disponibilité définitive du dossier de preuve (voir la fondation [*Documents signés & preuves*](/wm/guides/integration/recuperer-des-documents-signes-et-des-preuves)).

**Horodatages** : `created`, `started`, `stopped`, `finished`, `closed`.
**Suivi** en cours de déroulé : `progress`, `steps[].isStarted` / `steps[].isFinished`, `currentRecipientEmails` / `currentRecipientUsers` (qui doit agir maintenant).

> **Invitations à signer.** L'invitation part **automatiquement** : au **lancement** du parapheur
> (`workflowStatus: started`) **et** à la **fin de chaque étape intermédiaire**. Dans le cas
> normal, vous n'avez donc **rien à appeler** ; les **relances** sont réglées par `invitePeriod` /
> `maxInvites` (section [*Les étapes — steps (niveau 2)*](#les-etapes-steps-niveau-2)). Deux endpoints permettent d'intervenir sur l'invitation —
> `POST /api/workflows/{id}/invite` (obtenir le lien) et `POST /api/workflows/{id}/sendInvite`
> (renvoyer le message de la plateforme) — mais ils répondent à des besoins distincts, détaillés
> juste après. **Tous deux
> exigent un corps `{ "recipientEmail": … }`** identifiant le destinataire et renvoient
> l'`inviteUrl` — *omettre ce corps provoque une erreur HTTP 500*. Leurs erreurs
> métier renseignent sur les conditions : `InvalidWorkflowStatus` (le statut du parapheur
> n'autorise pas l'opération, par exemple parce qu'un administrateur ou un cogestionnaire a
> clôturé le parapheur entre temps), `WorkflowNotFound`, `RecipientNotFound`, et — pour
> `sendInvite` — `InviteAlreadySent`.

**Deux endpoints, deux usages sans rapport entre eux.**

* **`POST /api/workflows/{id}/invite` — obtenir le lien pour l'acheminer soi-même.** L'appel
  fabrique l'invitation et restitue son `inviteUrl` **sans qu'aucun message ne parte**. Associé à
  `maxInvites: 0` (section [*Les étapes — steps (niveau 2)*](#les-etapes-steps-niveau-2)), il donne à l'application le contrôle entier de l'acheminement : c'est le
  mode prévu pour qu'un intégrateur transmette lui-même le lien de signature, par son propre canal
  ou en l'affichant dans son interface.
* **`POST /api/workflows/{id}/sendInvite` — relancer l'invitation de la plateforme.** L'appel
  réexpédie le message d'invitation émis automatiquement, par exemple lorsqu'il s'est perdu ou a
  été supprimé avec les indésirables. C'est l'équivalent, côté API, du bouton de relance dont
  dispose le gestionnaire dans le Portail. Il suppose donc l'envoi automatique (`maxInvites` ≥ 1)
  et n'a pas de sens dans un parcours où l'application gère elle-même le lien.

Le second n'est pas le prolongement du premier : le lien issu de `/invite` est géré par
l'intégrateur, et `/sendInvite` ne s'y applique pas.

**Ce que contient l'`inviteUrl`.** L'adresse est de la forme `https://<plateforme>/invite?token=…`,
où le jeton est un JWT dont la charge utile désigne le parcours : `aud` (toujours `invite`),
`workflowId`, `stepId`, `userId`, `consentVersion` et `iat`. Deux conséquences pratiques :

* **aucune revendication `exp`** n'y figure — la durée de validité n'est pas dans le lien mais
  arbitrée côté serveur par le `validityPeriod` de l'étape et le statut du parapheur ; il est donc
  inutile d'espérer prolonger un accès en manipulant l'URL ;
* le lien est un **porteur** : sa seule détention suffit à se présenter comme le signataire
  désigné. Il ne doit pas être journalisé, ni transiter par une URL de redirection, ni s'afficher
  ailleurs que derrière l'authentification de votre application. L'authentification exigée par la
  page de consentement reste, elle, entièrement en place — voir la fondation [*Règles d'intégration technico-juridiques*](/wm/guides/integration/bonnes-pratiques-juridiques).

La référence propose par ailleurs la **duplication** et la **suppression** d'un parapheur.