Chaque mission de transport suit un cycle de vie : de sa planification jusqu’à sa clôture (ou son annulation). L’API expose un vocabulaire de statuts public et stable — un sous-ensemble condensé des statuts internes — pour que vous puissiez piloter votre intégration sans dépendre des détails opérationnels. À chaque changement d’étape, un événement webhook est émis. C’est le signal canonique pour réagir en temps réel : mettre à jour votre back-office, notifier un client, déclencher une facturation.
Le statut public d’une mission est exposé via le champ status (objet Transport) sur GET /transports/{id} et GET /transports. Les statuts internes ne sont jamais renvoyés.

Les 9 statuts publics

scheduled

Mission planifiée, en attente d’attribution d’un convoyeur. C’est le statut initial après POST /transports.

assigned

Un convoyeur a été attribué à la mission. Le véhicule n’est pas encore enlevé.

in_transit

Le véhicule a été enlevé et est en cours d’acheminement vers le point de livraison (jambe aller).

in_transit_return

La jambe retour est en cours (uniquement pour les missions aller-retour).

awaiting_documents

Le véhicule est livré ; la mission attend les PV et documents (inspection, bon de livraison).

under_review

Les documents transmis sont en cours de validation.

completed

Mission terminée. Documents validés, prestation clôturée.

incident

Une anomalie a été signalée sur la mission (peut survenir à tout moment).

cancelled

Mission annulée (peut survenir à tout moment avant la clôture).
Branchez votre logique sur la valeur exacte du statut (completed, cancelled, …), jamais sur un libellé affiché. Ces neuf valeurs constituent un contrat stable.

Diagramme des transitions

Le chemin nominal va de scheduled à completed. La jambe in_transit_return n’apparaît que pour les aller-retours. Les états incident et cancelled peuvent être atteints depuis n’importe quel état actif. Résumé textuel de la séquence nominale :
scheduled → assigned → in_transit [→ in_transit_return] → awaiting_documents → under_review → completed
incident et cancelled ne sont pas des étapes du flux nominal : ce sont des sorties qui peuvent intervenir à tout moment. Un incident ne clôt pas forcément la mission — il signale une anomalie à traiter.

Cas de l’aller-retour (double jambe)

Une mission peut comporter une jambe retour lorsque le convoyeur doit ramener un véhicule après la livraison aller. Vous l’activez à la création via le champ return_trip (booléen ou objet).
curl -s -X POST "https://api.myexpressdriver.com/v1/transports" \
  -H "X-Api-Key: med_live_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "vehicle":  { "type": "VP", "registration": "AB-123-CD" },
    "pickup":   { "address": "10 Rue de Rivoli, 75004 Paris", "date": "2026-07-01" },
    "delivery": { "address": "1 Place Bellecour, 69002 Lyon", "date": "2026-07-01" },
    "billing":  { "company_name": "Garage Demo SARL", "email": "compta@garage-demo.fr", "address": "5 Avenue des Champs, 75008 Paris" },
    "return_trip": true
  }'
Sur une mission aller-retour :
  • Le détail de la mission (GET /transports/{id}) porte un objet return_trip non null, qui contient son propre status, ses points pickup / delivery, son vehicle, sa distance_km et son price.
  • Le résumé de listing (GET /transports) expose un booléen has_return pour repérer les aller-retours d’un coup d’œil.
  • Le statut public passe par in_transit_return pendant que la jambe retour est en cours. Si la mission est un trajet simple, ce statut n’apparaît jamais — on passe directement de in_transit à awaiting_documents.
Les endpoints de modification raisonnent par jambe. Pour les dates (PATCH /transports/{id}/dates), les clés possibles sont enlevement-aller, livraison-aller, enlevement-retour, livraison-retour. Pour la refacturation (POST /transports/{id}/price-adjustments), le champ leg vaut aller ou retour. Seules les jambes réellement modifiées déclenchent une notification.

Webhook émis à chaque transition

Chaque changement d’état projette un événement dans le journal de la mission, qui est ensuite livré à vos endpoints webhook. Le tableau ci-dessous associe une transition à l’événement correspondant.
TransitionÉvénement webhookPayload data (résumé)
Création → scheduledtransport.created{ id, transport_id, status, price }
scheduledassignedtransport.assigned{ id, driver }
assignedin_transittransport.collected{ id, collected_at }
Tout changement de statut publictransport.status_changed{ id, from, to }
under_reviewcompletedtransport.completed{ id, completed_at }
incidenttransport.incident{ id }
cancelledtransport.cancelled{ id, reason }
L’événement générique transport.status_changed est émis à chaque transition de statut public et porte les deux statuts (from, to). Les événements plus spécifiques (transport.assigned, transport.collected, transport.completed, transport.incident, transport.cancelled) le doublent pour les étapes clés. Vous pouvez vous abonner uniquement à transport.status_changed pour suivre tout le cycle de vie avec un seul handler.
D’autres événements ne sont pas des transitions de cycle de vie mais accompagnent une mission active :
ActionÉvénement webhookPayload data (résumé)
Modification des dates (PATCH …/dates)transport.dates_updated{ id, updated_legs }
Refacturation (POST …/price-adjustments)transport.price_adjusted{ id, leg, old_price_ht, new_price_ht, motif }
Ajout / retrait d’option (POST / DELETE …/options)transport.price_adjusted{ id, option | removed_option, new_price }
Ajout d’un documentdocument.added{ id, document_key, url }
Document acceptédocument.accepted{ id, document_key, status }
Document refusédocument.rejected{ id, document_key, status }
La livraison des webhooks est at-least-once : un même événement peut vous parvenir plusieurs fois. Déduplifiez sur l’en-tête X-MED-Delivery-Id, et prévoyez une réconciliation périodique via GET /events?since=… pour rattraper d’éventuels événements manqués. Voir Webhooks · Événements pour le catalogue complet et la vérification de signature.

Réagir à une transition (exemple)

Voici un handler de webhook minimal qui aiguille selon le statut public reçu. Le détail de la vérification de signature HMAC est traité dans la page webhooks.
Node.js
// Reçu après vérification de la signature : { id, type, created_at, data }
function handleTransportEvent(event) {
  switch (event.type) {
    case "transport.created":
      // data = { id, transport_id, status, price } → status "scheduled"
      console.log(`Mission ${event.data.transport_id} planifiée`);
      break;

    case "transport.status_changed":
      // data = { id, from, to } — pilote tout le cycle de vie
      console.log(`Mission ${event.data.id} : ${event.data.from}${event.data.to}`);
      if (event.data.to === "in_transit") {
        // véhicule enlevé : notifier le destinataire
      }
      break;

    case "transport.completed":
      // data = { id, completed_at } → déclencher la facturation
      break;

    case "transport.incident":
      // data = { id } → alerter l'équipe support
      break;

    case "transport.cancelled":
      // data = { id, reason }
      break;
  }
}

Étapes suivantes

Catalogue des événements webhook

Tous les types d’événements, leurs payloads, les en-têtes de livraison et la vérification de signature.

Démarrage rapide

Créez votre première mission et abonnez-vous à ses événements en quelques minutes.