# Codes d’événements de suivi

Généré en direct sur https://api.superlabel.ca/api/documentation/tracking-events?lang=fr à partir de la table dictionnaire `tracking` déployée (quels codes d’état existent et s’ils sont visibles par le client), des clés TrackingEvent et des chaînes de description localisées `tracking.*`. Toujours à jour avec la base de données de cet environnement.

## Côté d’événement, pas type de commande

Ce dictionnaire n’est **pas** une liste de types de commande. Une même commande peut émettre des événements côté ramassage et côté livraison — par ex. une livraison avec arrêt de collecte, peer-to-peer (deux étapes), transfert multi-étapes ou passage entrepôts. Instant Deliver utilise un dictionnaire distinct (non listé ici). Chaque événement de suivi porte un **côté** (ramassage ou livraison) qui choisit la description et la visibilité pour ce statut. Le `status_id` numérique et la `key` stable correspondent à `tracking_event_status_id` / `tracking_event_key` dans les charges utiles API et webhooks ; basez la logique sur ces champs (et le côté si le libellé compte), jamais sur le type de commande ni sur le texte de description localisé.

## Visibilité client (`tracking.visible`)

La page de suivi publique et l’API de suivi publique n’affichent que les événements dont la ligne de dictionnaire a `tracking.visible = 1`, joints sur le code d’état **et** le côté d’événement (le même côté marqué sur l’événement). Les statuts marqués **Non** existent toujours dans le système (webhooks, historique d’opérations, outils internes) mais sont masqués de la timeline destinée au client. La visibilité est lue en direct dans la table `tracking` de ce déploiement.

## Événements côté livraison

Statuts utilisés lorsqu’un événement de suivi est du **côté livraison** du parcours (dépôt / dernier kilomètre). S’applique aux commandes livraison pure, à l’étape livraison du peer-to-peer, à la livraison avec ramassage, au multi-étapes et flux similaires — **pas seulement** aux « commandes livraison pure ». **Visible client** est `tracking.visible` pour ce statut de ce côté.

| status_id | key | otep | otep phase | visible client | description |
|---|---|---|---|---|---|
| 100 | `information_submitted` | `information_submitted` | `pre_shipment` | Oui | Vos informations d'expédition ont été soumises. |
| 110 | `booking_confirmed` | `booking_confirmed` | `pre_shipment` | Oui | Votre envoi a été confirmé. |
| 120 | `awaiting_pickup` | `awaiting_pickup` | `pre_shipment` | Oui | Votre colis est en attente de ramassage. |
| 200 | `pushed_successful` | — | — | Non | Votre commande a été envoyée à la planification d’itinéraire. |
| 201 | `pushed_failed` | — | — | Non | Votre commande n’a pas pu être envoyée à la planification d’itinéraire. Elle sera réessayée ou replanifiée. |
| 300 | `received` | `received` | `inbound` | Oui | Votre colis est bien arrivé à {warehouse_name}. |
| 301 | `arrival_scan` | `arrival_scan` | `inbound` | Oui | Votre colis a été récupéré et est arrivé à {warehouse_name}. |
| 400 | `planned` | `in_transit` | `transit` | Non | Votre colis est chargé et prêt à être livré. |
| 401 | `removed_from_route` | `removed_from_route` | `exception` | Non | Votre livraison sera bientôt reprogrammée. Veuillez attendre une mise à jour. |
| 402 | `route_cancelled` | `route_cancelled` | `exception` | Non | Le statut de votre livraison sera bientôt mis à jour. |
| 430 | `in_transit` | `in_transit` | `transit` | Oui | Votre colis est en transit. |
| 431 | `on_hold` | `in_transit` | `transit` | Oui | Votre colis est temporairement en attente. Nous vous tiendrons informé prochainement. |
| 432 | `customs_clearance` | `in_transit` | `transit` | Oui | Votre colis est en cours de dédouanement. |
| 433 | `loaded` | `package_outbound` | `transit` | Oui | Votre colis a été chargé et partira prochainement. |
| 434 | `collection_on_hold` | `awaiting_pickup` | `pre_shipment` | Oui | La collecte de votre colis est temporairement en attente. Nous vous tiendrons informé prochainement. |
| 435 | `facility_received` | `in_transit` | `transit` | Oui | Votre colis a été reçu par le centre de traitement. |
| 436 | `arrived_at_facility` | `in_transit` | `transit` | Oui | Votre colis est arrivé dans un centre de traitement. |
| 450 | `start_delivery` | `out_for_delivery` | `out_for_delivery` | Oui | Votre colis est actuellement en cours de livraison. |
| 470 | `at_device` | `awaiting_pickup` | `pre_shipment` | Oui | Votre colis vous attend dans une consigne automatique. |
| 471 | `device_picked_up` | `delivered` | `delivered` | Oui | Votre colis a été retiré de la consigne automatique. |
| 472 | `device_expired` | `awaiting_pickup` | `pre_shipment` | Oui | Votre colis n'a pas été retiré avant la date limite et se trouve toujours dans la consigne automatique. |
| 473 | `device_removed` | `received` | `inbound` | Oui | Votre colis a été sorti de la consigne automatique par le personnel. |
| 500 | `deliver_success` | `delivered` | `delivered` | Oui | Votre colis a été livré avec succès. Merci ! |
| 501 | `need_rescheduled` | `delivery_rescheduled` | `exception` | Oui | Malheureusement, nous n'avons pas pu livrer votre colis. |
| 502 | `redelivered_later` | `delivery_rescheduled` | `exception` | Oui | Malheureusement, nous n'avons pas pu livrer votre colis. |
| 503 | `not_delivered` | `delivery_failed` | `exception` | Oui | Un problème est survenu lors de la livraison. Veuillez contacter notre service client. |
| 504 | `partial_deliver_success` | — | — | Oui | Ce colis a été livré. Les autres colis de votre envoi sont encore en route. |
| 510 | `pickuped` | `picked_up` | `pickup` | Oui | Le colis a été récupéré avec succès par notre coursier. |
| 800 | `package_outbound` | `package_outbound` | `transit` | Oui | Votre colis a quitté {warehouse_name}. |

## Événements côté ramassage

Statuts utilisés lorsqu’un événement de suivi est du **côté ramassage** du parcours (étape de collecte). S’applique aux commandes ramassage pure, à l’étape ramassage du peer-to-peer, à la livraison avec ramassage, au multi-étapes et flux similaires — **pas seulement** aux « commandes ramassage pure ». **Visible client** est `tracking.visible` pour ce statut de ce côté.

| status_id | key | otep | otep phase | visible client | description |
|---|---|---|---|---|---|
| 100 | `information_submitted` | `information_submitted` | `pre_shipment` | Oui | Votre demande de colis a été reçue avec succès. |
| 110 | `booking_confirmed` | `booking_confirmed` | `pre_shipment` | Oui | Votre demande de ramassage a été confirmée. |
| 120 | `awaiting_pickup` | `awaiting_pickup` | `pre_shipment` | Oui | Votre colis est en attente de ramassage. |
| 200 | `pushed_successful` | — | — | Non | Votre commande de ramassage a été envoyée à la planification d’itinéraire. |
| 201 | `pushed_failed` | — | — | Non | Votre commande de ramassage n’a pas pu être envoyée à la planification d’itinéraire. Elle sera réessayée ou replanifiée. |
| 300 | `received` | `received` | `inbound` | Oui | Nous avons reçu votre colis à notre installation. |
| 301 | `arrival_scan` | `arrival_scan` | `inbound` | Oui | Order a-scan |
| 400 | `planned` | `in_transit` | `transit` | Non | Votre colis est actuellement en cours de traitement. |
| 401 | `removed_from_route` | `removed_from_route` | `exception` | Non | La collecte de votre colis sera bientôt reprogrammée. |
| 402 | `route_cancelled` | `route_cancelled` | `exception` | Non | Le statut de la collecte sera bientôt mis à jour. |
| 430 | `in_transit` | `in_transit` | `transit` | Oui | Votre colis est en transit. |
| 431 | `on_hold` | `in_transit` | `transit` | Oui | Votre colis est temporairement en attente. Nous vous tiendrons informé prochainement. |
| 432 | `customs_clearance` | `in_transit` | `transit` | Oui | Votre colis est en cours de dédouanement. |
| 433 | `loaded` | `package_outbound` | `transit` | Oui | Votre colis a été chargé et partira prochainement. |
| 434 | `collection_on_hold` | `awaiting_pickup` | `pre_shipment` | Oui | La collecte de votre colis est temporairement en attente. Nous vous tiendrons informé prochainement. |
| 435 | `facility_received` | `in_transit` | `transit` | Oui | Votre colis a été reçu par le centre de traitement. |
| 436 | `arrived_at_facility` | `in_transit` | `transit` | Oui | Votre colis est arrivé dans un centre de traitement. |
| 450 | `start_delivery` | `out_for_delivery` | `out_for_delivery` | Oui | Un coursier est en route pour récupérer votre colis. |
| 470 | `at_device` | `awaiting_pickup` | `pre_shipment` | Oui | Votre colis vous attend dans une consigne automatique. |
| 471 | `device_picked_up` | `delivered` | `delivered` | Oui | Votre colis a été retiré de la consigne automatique. |
| 472 | `device_expired` | `awaiting_pickup` | `pre_shipment` | Oui | Votre colis n'a pas été retiré avant la date limite et se trouve toujours dans la consigne automatique. |
| 473 | `device_removed` | `received` | `inbound` | Oui | Votre colis a été sorti de la consigne automatique par le personnel. |
| 500 | `deliver_success` | `delivered` | `delivered` | Oui | Votre colis a été récupéré avec succès. |
| 501 | `need_rescheduled` | `delivery_rescheduled` | `exception` | Oui | La collecte du colis a été reprogrammée. Vous recevrez bientôt le nouveau planning. |
| 502 | `redelivered_later` | `delivery_rescheduled` | `exception` | Oui | La collecte du colis a été reprogrammée. Vous recevrez bientôt le nouveau planning. |
| 503 | `not_delivered` | `delivery_failed` | `exception` | Oui | Un problème est survenu avec votre colis. Veuillez contacter notre service client. |
| 504 | `partial_deliver_success` | — | — | Oui | Ce colis a été collecté. Les autres colis de votre envoi seront collectés prochainement. |
| 510 | `pickuped` | `picked_up` | `pickup` | Oui | Votre colis a été récupéré avec succès. |
| 800 | `package_outbound` | `package_outbound` | `transit` | Oui | Votre colis a quitté {warehouse_name}. |

Les colonnes **otep** / **otep phase** sont générées en direct depuis `OTEPStatusInput::FROM_TRACKING_EVENT` et `PHASES` — le même pont que l’API publique de suivi écrit en `otep_status` sur chaque événement. Un tiret (—) signifie qu’aucun code OTEP n’existe dans le profil parcel (ex. push de routage 200/201) ; l’événement est quand même stocké et peut rester visible client si `visible = 1`.

## Créer votre propre page de suivi

Utilisez l’**API publique de suivi** pour une page à votre marque sur votre site ou application — sans connexion ni jeton. Le même point d’accès alimente la page intégrée et l’opération GraphQL `trackingPublic`. Combinez-le avec le dictionnaire de statuts de cette page et les schémas de flux ci-dessous.

### 1. Appeler le point d’accès public

Un GET par numéro de suivi. La recherche couvre les numéros Superroute, externes et certains numéros tiers sans id de fournisseur.

```
GET https://api.superlabel.ca/api/v1/tracking/{tracking_number}
```

- No authentication — public, rate-limited with the rest of the API.
- Path parameter: the Superroute tracking number, external tracking number, or (when applicable) third-party tracking number without a third-party provider id.
- HTTP **200** with `"result": true` when found; **404** with `"result": false` when not found or the order is cancelled.

### 2. Choisir la langue des descriptions

Les textes `description` suivent la locale de la requête via `Accept-Language`. Envoyez un code projet (`en`, `chs`, `fr`, …) ou un alias comme `zh-CN`. Sans en-tête, la locale par défaut s’applique.

```
Accept-Language: chs
Accept-Language: zh-CN
Accept-Language: de
```

### 3. Champs de réponse à afficher

Seule la surface publique est renvoyée — les adresses complètes expéditeur/destinataire **ne** sont **pas** incluses (uniquement sur l’endpoint interne authentifié).

| field | meaning |
|---|---|
| `result` | `true` when a live order was found |
| `data` | Event timeline (newest first) |
| `data[].tracking_event_status_id` | Numeric code — match the dictionary on this page |
| `data[].otep_status` | Open tracking code when mapped (same bridge as the **otep** column) |
| `data[].description` | Localized customer text for this event |
| `data[].updated_at` / `timestamp` / `updated_at_localized` | When it happened (UTC string, unix, local clock) |
| `data[].location_*` / `operation_location` | Where it happened, when known |
| `data[].reason` | Public return/failure reason text when present |
| `deliveried` / `returntosender` / `rejectedbyrecipient` | Coarse final-state flags for header chips |
| `postcode` | Normalized delivery postcode (for POD gate on your side if you need it) |
| `proofs[]` | Signature / photo files (`url`, `full_url`, `signed_url`, `type`, `file_id`) |
| `is_third_party_tracking` / `third_party_info` | Present when a label/carrier timeline was merged in |

### 4. Flux d’interface recommandé

1. Collectez le numéro auprès du visiteur et appelez le GET public (optionnellement avec `Accept-Language`).
2. Si `result` est false ou HTTP 404, affichez introuvable et arrêtez.
3. Utilisez `data[0]` (événement le plus récent) pour le statut d’en-tête : texte via `description` ; icônes/progression via `tracking_event_status_id` ou `otep_status`.
4. Affichez toute la liste `data` en chronologie (déjà du plus récent au plus ancien). N’inventez pas d’étapes manquantes.
5. Si `proofs` n’est pas vide et que le dernier statut est un succès (souvent 500 ou 510), proposez « voir la preuve » ; `signed_url` pour un lien temporaire, `full_url` pour le chemin permanent.

### 5. Barres de progression

Ne codez **pas** en dur une seule chaîne pour chaque colis. Utilisez le dictionnaire et les flux de cette page. Branchez sur `otep_status` ou `tracking_event_status_id` ; l’événement le plus récent fait foi.

### 6. Preuve de livraison

`proofs[]` porte les métadonnées photo/signature le cas échéant. Votre page peut encore exiger le code postal avant affichage ; l’API renvoie un `postcode` normalisé. N’affichez pas d’adresses rue complètes sur une page totalement publique.

### 7. Surfaces publiques associées

Choisissez la surface adaptée à votre stack. Toutes sont publiques (sans jeton) sauf indication contraire dans la doc API.

| surface | when to use |
|---|---|
| `GET https://api.superlabel.ca/api/v1/tracking/{tracking_number}` | Default branded tracking page (this guide) |
| GraphQL `trackingPublic(trackingNumber: …)` at `https://api.superlabel.ca/graphql` | Same payload when your stack is GraphQL-first |
| `GET https://api.superlabel.ca/api/v1/otep/trackings/{tracking_number}` | Vendor-neutral OTEP timeline / EPCIS / ONE Record / UN-CEFACT projections |

### 8. Exemples minimaux

```bash
curl -sS -H "Accept-Language: en" \
  "https://api.superlabel.ca/api/v1/tracking/SR1234567890"
```

```javascript
const res = await fetch(`https://api.superlabel.ca/api/v1/tracking/${encodeURIComponent(tn)}`, {
  headers: { "Accept-Language": "chs" },
});
const body = await res.json();
if (!body.result) {
  // show "not found"
} else {
  const events = body.data || [];          // newest first
  const latest = events[0];
  const proofs = body.proofs || [];
  // render latest.description, map latest.tracking_event_status_id or otep_status for the stepper
}
```

## Schémas de flux de suivi courants

Ce sont des **séquences typiques**, pas une machine à états stricte. Les timelines réelles sautent des étapes, ajoutent des exceptions ou entremêlent des événements côté ramassage et livraison sur la même commande. Les numéros sont `tracking_event_status_id` ; la timeline publique n’affiche que `tracking.visible = 1`. Branchez sur `status_id` / `key` et prenez l’événement le plus récent (id le plus élevé) comme référence.

### Entrepôt → livraison last-mile

Chemin flotte propre le plus courant : commande créée, colis reçu en site, chauffeur en tournée, puis succès ou exception. Les codes de planification 400/401/402 existent souvent mais ne sont **pas** visibles client.

```mermaid
flowchart LR
  s100["100 information_submitted"] --> s300["300 received / 301 arrival_scan"]
  s300 --> s450["450 start_delivery"]
  s450 --> s500["500 deliver_success"]
  s450 --> s501["501 need_rescheduled"]
  s450 --> s502["502 redelivered_later"]
  s450 --> s503["503 not_delivered"]
  s450 --> s700["700 rejected_by_recipient"]
  s501 --> s450
  s502 --> s450
```

### Collecte / étape ramassage seule

Le chauffeur part collecter puis enregistre le succès (POD possible) ou une exception de ramassage. Les commandes ramassage pure restent côté ramassage ; les parcours à deux étapes passent côté livraison après 510.

```mermaid
flowchart LR
  s100["100 information_submitted"] --> s460["460 start_pickup"]
  s460 --> s510["510 pickuped"]
  s460 --> s512["512 repickup_later"]
  s460 --> s513["513 not_pickuped"]
  s512 --> s460
```

### Parcours à deux étapes (ramasser puis livrer)

Quand un parcours a collecte et dépôt — livraison avec ramassage, peer-to-peer, beaucoup de multi-étapes. La timeline montre en général d’abord les jalons **côté ramassage** (460 → 510), puis **côté livraison** (450 → 500). Le côté d’événement choisit la description, pas le type de commande.

```mermaid
flowchart LR
  s100["100 information_submitted"] --> pickup["Pickup-side: 460 → 510"]
  pickup --> delivery["Delivery-side: 450 → 500"]
  pickup --> pFail["Pickup exception: 512 / 513"]
  delivery --> dFail["Delivery exception: 501 / 502 / 503 / 700"]
```

### Exécution tiers / transporteur

La réservation transporteur peut émettre 110/120 ; la politique produit les **masque** sur la timeline publique. Les jalons visibles partagés suivent entrepôt + last mile (300/301 → 800 → 450 → 500). L’annulation terminale transporteur utilise 403 (pas 402).

```mermaid
flowchart LR
  s100["100 information_submitted"] --> s110["110 / 120 hidden on public timeline"]
  s110 --> s300["300 / 301 warehouse"]
  s300 --> s800["800 package_outbound"]
  s800 --> s450["450 start_delivery"]
  s450 --> s500["500 deliver_success"]
  s450 --> sFail["501 / 503 / 600 / 700"]
```

### Instant Deliver (dispatch par tâches)

Dictionnaire propre (absent des tableaux ci-dessus). Chemin heureux : soumis → coursier assigné → vers le ramassage → ramassé → en livraison → livré. 411/412 peuvent boucler avant le départ ; 501 après un échec.

```mermaid
flowchart LR
  s100["100 information_submitted"] --> s410["410 rider_assigned"]
  s410 --> s411["411 reassigned optional"]
  s410 --> s412["412 assignment_cancelled"]
  s412 --> s410
  s410 --> s460["460 start_pickup"]
  s460 --> s510["510 pickuped"]
  s510 --> s450["450 start_delivery"]
  s450 --> s500["500 deliver_success"]
  s450 --> s501["501 need_rescheduled"]
```

### Codes d’exception et terminaux (aperçu)

| status_id | key | typical meaning |\n|---|---|---|\n| 501 | need_rescheduled | Delivery failed; needs a new plan |\n| 502 | redelivered_later | Retry on the same route / later attempt |\n| 503 | not_delivered | Delivery problem / failed attempt |\n| 512 | repickup_later | Pickup failed; try again later |\n| 513 | not_pickuped | Pickup problem |\n| 600 | return_to_sender | Returned to shipper |\n| 700 | rejected_by_recipient | Recipient refused |\n| 403 | cancelled | Terminal cancel (distinct from 402 route cancel) |\n| 402 | route_cancelled | Route cancelled / re-plan (usually not customer-visible) |

### Règles empiriques pour les intégrateurs

1. Ancres du chemin heureux : **100** créé, **300/301** en site, **450** en livraison, **500** livré ; ramassage **460** et **510**.
2. Ne supposez pas une chaîne complète fixe — scans optionnels, sauts tiers (800) et changements de côté sont normaux.
3. Les exceptions (501–503, 512–513, 600, 700) peuvent suivre un code « en route… » ; la commande peut revenir en 450/460 après replanification.
4. Ignorez les lignes non visibles sur la page publique ; les webhooks peuvent quand même les envoyer. Préférez toujours l’id d’événement le plus récent pour corriger.

Les espaces réservés tels que `{warehouse_name}` sont remplacés à l’exécution par le vrai nom d’entrepôt ou de lieu. Les nouvelles lignes et les changements de visibilité arrivent par migrations ; la page relit la table à chaque requête et ne peut pas devenir obsolète par rapport à cet environnement.