La création d’une mission est l’opération centrale de l’API Transport. Un seul appel POST /transports planifie un transport de véhicule, le rend visible côté convoyeurs, et déclenche l’événement webhook transport.created.
La mission créée porte le statut public scheduled : elle est planifiée et en attente d’attribution d’un convoyeur. Vous suivrez ensuite sa progression via les statuts assigned, in_transit, awaiting_documents, under_review puis completed.

Prérequis

Clé API

Une clé portant le scope transports:write, envoyée dans l’en-tête X-Api-Key: med_live_....

Adresses d'enlèvement et de livraison

Les champs pickup et delivery sont requis, chacun avec adresse, date, créneau (ou need_appointment: true) et contact complet (nom, téléphone, e-mail).

Facturation

Le bloc billing est requis, avec raison sociale, e-mail et adresse — même si vous désignez l’entité par entity_id.

Clé d'idempotence

Indispensable : un Idempotency-Key unique par mission, pour pouvoir réessayer sans jamais créer de doublon.

Les champs du corps de la requête

Le corps est un objet JSON. Sont requis : le véhicule (car, ou son alias vehicle) avec son immatriculation registration ; pickup et delivery, chacun avec address, date, contact (name, phone, mail) et le créneau start_time / end_time (sauf need_appointment: true) ; billing avec company_name, address et email. Tous les autres champs sont optionnels.
Ces exigences valent pour la création. L’estimation POST /pricing se contente des adresses (et du véhicule pour le gabarit).

Champs racine

string
Type de transport. Valeurs usuelles : livraison, restitution, conciergerie. En l’absence de valeur, le transport est traité comme une livraison standard.
boolean
défaut:"false"
Indique un transport sur plateau (camion porte-véhicule) plutôt qu’en roulant. Impacte la tarification.
boolean
défaut:"false"
Indique que le carburant est remboursé au convoyeur sur cette mission.
boolean
défaut:"false"
Véhicule circulant sous plaques W garage (immatriculation provisoire professionnelle).
string[]
Liste des clés d’options à appliquer à la mission (ex. lavage, plein de carburant). Les clés disponibles dépendent de la grille de votre groupe.
string
Note libre attachée à la mission (consignes particulières, référence interne).

car — le véhicule

object
requis
Caractéristiques du véhicule transporté.
Dans le contrat OpenAPI, l’objet véhicule est nommé vehicle et accepte aussi type, vin, brand et model. car est l’alias documenté côté guide ; les deux pointent vers le même objet véhicule. Préférez vehicle si vous générez votre client directement depuis l’OpenAPI.

pickup — point d’enlèvement

object
requis
Lieu, créneau et contact pour l’enlèvement du véhicule.

delivery — point de livraison

object
requis
Lieu, créneau et contact pour la livraison du véhicule. Mêmes propriétés et mêmes exigences que pickup.
Chaque champ manquant, mal formé ou incohérent est signalé dans errors[] d’une réponse 422, avec son chemin : pickup.date, pickup.start_time, pickup.contact, pickup.contact.phone, delivery.contact.mail… Toutes les erreurs sont renvoyées en une fois. Les incohérences de calendrier portent un code court dans errors[].error : past (enlèvement avant aujourd’hui), before_pickup (livraison avant l’enlèvement), before_start_time (fin de créneau antérieure au début).

billing — facturation

object
requis
Informations de facturation de la mission. company_name, address et email sont toujours requis, même avec entity_id : s’il en manque un, la création est refusée en 422 et errors[] nomme chaque champ manquant (billing.company_name, billing.address, billing.email).

return_trip — aller-retour

boolean | string | object
Décrit la jambe retour. Omettez (ou false) pour un aller simple. Trois formes :
  • true → A→B→A : retour vers le lieu d’enlèvement de l’aller.
  • "adresse" (chaîne) → A→B→C : retour vers cette adresse de destination.
  • objet → forme complète (ci-dessous), pour préciser véhicule / contacts / horaires du retour.
En forme courte (true ou chaîne), le retour reprend le véhicule de l’aller, la date de livraison de l’aller et le contact de livraison de l’aller (à défaut, celui d’enlèvement), sans créneau : il est créé en attente de rendez-vous.
Le retour n’a pas d’adresse de départ à renseigner. Il part automatiquement du lieu de livraison de l’aller (le convoyeur repart de là où il vient de livrer). Vous ne précisez donc que la destination du retour (forme courte "adresse", ou return_trip.delivery) — jamais un point de départ.

Exemple — aller simple

Exemple — aller-retour

Pour un aller-retour, ajoutez le bloc return_trip avec le véhicule et le point de livraison du retour.

Réponse 201 Created

En cas de succès, l’API renvoie 201 avec l’identifiant de la mission, son statut, le prix calculé et les adresses retenues.
string
Identifiant technique de la mission (offer_id). À utiliser dans tous les appels ultérieurs : GET /transports/{id}, suivi GPS, documents, etc.
string | null
Référence métier lisible de la mission (ex. M-54321). Vaut null dans cette réponse : elle est attribuée juste après la création. Lisez-la via GET /transports/{id}.
string
Statut public de la mission. À la création, vaut toujours scheduled.
string | null
Prix HT facturé pour l’aller, sous forme de chaîne décimale (ex. "407.44", ou "180" sans décimales), majorations comprises. Convertissez-la en nombre côté client. Le prix détaillé (price.amount_ht, price.surcharge_ht, price.currency) et celui du retour (return_trip.price) se lisent via GET /transports/{id}.
object | null
Entité(s) de facturation MED posée(s) sur la mission : entity_id (aller) et return_entity_id (retour, null sans trajet retour).
object
Adresse d’enlèvement résolue (géocodée) effectivement enregistrée : address normalisée, lat, lng, place_id. Contrôlez-la pour vérifier que le point retenu est bien celui visé.
object
Adresse de livraison résolue, même structure que pickup.
object | null
Pour un aller-retour : adresses résolues pickup (= livraison de l’aller) et delivery (destination du retour). null sur un aller simple.
Conservez l’id renvoyé : c’est lui qui identifie la mission pour le suivi, la modification des dates, les options et l’annulation.

Idempotence

La création de mission est l’opération la plus sensible aux doublons : un appel qui échoue côté réseau peut avoir réussi côté serveur. Pour vous protéger, envoyez systématiquement un en-tête Idempotency-Key (par exemple un UUID v4 que vous générez).
Exécutée normalement. La réponse est mise en cache et associée à la clé.
La réponse en cache est rejouée à l’identique, avec l’en-tête Idempotent-Replayed: true. Une seule mission est créée.
L’API renvoie 409 Conflict avec code: idempotency_key_reused : la clé a déjà servi pour une requête différente (autre corps, autre route ou autre mission).
Les réponses 5xx ne sont pas mises en cache : vous pouvez réessayer avec la même clé et le même corps. Un 502 avec code: relay_timeout signifie que la mission a pu être créée malgré l’erreur : le nouvel essai vous la renvoie (201 identique) au lieu d’en créer une seconde.
Un 502, ou un 409 request_in_progress sans Retry-After, peut porter outcome_unknown: true : la création avait commencé quand l’erreur est survenue, et son issue est inconnue. Cette situation ne se résout pas par un nouvel essai. Ne renvoyez pas la commande : vérifiez d’abord par GET /transports (avec since, ou en cherchant votre référence de commande) si la mission existe, ou contactez le support.
Si vous réessayez pendant que la première création est encore en traitement, l’API répond 409 avec code: request_in_progress et un en-tête Retry-After (5 s). Rien n’est recréé : patientez puis réessayez avec la même clé. Sans Retry-After et avec outcome_unknown: true, voir ci-dessous.
Sans Idempotency-Key, un nouvel essai après un timeout ou un 502 peut créer un doublon (deux convoyages, deux facturations). Si vous avez déjà envoyé une création sans clé, vérifiez vos missions (GET /transports) avant de la renvoyer.
Utilisez une clé d’idempotence distincte par mission à créer. Les clés sont conservées 24 h.

Erreurs

Les erreurs suivent la RFC 9457 (Content-Type: application/problem+json). Exemple de 422 lorsqu’un champ requis manque — detail résume, errors[] détaille champ par champ :
Branchez votre logique sur status et code, pas sur le texte de detail ni sur title, qui peuvent évoluer.

Étapes suivantes

Suivre une mission

Récupérer le détail, les positions GPS et l’ETA du convoyeur.

Modifier les dates

Ajuster les créneaux d’enlèvement et de livraison, par jambe.

Recevoir les événements

S’abonner aux webhooks signés (transport.created, transport.status_changed…).