# Guide des mises à jour d'intégration

Chaque changement ci-dessous est strictement additif : les points de terminaison existants, les champs de réponse, les codes de statut HTTP, les octets des charges utiles de webhook et l'en-tête historique `Signature` restent inchangés. Les intégrations qui ne font rien continuent de fonctionner exactement comme avant. Adoptez chaque fonctionnalité indépendamment, dans n'importe quel ordre.

Servi en direct à l'adresse https://api.superlabel.ca/api/documentation/integration-updates?lang=fr (`?download=1` pour l'enregistrer). Documents complémentaires : OpenAPI (https://api.superlabel.ca/api/documentation?lang=fr), collection Postman (https://api.superlabel.ca/api/documentation/postman-collection), dictionnaire et flux des statuts (https://api.superlabel.ca/api/documentation/order-status-flow?lang=fr).

---

## 1. Annulation par numéro de suivi (idempotente)

`POST https://api.superlabel.ca/api/v1/orders/cancel` — fournissez exactement l'un de `order_id`, `tracking_number`, `external_tracking_number`.

```json
POST /api/v1/orders/cancel
Authorization: Bearer <token>
{ "external_tracking_number": "WP1234567890" }
```

- Succès : `200 {"result":true,"id":123456,"already_cancelled":false,...}`
- Déjà annulée (nouvelle tentative sans risque) : `200` avec `"already_cancelled": true`
- Le numéro correspond à plusieurs commandes actives : `409` avec `"matched_order_ids": [...]` — réessayez avec `order_id`.
- Le point de terminaison historique `GET /v1/orders/{orderId}/cancel` reste inchangé.

## 2. Flux de réconciliation incrémentale

Balayez tout ce qui a changé dans une fenêtre donnée ; grâce à la pagination par curseur, aucun enregistrement n'est manqué ni compté deux fois.

- `GET https://api.superlabel.ca/api/v1/orders-reconciliation?updated_from=&updated_to=&per_page=&cursor=`
- `GET https://api.superlabel.ca/api/v1/tracking-events/reconciliation?...`

`updated_from` / `updated_to` acceptent des horodatages unix ou des chaînes `Y-m-d H:i:s` dans le fuseau horaire de la plateforme. Suivez `next_cursor` jusqu'à ce que `has_more` soit false ; comparez avec les champs unix `*_timestamp`, jamais avec des chaînes en heure locale. Les éléments d'événements de suivi incluent `occurred_at` / `occurred_timestamp` (heure de survenance métier ; égale à l'heure de création pour les lignes historiques).

## 3. Codes d'erreur lisibles par machine et traçage des requêtes

Les réponses d'erreur à haute fréquence de création/annulation portent désormais un champ `code` stable à côté du `message` inchangé :
`VALIDATION_FAILED`, `MISSING_IDENTIFIER`, `ORDER_NOT_FOUND`,
`ORDER_CANCEL_UNAUTHORIZED`, `ORDER_STATUS_NOT_CANCELLABLE`,
`ORDER_CANCEL_BLOCKED_THIRD_PARTY`, `LABEL_CANCEL_FAILED`,
`DUPLICATE_TRACKING_NUMBER`, `MULTIPLE_ORDERS_MATCHED`.
Les codes sont des identifiants stables — de nouveaux codes peuvent apparaître, les codes existants ne changent jamais de signification. Chaque réponse de l'API renvoie également `X-Request-ID` ; citez-le lorsque vous signalez un problème.

## 4. Améliorations de la détection des doublons

Avec `auto_deduplication=1`, les entrées `exist_package_ref` / `exist_external_tracking_number` d'une création bloquée incluent désormais les `order_id` et `order_ref` existants, et l'enveloppe porte `"duplicate": true`. Mode strict optionnel : envoyez `strict_duplicate_check=1` pour recevoir un HTTP `409` au lieu du `200` + `result:false` historique (omettez l'indicateur pour conserver le comportement historique).

## 5. Options de création par lot

- `per_order_transaction: 1` (au niveau supérieur du corps du lot) : chaque commande est validée indépendamment — un échec n'annule plus les autres commandes du lot. Si le traitement s'interrompt prématurément, vous recevez tout de même les lignes de tout ce qui a été terminé, plus une ligne finale `{"result":false,"batch_aborted":true}`.
- Les lots de plus de 100 commandes reçoivent un en-tête de réponse consultatif `X-Batch-Size-Warning` ; préférez `POST /v1/client/batchOrderCreateAsync` pour les gros volumes.

## 6. Synchronisation des fichiers de preuve de livraison

Les entrées `proofs[]` des réponses de suivi portent désormais également :

```json
{ "url": "...", "full_url": "...", "type": 2,
  "file_id": 234567, "uploaded_at": "2026-07-20 14:30:05",
  "uploaded_timestamp": 1784745005,
  "signed_url": "https://.../files/pod/234567?expires=...&signature=...",
  "signed_url_expires_at": 1784745005 }
```

Utilisez `file_id` comme clé de déduplication / de synchronisation incrémentale. `signed_url` est un lien à expiration (7 jours) — réinterrogez le suivi pour en obtenir un nouveau après expiration. Les liens permanents `url` / `full_url` restent inchangés.

## 7. Webhooks : en-têtes de signature v2 (toutes les livraisons)

Chaque webhook envoie désormais AUSSI, en plus de l'en-tête historique `Signature` inchangé :

| En-tête | Signification |
|---|---|
| `X-Webhook-Event-Id` | UUID, stable entre les nouvelles tentatives — à utiliser pour la déduplication |
| `X-Webhook-Timestamp` | secondes unix au premier envoi |
| `X-Webhook-Signature-V2` | HMAC-SHA256 de `"<timestamp>.<raw body>"` |

Vérification (dans n'importe quel langage) : `expected = HMAC_SHA256(timestamp + "." + raw_body, your_secret)` ; comparez avec l'en-tête en temps constant. L'horodatage est fixé au premier envoi et réutilisé lors des nouvelles tentatives (celles-ci peuvent s'étaler sur environ 3 heures) ; associez donc une fenêtre de tolérance généreuse à une déduplication par `X-Webhook-Event-Id` plutôt qu'une limite de rejeu stricte. Votre vérification existante de l'en-tête historique `Signature` continue de fonctionner sans changement — adoptez la v2 quand vous le souhaitez. Testez les deux signatures contre votre point de terminaison depuis la page du guide des webhooks (`/webhooks-guide`).

## 8. Webhooks : enveloppe de charge utile en opt-in

Définissez `webhook_payload_envelope = 1` dans vos paramètres de webhook pour recevoir, dans le corps JSON des événements de forme objet : `event_id`, `event_time` (ISO8601 avec décalage horaire), `event_timestamp` (unix), plus — le cas échéant — `is_correction: true` (une commande précédemment livrée/remise est rentrée dans le flux) et `occurred_at` / `occurred_timestamp` sur les événements de suivi. Sans cet indicateur, votre charge utile reste identique octet pour octet à ce qu'elle était. Les charges utiles de forme liste (`order.create_async`) ne sont jamais modifiées.

## 9. Nouveaux événements de webhook (URL en opt-in)

- `pod.files_updated` — une photo ou une signature de livraison a été ajoutée ou supprimée a posteriori. Configurez `pod_files_webhook_url`. Charge utile :
  `{"action":"added|removed","order_id":...,"order_ref":...,
  "tracking_number":[...],"external_tracking_number":[...],
  "file":{"file_id":...,"type":1|2,"note":null}, "event_id":..., ...}`
- `order.deleted` — une commande a été définitivement supprimée. Configurez `order_deleted_webhook_url`. Charge utile : `{"action":"deleted","order_id":...,
  "order_ref":...,"tracking_number":[...],"external_tracking_number":[...],
  "event_id":..., ...}`

Ces deux événements incluent toujours les champs de l'enveloppe et ne sont envoyés que lorsque leur URL est configurée.

## 10. Webhooks : options de livraison

- **Plusieurs points de terminaison par événement** : chaque paramètre d'URL de webhook accepte une URL unique (comme avant), une liste séparée par des virgules ou un tableau JSON. Chaque point de terminaison bénéficie de son propre cycle de livraison et de nouvelles tentatives.
- **Vérification TLS** : définissez `webhook_verify_ssl = 1` pour que les appels sortants vérifient votre certificat. La valeur par défaut reste désactivée (comportement historique).
- **order.created pour tous les types de commande** : définissez `order_created_webhook_all_types = 1` pour étendre l'événement de création de commande au-delà des commandes de livraison locale. La valeur par défaut conserve la portée historique.
- **Secrets de signature** : les configurations initiales reçoivent un secret aléatoire robuste ; les secrets existants ne subissent jamais de rotation automatique.

## 11. Portées de jeton d'API et listes d'adresses IP autorisées (optionnel)

Chaque jeton peut être limité à `orders:read`, `orders:write` et/ou `webhooks:manage`, ainsi qu'à une liste d'adresses IP autorisées. Les jetons sans restriction (le comportement par défaut, et tous les jetons préexistants) se comportent exactement comme avant. Un jeton restreint appelant hors de ses portées/adresses IP reçoit un `403`. Contactez le support pour restreindre un jeton.

## 12. Soumission de colis transporteur (Smart Locker)

Les transporteurs externes soumettent des colis dans la zone de préparation d'un entrepôt en un seul appel par lot. Vous pouvez éventuellement joindre un téléphone/e-mail du destinataire afin de le notifier avec un code de retrait une fois le colis déposé dans un casier intelligent. Les champs du destinataire sont facultatifs — l'endpoint reste rétrocompatible.

```json
POST https://api.superlabel.ca/api/v1/inventories/carrier-staging-stockin
Authorization: Bearer <token>
{ "carrier_id": 1, "warehouse_id": 10, "data": [
  { "carrier_reference_number": "TRK1", "ref": "REF1",
    "recipient_phone": "+14165550123", "recipient_email": "r@example.com" }
] }
```

```graphql
mutation($carrierId: Int!, $warehouseId: Int, $packages: Json) {
  submitCarrierPackages(carrierId: $carrierId, warehouseId: $warehouseId, packages: $packages)
}
```

- Authentification : jeton Bearer comme d'habitude. Les comptes clients doivent disposer d'une autorisation de dépôt transporteur (transporteur + entrepôt) ; les comptes client, employé et partenaire utilisent leur propre périmètre d'entrepôt.
- Par colis : member_number et/ou carrier_reference_number selon la configuration du transporteur ; facultatifs carrier_order_id, batch, ref, grid_code (personnel uniquement), recipient_phone, recipient_email.
- Chaque ligne de la réponse renvoie un pickup_code ; le même code est transmis au destinataire dans la notification de retrait.

Le contact du destinataire est stocké chiffré et jamais renvoyé. Lorsque le téléphone et l'e-mail sont fournis, les deux canaux sont notifiés ; le téléphone/e-mail est prioritaire sur la notification in-app par liaison de membre.

## Promesse de compatibilité

Consultez la politique de gestion des changements : réponses strictement additives, nouveaux points de terminaison en parallèle des anciens, corps de webhook figés par défaut, valeurs par défaut jamais modifiées, dépréciations annoncées au moins 30 jours à l'avance avec les en-têtes `Deprecation` / `Sunset`. Ces garanties sont appliquées par des tests de compatibilité automatisés au niveau de l'octet à chaque publication.