> 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.

# Structure

> Conventions transverses : formats de données, réponses d'erreur, versions, concurrence (If-Match), identifiants, recherche et pagination

# Conventions transverses

Les conventions ci-dessous s'appliquent à l'ensemble des endpoints de l'API.

## Formats de données

* Les données structurées sont échangées en **JSON**.
* **Tous les horodatages sont exprimés en millisecondes** depuis le 1ᵉʳ janvier 1970
  (millisecondes, et non secondes — à prendre en compte lors des conversions).
  Exemple : `"created": 1783777360803`.

## Réponses d'erreur

Toute réponse d'erreur est un objet JSON. Le champ **`code`** en identifie la nature de
façon stable : c'est sur lui que votre application doit s'appuyer pour réagir.

```json
{
  "status": 404,
  "error": "Not Found",
  "message": "Request not found.",
  "code": "RequestNotFound"
}
```

| Champ     | Type   | Rôle                                                      |
| --------- | ------ | --------------------------------------------------------- |
| `status`  | Number | Code HTTP.                                                |
| `error`   | String | Libellé HTTP.                                             |
| `message` | String | Message lisible.                                          |
| `code`    | String | **Code stable** — à utiliser pour la logique applicative. |

La réponse comporte aussi deux références de traçabilité :

* `requestId` — identifiant de la requête, utile à communiquer au support.
* `logId` — référence d'un **journal d'exécution** du Workflow Manager.

```json
{ "status": 400, "error": "Bad Request",
  "message": "A recipient in the request is missing identity information.",
  "code": "RecipientInfoMissing",
  "requestId": "88cf2469-9677498", "logId": "log_6VabA4TAYp2GHUj7Yx2sJ9kX" }
```

**À propos de `logId` — à considérer comme une aide au débogage.** Ce journal reflète
l'exécution interne du Workflow Manager ; il n'est **pas destiné à être analysé de façon
programmatique**, et certains incidents ne peuvent être interprétés que par Goodflag. Par
exemple, tenter de faire signer (au format PAdES) un document qui est **déjà signé avec
interdiction de co-signer** produit une erreur **au moment de la signature** — situation
qu'il n'est pas possible de détecter préventivement ; le journal permet alors à Goodflag
d'en établir la cause.

**Recommandation** : brancher la logique métier sur `code` ; transmettre `requestId` et
`logId` au support de Goodflag en cas de blocage inexpliqué, sans chercher à exploiter le
journal vous-même.

Quelques codes que vous pourrez rencontrer :

| HTTP | `code`                  | Situation                                                |
| ---- | ----------------------- | -------------------------------------------------------- |
| 400  | `RecipientInfoMissing`  | Un destinataire est décrit sans identité suffisante.     |
| 403  | `UserDisabled`          | L'utilisateur visé est désactivé.                        |
| 404  | `WorkflowNotFound`      | Le parapheur est introuvable.                            |
| 412  | *(Precondition Failed)* | En-tête `If-Match` fourni mais désynchronisé (voir 1.4). |

## Version de l'application

```http
GET /api/version
```

Renvoie la version de l'application sous forme de chaîne, par exemple `"sgs-wm-webapp:1.20.3"`.

## Concurrence : l'en-tête conditionnel `If-Match`

L'API gère les modifications concurrentes par **concurrence optimiste**, au moyen de
l'en-tête conditionnel `If-Match`, associé à l'`ETag` de l'objet.

* **Lire l'`ETag`** : la réponse d'un `GET` renvoie l'objet et son `ETag` dans les
  en-têtes (exemple : `ETag: "CTTkrQ1JHmhh8GTyW9Cdc3Ws"`).
* **Écrire en sécurité** : renvoyer cet `ETag` dans `If-Match` lors d'un `PATCH` ou d'un
  `DELETE` garantit que vous modifiez bien la version que vous avez lue. Si l'objet a
  changé entre-temps, la plateforme répond `412` : vous relisez, réappliquez, réessayez.
* `If-Match` est **facultatif** : une modification sans cet en-tête est acceptée. Il agit
  comme un garde-fou que vous activez lorsque vous en avez besoin.

**Recommandation** : utiliser `If-Match` dès que plusieurs personnes ou processus peuvent
modifier le même objet, afin de ne pas écraser une modification concurrente.

## Identifiants

Les identifiants sont des chaînes **opaques**, préfixées par le type d'objet :

| Préfixe | Objet                               |
| ------- | ----------------------------------- |
| `act_`  | Jeton d'API                         |
| `ten_`  | Tenant                              |
| `grp_`  | Groupe                              |
| `usr_`  | Utilisateur                         |
| `cop_`  | Page de consentement                |
| `wfl_`  | Parapheur                           |
| `blb_`  | Binaire téléversé (blob)            |
| `doc_`  | Document d'un parapheur             |
| `stp_`  | Étape d'un parapheur                |
| `sip_`  | Profil de signature                 |
| `con_`  | Contact                             |
| `org_`  | Organisation                        |
| `lay_`  | Disposition de métadonnées (layout) |
| `wtm_`  | Modèle de parapheur (template)      |
| `res_`  | Ressource (image…)                  |
| `evi_`  | Fichier de preuve                   |
| `log_`  | Journal d'exécution (débogage)      |

## Recherche & pagination

Les endpoints `Search *` acceptent : `text` (recherche plein texte), `items.<champ>`
(filtres par champ, par ex. `items.name`, `items.userId`, `items.email`), `sortBy`,
`sortOrder`, `itemsPerPage` (**maximum 50**), `pageIndex`. La réponse contient un tableau
**`items`**.