curl --request POST \
--url https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--data '
{
"reason": "<string>"
}
'import requests
url = "https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel"
payload = { "reason": "<string>" }
headers = {
"X-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({reason: '<string>'})
};
fetch('https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'reason' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel"
payload := strings.NewReader("{\n \"reason\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Api-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"reason\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"reason\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "-O9xAbCdEf",
"status": "cancelled",
"penalty": {
"ratio": 0.5,
"client_charge_ht": 203.72,
"currency": "EUR"
},
"return_included": false
}Annuler la mission
Annule la mission, tant que le véhicule n’est pas parti (statut public
scheduled ou assigned). Exception : une mission assigned dont
l’attribution au convoyeur est encore en cours de confirmation est refusée
(409, code: not_cancellable) ; contactez le support si l’annulation est
urgente. Émet transport.cancelled.
La mission est conservée : elle passe au statut cancelled, reste
lisible par GET /transports/{id} et apparaît dans
GET /transports?status=cancelled. Une mission aller-retour est annulée en
entier ; le retour suit l’aller s’il n’est pas déjà terminé
(return_included).
Frais d’annulation — même barème que l’espace client, calculé sur la date d’enlèvement de l’aller, heure de Paris, jours ouvrés (lundi à vendredi) :
| Moment de l’annulation | Frais (penalty.ratio) |
|---|---|
| Enlèvement dans 2 jours ouvrés ou plus | 0 % (0) |
| Aucun convoyeur encore attribué, quel que soit le délai | 0 % (0) |
| Veille ouvrée de l’enlèvement, ou après 18 h l’avant-veille | 50 % (0.5) |
| Jour même de l’enlèvement, ou après 18 h la veille | 100 % (1) |
penalty.client_charge_ht est le montant HT facturé au titre de
l’annulation : prix HT de la mission (retour compris quand
return_included vaut true) multiplié par penalty.ratio.
Ces frais restent lisibles ensuite : après l’annulation, price.amount_ht
de GET /transports/{id} (et return_trip.price.amount_ht si le retour
est inclus) vaut le montant facturé pour chaque jambe, et
GET /transports/{id}/price-history trace le passage de l’ancien prix au
prix d’annulation.
Une mission déjà annulée, terminée ou déjà partie renvoie 409 : une seconde
annulation n’a donc aucun effet. Un 502 dont le detail indique que
l’annulation n’a pas pu être confirmée (The cancellation could not be confirmed…) signifie que son issue est incertaine : relisez la mission
avant de réessayer. Après un 502 (relay_timeout),
l’annulation a pu aboutir : un nouvel essai, même avec le même
Idempotency-Key, reçoit alors 409 already_cancelled (et non la réponse
200) ; lisez les frais via GET /transports/{id}.
L’événement transport.cancelled ({ id, transport_id, cancelled_at }) est
émis peu après, de façon asynchrone, accompagné d’un
transport.status_changed vers cancelled. Il ne porte pas les frais :
conservez la réponse 200 (penalty). Le motif (reason) n’est renvoyé
ni par l’événement ni par la réponse.
curl --request POST \
--url https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--data '
{
"reason": "<string>"
}
'import requests
url = "https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel"
payload = { "reason": "<string>" }
headers = {
"X-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({reason: '<string>'})
};
fetch('https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'reason' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel"
payload := strings.NewReader("{\n \"reason\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Api-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"reason\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sandbox.myexpressdriver.com/v1/transports/{id}/cancel")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"reason\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "-O9xAbCdEf",
"status": "cancelled",
"penalty": {
"ratio": 0.5,
"client_charge_ht": 203.72,
"currency": "EUR"
},
"return_included": false
}Autorisations
Clé API liée à un groupe (med_live_… en production, med_test_… en test).
Fournie en clair une seule fois à la création depuis le profil client.
En-têtes
Clé d'idempotence fournie par le client (un UUID v4 par opération), conservée
24 h. Recommandée sur toutes les créations. Rejouer la même clé avec un
corps identique sur la même route renvoie la réponse en cache
(Idempotent-Replayed: true). L'empreinte couvre la méthode, le chemin
(donc la mission visée) et le corps : la même clé pour une autre requête
renvoie 409 idempotency_key_reused. Requête identique encore en
traitement : 409 request_in_progress avec Retry-After.
Les réponses 5xx, 404 et 422 documents_failed ne sont pas mémorisées :
un nouvel essai avec la même clé et le même corps est retraité.
Après un 502 (code: relay_timeout), une erreur réseau ou un 5xx,
réessayez avec la même clé et le même corps : la requête est
relancée, et une mission créée malgré l'erreur vous est renvoyée (201,
Idempotent-Replayed: true) au lieu d'être créée une seconde fois.
Exception : si la réponse porte outcome_unknown: true, ne réessayez pas,
vérifiez d'abord (GET /transports). Seuls la création de mission et le
dépôt de documents sont dédoublonnés ainsi ; sans clé, un nouvel essai peut
créer un doublon.
"1f3c2b7a-9d4e-4a1b-8c2f-0e6d5a4b3c2d"
Paramètres de chemin
Identifiant de la mission (offer_id).
Corps
Motif d'annulation (optionnel).
Réponse
Mission annulée.
Identifiant de la mission (offer_id).
cancelled Frais d'annulation facturés (prix client HT uniquement). Barème : voir POST /transports/{id}/cancel.
Show child attributes
Show child attributes
Vrai si le trajet retour a été annulé avec l'aller (mission aller-retour dont le retour n'était pas terminé). Faux pour un aller simple.
