Documentation API
Tout ce dont vous avez besoin pour intégrer votre plateforme de livraison à RouteMate.
Sommaire
Premiers pas
L'API d'intégration RouteMate vous permet d'importer des missions de livraison par programmation, d'optimiser automatiquement les itinéraires et de consulter le statut des missions depuis vos systèmes existants.
URL de base
https://api.routemate.app/v1Fonctionnement
- Créer une intégration — Dans l'application web RouteMate, allez dans Intégrations puis cliquez sur Créer une intégration. Vous recevrez un client_id et un client_secret.
- Obtenir un jeton d'accès — Échangez vos identifiants contre un bearer token temporaire valable 1 heure.
- Importer un job — Envoyez vos arrêts de livraison via POST. RouteMate géocode les adresses, optimise l'ordre de livraison et assigne le job à un conducteur.
- Consulter le statut — Vérifiez la progression de votre job à tout moment pour voir quels arrêts sont terminés.
Prérequis
- Un compte RouteMate sur l'offre Team ou Enterprise
- Une organisation créée dans l'application web RouteMate
- Une intégration active avec des identifiants client
Flux client credentials
L'API utilise des identifiants client OAuth2. Votre secret n'est jamais stocké : seul un hash SHA-256 est conservé sur nos serveurs.
Modèle de sécurité
- Les secrets client sont hachés en SHA-256 et jamais stockés en clair
- Les jetons d'accès sont opaques (pas des JWT) et valables pendant 1 heure
- Les jetons sont à usage unique et limités à votre intégration
- Toutes les requêtes doivent être effectuées via HTTPS
- Incluez le jeton dans chaque requête : Authorization: Bearer <token>
Important : Votre client_secret n'est affiché qu'une seule fois lors de la création de l'intégration. Stockez-le de manière sécurisée, par exemple dans des variables d'environnement ou un gestionnaire de secrets. En cas de perte, vous devrez le régénérer depuis le tableau de bord RouteMate.
Obtenir un jeton d'accès
/v1/integration-tokenCorps de la requête
| Field | Type | Required | Description |
|---|---|---|---|
| client_id | string | Yes | L'identifiant client de votre intégration (commence par rm_ci_) |
| client_secret | string | Yes | Le secret client de votre intégration (commence par rm_cs_) |
Exemple de requête
curl -X POST https://api.routemate.app/v1/integration-token \
-H "Content-Type: application/json" \
-d '{
"client_id": "rm_ci_abc123...",
"client_secret": "rm_cs_xyz789..."
}'Réponse de succès 200
{
"access_token": "rm_at_e5988dd1b91a4ff3827c5d2ed416ccbe37ae227a",
"token_type": "Bearer",
"expires_in": 3600
}Réponses d'erreur
400client_id ou client_secret manquant
401Identifiants invalides (mauvais secret ou client_id inconnu)
403L'intégration a été désactivée
Importer un job et des arrêts
/v1/integration-importEn-têtes de la requête
| Field | Type | Required | Description |
|---|---|---|---|
| Authorization | string | Yes | Bearer <access_token> |
| Content-Type | string | Yes | application/json |
| Idempotency-Key | string | No | Clé unique pour éviter les imports en double (valable 24 heures) |
Corps de la requête — Champs du job
| Field | Type | Required | Description |
|---|---|---|---|
| external_job_id | string | Yes | Votre identifiant unique pour ce job (doit être unique par intégration) |
| title | string | Yes | Titre du job (par exemple Morning Deliveries - Zone A) |
| driver_email | string | Yes | Email du conducteur à assigner. S'il possède un compte RouteMate, il verra la tournée dans son application. Sinon, une invitation sera créée. |
| scheduled_date | string | No | Date planifiée au format ISO (YYYY-MM-DD) |
| timezone | string | No | Fuseau horaire IANA (par exemple Australia/Brisbane ou America/New_York) |
| metadata | object | No | Données clé-valeur personnalisées attachées au job |
| stops | array | Yes | Tableau d'objets arrêt (voir Champs d'arrêt ci-dessous) |
Exemple de requête
curl -X POST https://api.routemate.app/v1/integration-import \
-H "Authorization: Bearer rm_at_your_token_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-batch-2026-03-09-001" \
-d '{
"external_job_id": "BATCH-2026-03-09-A",
"title": "Morning Deliveries - Zone A",
"driver_email": "driver@example.com",
"scheduled_date": "2026-03-09",
"timezone": "Australia/Brisbane",
"stops": [
{
"external_stop_id": "ORD-1001",
"address": "1 George St, Brisbane QLD 4000, Australia",
"label": "John Smith",
"notes": "Leave at front door",
"priority": 1,
"parcel_count": 2
},
{
"external_stop_id": "ORD-1002",
"address": "100 Queen St, Brisbane QLD 4000, Australia",
"label": "Jane Doe",
"notes": "Ring doorbell",
"priority": 2
},
{
"external_stop_id": "ORD-1003",
"address": "South Bank Parklands, Brisbane QLD 4101, Australia",
"label": "Bob Wilson",
"priority": 3,
"parcel_count": 1
}
]
}'Réponse de succès 200
{
"job_id": "e7ad097b-bc51-4d01-9b04-0e372d80613a",
"external_job_id": "BATCH-2026-03-09-A",
"route_id": "1c2a8c0b-1b69-4a04-85b1-608b2ebe3878",
"driver_email": "driver@example.com",
"driver_resolved": true,
"driver_user_id": "573b6bee-aa3d-4cb0-af87-620bba0db049",
"stops_imported": 3,
"stops_geocoded": 3,
"stops_geocode_failed": 0,
"optimization": {
"total_distance_km": 12.4,
"total_duration_minutes": 25,
"encoded_polyline": "fvmfDqmfe\\bPtA..."
},
"stops": [
{
"external_stop_id": "ORD-1001",
"address": "1 George St, Brisbane QLD 4000, Australia",
"latitude": -27.4710,
"longitude": 153.0234,
"label": "John Smith",
"notes": "Leave at front door",
"sort_order": 0,
"priority": 1,
"parcel_count": 2,
"status": "pending"
},
{
"external_stop_id": "ORD-1003",
"address": "South Bank Parklands, Brisbane QLD 4101, Australia",
"latitude": -27.4753,
"longitude": 153.0208,
"label": "Bob Wilson",
"notes": null,
"sort_order": 1,
"priority": 3,
"parcel_count": 1,
"status": "pending"
},
{
"external_stop_id": "ORD-1002",
"address": "100 Queen St, Brisbane QLD 4000, Australia",
"latitude": -27.4688,
"longitude": 153.0281,
"label": "Jane Doe",
"notes": "Ring doorbell",
"sort_order": 2,
"priority": 2,
"parcel_count": 1,
"status": "pending"
}
],
"deep_link": "https://app.routemate.app/app/jobs/e7ad097b-...",
"warnings": [
{ "code": "ADDRESS_GEOCODED", "message": "3 stop(s) were geocoded from address text" },
{ "code": "ROUTE_OPTIMIZED", "message": "Route optimized: 12.4 km, 25 min" }
]
}Remarque : Remarque : le tableau stops est renvoyé dans l'ordre de livraison optimisé selon sort_order, et non dans l'ordre d'envoi.
Codes d'avertissement
| Field | Type | Required | Description |
|---|---|---|---|
| ROUTE_OPTIMIZED | info | No | L'itinéraire a été optimisé avec succès avec distance et durée |
| ADDRESS_GEOCODED | info | No | Un ou plusieurs arrêts ont été géocodés à partir du texte de l'adresse |
| DRIVER_AUTO_ADDED | info | No | Le conducteur possédait déjà un compte RouteMate et a été automatiquement ajouté à votre organisation |
| DRIVER_NOT_FOUND | warning | No | Aucun compte RouteMate n'a été trouvé pour cet email. Une invitation a été créée. |
| GEOCODE_FAILED | warning | No | Impossible de géocoder l'adresse d'un arrêt. Fournissez latitude/longitude à la place. |
Consulter le statut d'un job
/v1/integration-jobsParamètres de requête
| Field | Type | Required | Description |
|---|---|---|---|
| external_job_id | string | No | Votre identifiant externe de job (celui fourni lors de l'import) |
| job_id | string | No | L'UUID interne du job dans RouteMate |
Au moins l'un des paramètres external_job_id ou job_id doit être fourni.
Exemple de requête
curl "https://api.routemate.app/v1/integration-jobs?external_job_id=BATCH-2026-03-09-A" \
-H "Authorization: Bearer rm_at_your_token_here"Réponse de succès 200
{
"job_id": "e7ad097b-bc51-4d01-9b04-0e372d80613a",
"external_job_id": "BATCH-2026-03-09-A",
"title": "Morning Deliveries - Zone A",
"status": "assigned",
"driver_email": "driver@example.com",
"driver_resolved": true,
"driver_user_id": "573b6bee-...",
"route_id": "1c2a8c0b-...",
"scheduled_date": "2026-03-09",
"timezone": "Australia/Brisbane",
"metadata": {},
"stop_count": 3,
"status_counts": {
"pending": 2,
"completed": 1
},
"deep_link": "https://app.routemate.app/app/jobs/e7ad097b-...",
"stops": [
{
"external_stop_id": "ORD-1001",
"address": "1 George St, Brisbane QLD 4000",
"latitude": -27.4710,
"longitude": 153.0234,
"label": "John Smith",
"notes": "Leave at front door",
"status": "completed",
"priority": 1,
"parcel_count": 2
},
...
],
"created_at": "2026-03-09T08:30:00.000Z",
"updated_at": "2026-03-09T10:15:00.000Z"
}Statuts du job
| Field | Type | Required | Description |
|---|---|---|---|
| pending | status | No | Job créé, mais le conducteur n'a pas encore été assigné ou résolu |
| assigned | status | No | Le conducteur a été assigné et peut voir la tournée dans son application |
| in_progress | status | No | Le conducteur a commencé la tournée |
| completed | status | No | Tous les arrêts ont été livrés |
Champs d'arrêt
Liste complète des champs disponibles pour chaque arrêt dans la requête d'import.
| Field | Type | Required | Description |
|---|---|---|---|
| external_stop_id | string | Yes | Votre identifiant unique pour cet arrêt (doit être unique dans le job) |
| address | string | Yes | Adresse complète. Elle sera géocodée si latitude/longitude ne sont pas fournies. |
| latitude | number | No | Latitude en degrés décimaux. Le géocodage est ignoré si longitude est aussi fournie. |
| longitude | number | No | Longitude en degrés décimaux. Le géocodage est ignoré si latitude est aussi fournie. |
| label | string | No | Libellé affiché (par exemple nom du client ou numéro de commande) |
| notes | string | No | Instructions de livraison pour le conducteur |
| service_type | string | No | Type de service (par exemple delivery, pickup ou service_call) |
| duration_minutes | number | No | Durée de service prévue à cet arrêt en minutes |
| time_window_start | string | No | Heure de livraison la plus tôt (datetime ISO 8601) |
| time_window_end | string | No | Heure limite de livraison (datetime ISO 8601) |
| priority | number | No | Niveau de priorité (plus la valeur est basse, plus la priorité est élevée). Par défaut : 0 |
| parcel_count | number | No | Nombre de colis pour cet arrêt. Par défaut : 1 |
| metadata | object | No | Données clé-valeur personnalisées attachées à cet arrêt |
Astuce : Astuce : fournir directement latitude et longitude est plus rapide et plus fiable que le géocodage.
Optimisation d'itinéraire
Chaque import optimise automatiquement la séquence de livraison pour réduire temps et distance.
Fonctionnement de l'optimisation
- Tous les arrêts sans coordonnées sont géocodés à partir du texte de leur adresse
- Le premier arrêt est traité comme origine et le dernier comme destination
- Tous les arrêts intermédiaires sont optimisés pour l'itinéraire routier le plus court via Google Routes API
- Le champ sort_order de chaque arrêt est mis à jour pour refléter la séquence optimisée
- La polyligne de l'itinéraire, la distance totale et la durée estimée sont calculées
Champs de réponse
| Field | Type | Required | Description |
|---|---|---|---|
| optimization.total_distance_km | number | No | Distance totale de l'itinéraire en kilomètres |
| optimization.total_duration_minutes | number | No | Temps total de conduite estimé en minutes |
| optimization.encoded_polyline | string | No | Google Encoded Polyline pour afficher l'itinéraire sur une carte |
Remarque : L'optimisation nécessite au moins 2 arrêts avec des coordonnées valides. Si le géocodage échoue pour certains arrêts, l'itinéraire sera optimisé uniquement avec ceux qui ont pu être géocodés.
Idempotence
Relancez les requêtes échouées sans créer de jobs en double.
Ajoutez un en-tête Idempotency-Key avec une valeur unique aux requêtes d'import. Si la même clé est renvoyée dans les 24 heures, l'API renverra la réponse en cache au lieu de créer un doublon.
curl -X POST https://api.routemate.app/v1/integration-import \
-H "Authorization: Bearer rm_at_your_token" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: batch-2026-03-09-zone-a" \
-d '{ ... }'
# Safe to retry — same Idempotency-Key returns cached response
curl -X POST https://api.routemate.app/v1/integration-import \
-H "Authorization: Bearer rm_at_your_token" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: batch-2026-03-09-zone-a" \
-d '{ ... }'Bonne pratique : Ajoutez toujours un Idempotency-Key en production. Utilisez une clé déterministe pour éviter les doublons lors des retries réseau.
Gestion des erreurs
Toutes les erreurs renvoient un corps JSON avec un champ error.
{
"error": "Rate limit exceeded",
"retry_after_seconds": 45
}
// ou pour les erreurs de validation :
{
"error": {
"code": "VALIDATION_ERROR",
"messages": [
"external_job_id is required",
"stops[0].address is required"
]
}
}| Statut | Signification | Action |
|---|---|---|
| 200 | Succès | La requête a été traitée avec succès |
| 400 | Requête invalide | Vérifiez les messages d'erreur et corrigez le corps de la requête |
| 401 | Non autorisé | Votre jeton est invalide ou expiré. Obtenez-en un nouveau. |
| 403 | Interdit | Votre intégration a été désactivée. Contactez votre administrateur. |
| 404 | Introuvable | Le job ou l'endpoint n'existe pas |
| 405 | Méthode non autorisée | Utilisez la bonne méthode HTTP (POST ou GET) |
| 429 | Trop de requêtes | Attendez retry_after_seconds avant de réessayer |
| 500 | Erreur serveur | Réessayez avec un backoff exponentiel. Contactez le support si le problème persiste. |
Limites de débit
Les limites de débit s'appliquent par intégration sur une fenêtre glissante d'une minute.
| Offre | Requêtes / minute | Arrêts max / import |
|---|---|---|
| Team | 60 | 200 |
| Enterprise | Custom | Custom |
En cas de limitation, l'API renvoie HTTP 429 avec un champ retry_after_seconds.
Exemples de code complets
Exemples prêts à copier-coller pour les langages courants. Tous montrent le flux complet : authentifier, importer et consulter.
#!/bin/bash
# RouteMate API Integration Example
API_BASE="https://api.routemate.app/v1"
CLIENT_ID="rm_ci_your_client_id"
CLIENT_SECRET="rm_cs_your_client_secret"
# Step 1: Get access token
TOKEN=$(curl -s -X POST "$API_BASE/integration-token" \
-H "Content-Type: application/json" \
-d "{
\"client_id\": \"$CLIENT_ID\",
\"client_secret\": \"$CLIENT_SECRET\"
}" | jq -r '.access_token')
echo "Access Token: $TOKEN"
# Step 2: Import a job with stops
RESULT=$(curl -s -X POST "$API_BASE/integration-import" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-batch-001" \
-d '{
"external_job_id": "BATCH-001",
"title": "Morning Deliveries",
"driver_email": "driver@example.com",
"scheduled_date": "2026-03-10",
"timezone": "Australia/Brisbane",
"stops": [
{
"external_stop_id": "STOP-1",
"address": "1 George St, Brisbane QLD 4000",
"label": "Customer A",
"parcel_count": 2
},
{
"external_stop_id": "STOP-2",
"address": "100 Queen St, Brisbane QLD 4000",
"label": "Customer B",
"notes": "Leave at reception"
}
]
}')
echo "$RESULT" | jq .
# Step 3: Query job status
JOB_ID=$(echo "$RESULT" | jq -r '.job_id')
curl -s "$API_BASE/integration-jobs?job_id=$JOB_ID" \
-H "Authorization: Bearer $TOKEN" | jq .Webhooks
Recevez des notifications en temps réel lorsque les livraisons sont terminées.
La prise en charge des webhooks arrive bientôt. Vous pourrez enregistrer une URL et recevoir des notifications POST pour des événements tels que :
- job.completed — Tous les arrêts d'un job ont été livrés
- stop.completed — Un seul arrêt a été livré (avec preuve de livraison)
- stop.failed — Une tentative de livraison a échoué
- driver.location — Mises à jour GPS du conducteur en temps réel
Intéressé par un accès anticipé ? Contactez-nous.