> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs.useopenwrench.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Bons de travail dans l'API Acheteur

> Créez, listez, filtrez, réaffectez et clôturez des bons de travail avec l'API Acheteur : actions de statut, notes, étiquettes et types de problèmes.

Les bons de travail sont au centre de l'API Acheteur. Ce guide couvre l'ensemble de la surface sous `/v1/buyer/work_order/` : la création de bons de travail, leur interrogation, les actions de statut côté acheteur, le fil de notes, les étiquettes et les types de problèmes.

Tous les exemples supposent ces variables shell :

```bash theme={null}
export BASE="https://api.useopenwrench.com/api/external"
export KEY="<your-api-key>"        # X-API-KEY header
export SECRET="<shared-secret>"    # OW-KEY header
```

## L'objet bon de travail

Un bon de travail retourné par l'API porte, entre autres champs :

| Champ                                                                | Notes                                                                                                                                                                           |
| -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                                                                 | Id numérique utilisé par tous les autres endpoints.                                                                                                                             |
| `title`, `description`                                               | Ce qu'il faut faire. `descriptionNonFormatted` est la variante en texte brut.                                                                                                   |
| `status`, `displayStatus`                                            | `status` est le statut machine à granularité fine (voir [le modèle de statut](#le-modèle-de-statut)); `displayStatus` est l'étiquette plus grossière affichée dans l'interface. |
| `locationId`, `assetId`, `subAssetIds`, `areaId`                     | Où le travail se déroule et sur quoi il porte.                                                                                                                                  |
| `problemTypeId`, `workCategoryId`, `spendCategoryId`, `woPriorityId` | Classification.                                                                                                                                                                 |
| `supplierFacilityId`, `supplierPrimaryContactEmail`                  | Le fournisseur affecté, une fois réparti.                                                                                                                                       |
| `nte`, `price`, `currencyId`                                         | Montant à ne pas dépasser et tarification.                                                                                                                                      |
| `scheduledAt`, `estimatedCompletionDate`, `dueDate`, `completedAt`   | Dates clés.                                                                                                                                                                     |
| `notes`, `lastNote`, `lastNoteAddedBy`, `lastNoteAddedAt`            | Fil de notes acheteur-fournisseur. `lastNoteAddedAt` est en millisecondes epoch.                                                                                                |
| `associatedServiceCalls`, `lastServiceCall`                          | Visites enregistrées par le fournisseur. Voir [Appels de service](/fr-CA/buyer-api/service-calls).                                                                              |
| `statusChanges`                                                      | Historique complet des statuts.                                                                                                                                                 |
| `buyerAttachments`, `supplierAttachments`                            | Références de fichiers. Voir [Fichiers et pièces jointes](/fr-CA/buyer-api/files-and-attachments).                                                                              |
| `isPM`, `plannedMaintenanceScheduleId`                               | Défini lorsque le bon de travail a été généré à partir d'un calendrier d'entretien préventif.                                                                                   |
| `walkThroughId`                                                      | Défini lorsque le bon de travail est issu d'une visite d'inspection de site.                                                                                                    |

## Créer un bon de travail

`POST /v1/buyer/work_order/work_orders` exige plus que les champs évidents. Contrairement à la plupart des endpoints acheteur, **`buyerFacilityId`, `buyerCompanyId` et `createdBy` doivent être fournis dans le corps**; ils ne sont pas dérivés de votre clé d'API sur cet endpoint. Utilisez [`GET /v1/buyer/me`](/fr-CA/buyer-api/account-and-utilities) pour rechercher une fois vos ids d'entreprise et d'établissement et les mettre en cache.

Champs requis : `title`, `locationId`, `problemTypeId`, `buyerFacilityId`, `buyerCompanyId` et `createdBy` (le courriel du contact créateur).

```bash theme={null}
curl -X POST "$BASE/v1/buyer/work_order/work_orders" \
  -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Walk-in cooler not holding temperature",
    "description": "Temp reading 48F, product at risk.",
    "locationId": 1204,
    "assetId": 5511,
    "problemTypeId": 17,
    "woPriorityId": 3,
    "nte": 500,
    "buyerFacilityId": 88,
    "buyerCompanyId": 12,
    "createdBy": "ops@example.com",
    "supplierFacilityId": 3021
  }'
```

Comportement à connaître :

* **Statut initial.** Si `status` est omis, le statut initial est calculé à partir de la configuration de votre entreprise. Les demandes de service commencent généralement en `PendingApproval`; les bons de travail sont par défaut `Unassigned`. Si vous passez un `status`, il est tout de même résolu par rapport à la configuration de l'entreprise, alors le statut effectif peut différer de ce que vous avez envoyé.
* **Répartition à la création.** Passer `supplierFacilityId` affecte le fournisseur immédiatement. Un `supplierFacilityId`, `assetId` ou `problemTypeId` inconnu est rejeté avec `400`.
* **Sous-actifs.** `subAssetIds` est un tableau optionnel d'ids de sous-actifs attachés en plus de l'`assetId` principal. Les sous-actifs sont des actifs créés avec un `parentId`; voir [Actifs](/fr-CA/buyer-api/assets-and-locations#actifs).
* **Drapeau d'approbation.** Le champ est `needApproval`, pas `needsApproval`. L'objet de réponse utilise `needsApproval`; la requête de création utilise `needApproval`.
* **Liaison à une visite d'inspection.** `walkThroughId` et `siteSurveyTaskTitleId` doivent être fournis ensemble ou pas du tout. Voir [Visites d'inspection de site](/fr-CA/buyer-api/site-survey-walkthroughs).
* **Upserts.** Passer un `id` met à jour ce bon de travail existant au lieu d'en créer un nouveau.

## Lister, filtrer et compter

```bash theme={null}
# Most recent work orders for one location
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  "$BASE/v1/buyer/work_order/work_orders?locationId=1204&limit=25&sort_by=createdAt&order=desc"

# How many match, without fetching them
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  "$BASE/v1/buyer/work_order/work_orders/count_by?locationId=1204"
```

Les endpoints de liste prennent `offset`, `limit` (par défaut 10, maximum 25), `sort_by` et `order`. Tout autre paramètre de requête est traité comme un filtre de champ; séparez une valeur par une virgule pour correspondre à plusieurs (`status=Unassigned,PendingApproval`). Les filtres se combinent toujours avec la portée de locataire dérivée de votre clé, donc vous ne voyez jamais que les bons de travail de votre entreprise.

La liste et le comptage déterminent quels bons de travail correspondent dans l'index de recherche d'OpenWrench, puis chargent les enregistrements complets depuis la base de données. Cela change quelques comportements :

* **Recherche plein texte.** `search=` correspond aux mots (avec correspondance par préfixe et par radical) dans le titre, la description, le nom de l'emplacement, les notes, les notes d'arrivée et de départ des appels de service, et le nom du type de problème. Il correspond aussi aux numéros de référence comme le numéro de bon de travail, le numéro de bon de commande et le numéro de série d'actif. Mettez la valeur entre guillemets (`search="walk-in cooler"`) pour exiger la phrase exacte.
* **Les filtres d'actif incluent les sous-actifs.** `assetId=` et `assetIds=` correspondent aux bons de travail dont l'actif principal *ou* n'importe quel sous-actif est l'id donné.
* **Tri.** `sort_by` prend en charge `createdAt`, `locationName`, `woPriority` (selon le délai de résolution attendu de la priorité) et `lastServiceCallServiceScheduledAt`. Toute autre valeur, ou l'absence de `sort_by`, trie par `createdAt` décroissant.
* **Les filtres non indexés sont ignorés.** `updatedAtStartDate`, `updatedAtEndDate`, `buyerFacilityId` et `walkthroughId` ne figurent pas dans l'index de recherche et ne restreignent plus les résultats. Filtrez plutôt sur des fenêtres `statusChangedAt` ou d'autres colonnes indexées.
* **Fraîcheur.** Les mises à jour de l'index de recherche et du réplica accusent un léger retard sur les écritures, alors un bon de travail créé il y a quelques millisecondes peut être brièvement absent des résultats de liste et des comptages.
* **Profondeur de pagination.** `offset + limit` ne peut pas dépasser la fenêtre de résultats de recherche de 10 000. Resserrez le filtre plutôt que de paginer aussi profondément.

L'endpoint de comptage exécute la même requête d'index de recherche que la liste, alors un comptage concorde toujours avec la liste qu'il décrit.

Récupérez un bon de travail avec `GET /v1/buyer/work_order/work_orders/{id}`.

<Warning>
  **Utilisez la liste pour interroger, pas pour surveiller les changements.** Si votre intégration doit savoir quand des bons de travail sont créés, changent de statut ou reçoivent une nouvelle note, enregistrez un [webhook](/fr-CA/buyer-api/webhooks). Récupérez par id le bon de travail nommé dans chaque événement. Sonder l'endpoint de liste selon un horaire est lent sur les gros comptes, dépense votre limite de débit et manque quand même les changements entre les sondages. Réservez les appels de liste aux requêtes ponctuelles, au chargement initial unique et à une réconciliation occasionnelle étroitement filtrée (fenêtre `statusChangedAt`, petit `limit`).
</Warning>

## Réaffecter un fournisseur

`PATCH /v1/buyer/work_order/work_orders/{id}` est délibérément restreint : **seuls `supplierFacilityId` et `supplierPrimaryContactEmail` sont lus depuis le corps**. Tous les autres champs que vous envoyez sont silencieusement ignorés plutôt que rejetés.

```bash theme={null}
curl -X PATCH "$BASE/v1/buyer/work_order/work_orders/9001" \
  -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "supplierFacilityId": 3055, "supplierPrimaryContactEmail": "dispatch@newsupplier.com" }'
```

Deux pièges :

* `supplierPrimaryContactEmail` ne s'applique que dans le cadre d'une réaffectation. L'envoyer sans changement d'établissement fournisseur rend l'ensemble du patch inopérant : rien n'est enregistré et le bon de travail courant est retourné.
* Un id inexistant et un refus de permission renvoient tous deux la même réponse `400` non autorisée, alors n'utilisez pas cet endpoint pour sonder l'existence d'un bon de travail.

Pour choisir le bon fournisseur de manière programmatique, voir [Réseau de fournisseurs](/fr-CA/buyer-api/supplier-network), qui couvre l'endpoint classé du réseau privé.

## Actions de statut acheteur

Quatre endpoints dédiés font progresser un bon de travail à travers les parties du cycle de vie appartenant à l'acheteur. Chacun prend le même corps : l'`id` du bon de travail et une `note` optionnelle qui est ajoutée au fil en même temps que le changement de statut.

| Endpoint                                             | Statut résultant           | Effets secondaires                                                                                                                                                         |
| ---------------------------------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST .../status_update/work_reviewed_and_completed` | `WorkReviewedAndCompleted` | Peut publier le brouillon de facture du fournisseur (selon les paramètres du fournisseur) et remplir les demandes d'achat liées.                                           |
| `POST .../status_update/cancelled`                   | `CancelledWithReason`      | Rejetée avec `409` pendant qu'un technicien est sur place, si votre entreprise active le [verrou d'annulation](#verrou-dannulation-pendant-quun-technicien-est-sur-place). |
| `POST .../status_update/work_unsatisfactory`         | `WorkUnsatisfactory`       | Envoie la note jointe au fournisseur.                                                                                                                                      |
| `POST .../status_update/reopen`                      | Rouvert                    | Envoie la note jointe.                                                                                                                                                     |

```bash theme={null}
curl -X POST "$BASE/v1/buyer/work_order/work_orders/status_update/work_reviewed_and_completed" \
  -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "id": 9001,
    "note": {
      "text": "Verified on site, closing out.",
      "noteAddedBy": "ops@example.com",
      "noteAddedAt": "2026-08-21T09:00:00.000-07:00"
    }
  }'
```

Chaque action de statut retourne le bon de travail mis à jour dans l'enveloppe standard.

### Verrou d'annulation pendant qu'un technicien est sur place

Les entreprises peuvent activer un verrou d'annulation qui garde les bons de travail ouverts pendant qu'un technicien est sur place. Avec le verrou activé, OpenWrench rejette toute annulation avec `409 Conflict` si un technicien est activement arrivé (check-in) sur l'un des appels de service du bon de travail. Cela couvre les visites du bon de travail lui-même et les visites de ses bons de travail sous-traités. OpenWrench bloque de la même façon l'annulation d'un sous-contrat dont le statut se propage au bon de travail racine, et n'enregistre rien sur aucun des deux bons.

Le verrou se configure par entreprise acheteuse avec deux paramètres :

| Paramètre                          | Par défaut | Effet                                                                                                                                                                     |
| ---------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`                          | `false`    | Active le verrou. Désactivé (la valeur par défaut), les arrivées ne bloquent jamais les annulations.                                                                      |
| `checkInConsideredStaleAfterHours` | `24`       | Une arrivée ouverte plus ancienne que ce nombre d'heures est traitée comme un départ oublié, pas comme du travail en cours, et cesse de bloquer l'annulation d'elle-même. |

Le message d'erreur `409` identifie le technicien sur place par son courriel lorsque la visite l'a enregistré :

```json theme={null}
{
  "message": "You can’t cancel this work order: technician tech@supplier.com is currently checked in."
}
```

Quand votre intégration reçoit ce `409`, attendez que le technicien enregistre son départ (ou que l'arrivée devienne périmée) et réessayez, ou demandez au fournisseur de terminer la visite d'abord. Le verrou fait partie de la configuration des bons de travail de votre entreprise acheteuse dans OpenWrench.

## Le modèle de statut

Valeurs de `status` que vous verrez et définirez via l'API :

| Statut                                             | Propriétaire | Signification                                                                                                                                                                                                                    |
| -------------------------------------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Unassigned`                                       | Système      | Créé, aucun fournisseur affecté pour l'instant.                                                                                                                                                                                  |
| `PendingApproval`                                  | Acheteur     | En attente d'approbation interne, ou retourné ici après un refus de fournisseur.                                                                                                                                                 |
| `SupplierInitiatedPendingApproval`                 | Acheteur     | Un fournisseur a ouvert ce bon de travail de lui-même; il attend votre approbation avant que le fournisseur y soit confirmé (ignoré lorsque votre entreprise approuve automatiquement le travail à l'initiative du fournisseur). |
| `ConfirmedByServiceProvider`                       | Fournisseur  | Le fournisseur a accepté le travail.                                                                                                                                                                                             |
| `TechAssigned`, `TechScheduled`, `TechRescheduled` | Fournisseur  | Appel de service créé ou (re)planifié.                                                                                                                                                                                           |
| `TechWorkingOnSite`                                | Fournisseur  | Technicien arrivé sur place.                                                                                                                                                                                                     |
| `PartsRequested`, `PartsOnOrder`, `PartsReceived`  | Fournisseur  | Approvisionnement de pièces en cours.                                                                                                                                                                                            |
| `WaitingForReview`                                 | Fournisseur  | Travail terminé, en attente de votre révision.                                                                                                                                                                                   |
| `WorkReviewedAndCompleted`                         | Acheteur     | Vous avez révisé et clôturé le travail.                                                                                                                                                                                          |
| `WorkUnsatisfactory`                               | Acheteur     | Vous avez refusé le travail complété.                                                                                                                                                                                            |
| `CancelledWithReason`                              | Acheteur     | Annulé.                                                                                                                                                                                                                          |

Les transitions appartenant au fournisseur arrivent via sa propre intégration ou les applications OpenWrench; votre côté les observe via les [webhooks](/fr-CA/buyer-api/webhooks) ou le sondage (`statusChangedAt`, `statusChanges`) et agit sur celles qui vous appartiennent.

## Notes

Les bons de travail portent un fil de notes partagé entre acheteur et fournisseur.

**Ajouter** avec `PATCH /v1/buyer/work_order/work_orders/append_notes`. Le corps est `{ "id": <woId>, "note": { ... } }` où la note a besoin de `text` et `noteAddedBy`. Le serveur écrase `noteAddedAt` avec sa propre horloge, et le courriel de l'auteur est ajouté à la liste des abonnés acheteur du bon de travail afin qu'il reçoive les notifications subséquentes.

```bash theme={null}
curl -X PATCH "$BASE/v1/buyer/work_order/work_orders/append_notes" \
  -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "id": 9001,
    "note": {
      "text": "Access code for the back door is 4417.",
      "noteAddedBy": "ops@example.com",
      "noteAddedAt": "2026-08-21T09:00:00.000-07:00"
    }
  }'
```

**Étiqueter des personnes sur une note** en ajoutant `taggedUsers` à côté de `note` : une liste de courriels de contacts à @mentionner. OpenWrench intègre chaque courriel dans `note.elements` comme un élément `user`, la même forme que les applications écrivent pour une @mention, vous n'avez donc pas à construire la structure `elements` vous-même. Les contacts étiquetés sont ajoutés à la liste des abonnés du bon de travail s'ils ne sont pas déjà abonnés.

```bash theme={null}
curl -X PATCH "$BASE/v1/buyer/work_order/work_orders/append_notes" \
  -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "id": 9001,
    "note": {
      "text": "Access code for the back door is 4417.",
      "noteAddedBy": "ops@example.com",
      "noteAddedAt": "2026-08-21T09:00:00.000-07:00"
    },
    "taggedUsers": ["tech@supplier.com", "manager@example.com"]
  }'
```

Règles de `taggedUsers` :

* Les courriels sont épurés et mis en minuscules avant la correspondance. Une note peut mentionner au plus 25 utilisateurs.
* Les courriels en double dans la liste, et les utilisateurs déjà étiquetés dans `note.elements`, sont ignorés plutôt que mentionnés deux fois.
* Une entrée qui n'est pas un courriel valide, ou une liste de plus de 25 courriels, est rejetée avec un `400` de type `invalidInputDataException`. Rien n'est persisté.
* Une liste vide est ignorée. Envoyer `taggedUsers` sans objet `note` est rejeté avec `400`.

**Ajouter des photos en lot** avec `PATCH /v1/buyer/work_order/work_orders/append_notes/bulk`. Utilisez-le lorsque vous avez un lot de photos à publier (le jeu avant/après d'un technicien, par exemple) : les abonnés reçoivent une seule notification groupée au lieu d'une notification par photo. Le corps est `{ "id": <woId>, "notes": [ ... ] }` avec 1 à 25 notes, et chaque note doit porter une URL `photo` et aucun autre contenu : `text` doit être vide et `video`, `audio`, `otherFile` et `elements` doivent être absents. Répéter la même URL de photo dans une requête est rejeté avec `400`. Le serveur horodate chaque note du lot avec le même `noteAddedAt` et préserve l'ordre d'envoi.

```bash theme={null}
curl -X PATCH "$BASE/v1/buyer/work_order/work_orders/append_notes/bulk" \
  -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "id": 9001,
    "notes": [
      { "text": "", "photo": "https://cdn.example.com/wo-9001/before.jpg" },
      { "text": "", "photo": "https://cdn.example.com/wo-9001/after.jpg" }
    ]
  }'
```

**Lire** avec `GET /v1/buyer/work_order/work_order_notes/{woId}`. Cela retourne uniquement le fil racine acheteur-fournisseur (les fils sous-traitant et interne sont séparés), et la lecture marque les notes comme lues pour votre contact. Une lecture refusée retourne une liste vide plutôt qu'une erreur.

## Étiquettes

Les étiquettes sont des marqueurs légers que votre équipe définit dans l'application OpenWrench (un nom et une couleur optionnelle). Via l'API, vous pouvez lire le catalogue et remplacer les étiquettes appliquées à un bon de travail. La création et la modification des étiquettes elles-mêmes restent dans l'application.

**Parcourir le catalogue** avec `GET /v1/buyer/work_order/work_order_labels`, ou en récupérer une avec `GET /v1/buyer/work_order/work_order_labels/{id}`. La liste est restreinte aux étiquettes de votre entreprise et paginée à 10 par page par défaut. Elle accepte les filtres `search` et `label` sur le texte de l'étiquette. Passez `no_pagination=true` pour récupérer tout le catalogue en un seul appel (le tri s'applique toujours).

```bash theme={null}
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  "$BASE/v1/buyer/work_order/work_order_labels?no_pagination=true"
```

**Remplacer les étiquettes d'un bon de travail** avec `PUT /v1/buyer/work_order/work_orders/{woId}/labels`. Le corps est `{ "ids": [...] }` et il s'agit d'un remplacement complet : les étiquettes non listées sont retirées, et un tableau vide les efface toutes. La réponse liste les associations d'étiquettes désormais actives sur le bon de travail.

```bash theme={null}
curl -X PUT "$BASE/v1/buyer/work_order/work_orders/9001/labels" \
  -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "ids": [4, 12] }'
```

Comportement à connaître :

* Un `ids` manquant ou qui n'est pas un tableau, ou un id qui n'est pas un nombre entier, est rejeté avec `400`.
* Chaque id doit être une étiquette active de votre propre catalogue. Les ids inconnus ou d'un autre locataire répondent `400` avec la liste des ids fautifs.
* L'écriture requiert la permission d'écriture sur les bons de travail. Un id de bon de travail inconnu, supprimé ou étranger répond le même `400` qu'une écriture refusée, pas un `404`.

## Types de problèmes

`GET /v1/buyer/work_order/problem_types` liste les types de problèmes configurés pour votre entreprise. Mettez-le en cache : vous avez besoin d'un `problemTypeId` valide pour chaque bon de travail que vous créez, et l'endpoint classé de fournisseurs en prend un aussi.

```bash theme={null}
curl -H "X-API-KEY: $KEY" -H "OW-KEY: $SECRET" \
  "$BASE/v1/buyer/work_order/problem_types"
```

## Assembler le tout

Une intégration de répartition typique :

1. Mettez en cache `me`, les types de problèmes et les emplacements au démarrage.
2. Créez le bon de travail avec `supplierFacilityId` défini (ou créez non assigné, puis classez les fournisseurs et effectuez l'assignation par `PATCH`).
3. Suivez la progression du fournisseur via les [webhooks](/fr-CA/buyer-api/webhooks) (`workorder.status_update`), en récupérant chaque bon de travail par id à l'arrivée d'un événement. Gardez `GET /work_orders?statusChangedAt=...` comme passe de réconciliation peu fréquente, pas comme signal principal.
4. Lorsque le fournisseur atteint `WaitingForReview`, vérifiez le travail (voir [Appels de service](/fr-CA/buyer-api/service-calls) pour les preuves de visite) et postez `work_reviewed_and_completed`, ou `work_unsatisfactory` avec une note.
5. Réconciliez le côté monétaire via [Soumissions et propositions](/fr-CA/buyer-api/quotes-and-proposals) et [Factures](/fr-CA/buyer-api/invoices).
