Documentazione API
Tutto ciò che ti serve per integrare la tua piattaforma di consegna con RouteMate.
Contenuti
Per iniziare
La Integration API di RouteMate ti consente di importare job di consegna in modo programmatico, ottimizzare automaticamente i percorsi e consultare lo stato dei job dai tuoi sistemi esistenti.
URL base
https://api.routemate.app/v1Come funziona
- Crea un'integrazione — Nell'app web di RouteMate vai su Integrazioni e fai clic su Crea integrazione. Riceverai un client_id e un client_secret.
- Ottieni un token di accesso — Scambia le tue credenziali con un bearer token temporaneo valido per 1 ora.
- Importa un job — Invia le fermate di consegna tramite POST. RouteMate geocodifica gli indirizzi, ottimizza l'ordine del percorso e assegna il job a un driver.
- Controlla lo stato — Verifica in qualsiasi momento l'avanzamento del job per vedere quali fermate sono state completate.
Requisiti
- Un account RouteMate con piano Team o Enterprise
- Un'organizzazione creata nell'app web di RouteMate
- Un'integrazione attiva con credenziali client
Flusso client credentials
La API usa credenziali client OAuth2. Il tuo secret non viene mai memorizzato: sui nostri server conserviamo solo un hash SHA-256.
Modello di sicurezza
- I client secret vengono hashati con SHA-256 e non sono mai salvati in chiaro
- I token di accesso sono opachi (non JWT) e validi per 1 ora
- I token sono monouso e limitati alla tua integrazione
- Tutte le richieste devono essere effettuate tramite HTTPS
- Includi il token in ogni richiesta: Authorization: Bearer <token>
Importante: Il tuo client_secret viene mostrato una sola volta quando crei l'integrazione. Conservalo in modo sicuro, ad esempio in variabili d'ambiente o in un secrets manager. Se lo perdi, dovrai rigenerarlo dal dashboard di RouteMate.
Ottieni token di accesso
/v1/integration-tokenCorpo della richiesta
| Field | Type | Required | Description |
|---|---|---|---|
| client_id | string | Yes | Il client ID della tua integrazione (inizia con rm_ci_) |
| client_secret | string | Yes | Il client secret della tua integrazione (inizia con rm_cs_) |
Richiesta di esempio
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..."
}'Risposta di successo 200
{
"access_token": "rm_at_e5988dd1b91a4ff3827c5d2ed416ccbe37ae227a",
"token_type": "Bearer",
"expires_in": 3600
}Risposte di errore
400Manca client_id o client_secret
401Credenziali non valide (secret errato o client_id sconosciuto)
403L'integrazione è stata disattivata
Importa job e fermate
/v1/integration-importHeader della richiesta
| Field | Type | Required | Description |
|---|---|---|---|
| Authorization | string | Yes | Bearer <access_token> |
| Content-Type | string | Yes | application/json |
| Idempotency-Key | string | No | Chiave univoca per evitare import duplicati (valida per 24 ore) |
Corpo della richiesta — Campi del job
| Field | Type | Required | Description |
|---|---|---|---|
| external_job_id | string | Yes | Il tuo identificatore univoco per questo job (deve essere unico per integrazione) |
| title | string | Yes | Titolo del job (ad esempio Morning Deliveries - Zone A) |
| driver_email | string | Yes | Email del driver da assegnare. Se il driver ha un account RouteMate, vedrà il percorso nella sua app. In caso contrario verrà creata un'invito. |
| scheduled_date | string | No | Data pianificata in formato ISO (YYYY-MM-DD) |
| timezone | string | No | Fuso orario IANA (ad esempio Australia/Brisbane o America/New_York) |
| metadata | object | No | Dati chiave-valore personalizzati associati al job |
| stops | array | Yes | Array di oggetti fermata (vedi Campi della fermata qui sotto) |
Richiesta di esempio
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
}
]
}'Risposta di successo 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" }
]
}Nota: Nota: l'array stops viene restituito nell'ordine di consegna ottimizzato in base a sort_order, non nell'ordine inviato.
Codici di avviso
| Field | Type | Required | Description |
|---|---|---|---|
| ROUTE_OPTIMIZED | info | No | Il percorso è stato ottimizzato correttamente con distanza e durata |
| ADDRESS_GEOCODED | info | No | Una o più fermate sono state geocodificate dal testo dell'indirizzo |
| DRIVER_AUTO_ADDED | info | No | Il driver aveva già un account RouteMate ed è stato aggiunto automaticamente alla tua organizzazione |
| DRIVER_NOT_FOUND | warning | No | Nessun account RouteMate trovato per questa email. È stato creato un invito. |
| GEOCODE_FAILED | warning | No | Impossibile geocodificare l'indirizzo di una fermata. Fornisci invece latitude/longitude. |
Consulta stato job
/v1/integration-jobsParametri di query
| Field | Type | Required | Description |
|---|---|---|---|
| external_job_id | string | No | Il tuo ID job esterno (quello fornito durante l'importazione) |
| job_id | string | No | UUID interno del job in RouteMate |
È necessario fornire almeno external_job_id o job_id.
Richiesta di esempio
curl "https://api.routemate.app/v1/integration-jobs?external_job_id=BATCH-2026-03-09-A" \
-H "Authorization: Bearer rm_at_your_token_here"Risposta di successo 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"
}Stati del job
| Field | Type | Required | Description |
|---|---|---|---|
| pending | status | No | Job creato ma il driver non è ancora stato assegnato o risolto |
| assigned | status | No | Il driver è stato assegnato e può vedere il percorso nella sua app |
| in_progress | status | No | Il driver ha iniziato il percorso |
| completed | status | No | Tutte le fermate sono state consegnate |
Campi della fermata
Elenco completo dei campi disponibili per ogni fermata nella richiesta di importazione.
| Field | Type | Required | Description |
|---|---|---|---|
| external_stop_id | string | Yes | Il tuo identificatore univoco per questa fermata (deve essere unico all'interno del job) |
| address | string | Yes | Indirizzo completo. Verrà geocodificato se latitude/longitude non vengono forniti. |
| latitude | number | No | Latitudine in gradi decimali. Salta la geocodifica se fornita insieme a longitude. |
| longitude | number | No | Longitudine in gradi decimali. Salta la geocodifica se fornita insieme a latitude. |
| label | string | No | Etichetta visibile (ad esempio nome cliente o numero ordine) |
| notes | string | No | Istruzioni di consegna per il driver |
| service_type | string | No | Tipo di servizio (ad esempio delivery, pickup o service_call) |
| duration_minutes | number | No | Durata prevista del servizio presso questa fermata, in minuti |
| time_window_start | string | No | Orario più anticipato di consegna (datetime ISO 8601) |
| time_window_end | string | No | Orario ultimo di consegna (datetime ISO 8601) |
| priority | number | No | Livello di priorità (numero più basso = priorità più alta). Predefinito: 0 |
| parcel_count | number | No | Numero di colli per questa fermata. Predefinito: 1 |
| metadata | object | No | Dati chiave-valore personalizzati associati a questa fermata |
Suggerimento: Suggerimento: fornire direttamente latitude e longitude è più veloce e affidabile del geocoding.
Ottimizzazione del percorso
Ogni import ottimizza automaticamente la sequenza di consegna per ridurre distanza e tempo di guida.
Come funziona l'ottimizzazione
- Tutte le fermate senza coordinate vengono geocodificate dal testo dell'indirizzo
- La prima fermata viene trattata come origine e l'ultima come destinazione
- Tutte le fermate intermedie vengono ottimizzate per il percorso più breve usando la Google Routes API
- Il campo sort_order di ogni fermata viene aggiornato per riflettere la sequenza ottimizzata
- Vengono calcolati polilinea del percorso, distanza totale e durata stimata
Campi della risposta
| Field | Type | Required | Description |
|---|---|---|---|
| optimization.total_distance_km | number | No | Distanza totale del percorso in chilometri |
| optimization.total_duration_minutes | number | No | Tempo totale di guida stimato in minuti |
| optimization.encoded_polyline | string | No | Google Encoded Polyline per disegnare il percorso su una mappa |
Nota: Nota: l'ottimizzazione richiede almeno 2 fermate con coordinate valide. Se la geocodifica fallisce per alcune fermate, il percorso verrà ottimizzato usando solo quelle geocodificate correttamente.
Idempotenza
Riprova in sicurezza le richieste fallite senza creare job duplicati.
Includi un header Idempotency-Key con un valore univoco nelle richieste di importazione. Se la stessa chiave viene inviata entro 24 ore, la API restituirà la risposta in cache invece di creare un job duplicato.
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 '{ ... }'Buona pratica: Usa sempre un Idempotency-Key in produzione. Preferisci una chiave deterministica per evitare duplicati durante i retry di rete.
Gestione degli errori
Tutti gli errori restituiscono un corpo JSON con un campo error.
{
"error": "Rate limit exceeded",
"retry_after_seconds": 45
}
// oppure per gli errori di validazione:
{
"error": {
"code": "VALIDATION_ERROR",
"messages": [
"external_job_id is required",
"stops[0].address is required"
]
}
}| Stato | Significato | Azione |
|---|---|---|
| 200 | Successo | La richiesta è stata completata correttamente |
| 400 | Richiesta non valida | Controlla i messaggi di errore e correggi il corpo della richiesta |
| 401 | Non autorizzato | Il tuo token non è valido o è scaduto. Ottienine uno nuovo. |
| 403 | Proibito | La tua integrazione è stata disattivata. Contatta il tuo amministratore. |
| 404 | Non trovato | Il job o l'endpoint non esiste |
| 405 | Metodo non consentito | Usa il metodo HTTP corretto (POST o GET) |
| 429 | Troppe richieste | Attendi retry_after_seconds prima di riprovare |
| 500 | Errore del server | Riprova con exponential backoff. Contatta il supporto se il problema persiste. |
Rate limits
I limiti si applicano per integrazione su una finestra mobile di 1 minuto.
| Piano | Richieste / minuto | Max fermate / import |
|---|---|---|
| Team | 60 | 200 |
| Enterprise | Custom | Custom |
Quando viene applicato il rate limit, la API restituisce HTTP 429 con un campo retry_after_seconds.
Esempi di codice completi
Esempi pronti da copiare per i linguaggi più comuni. Tutti mostrano il flusso completo: autenticazione, import e query.
#!/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 .Webhook
Ricevi notifiche in tempo reale quando le consegne vengono completate.
Il supporto webhook arriverà presto. Potrai registrare un URL e ricevere notifiche POST per eventi come:
- job.completed — Tutte le fermate di un job sono state consegnate
- stop.completed — Una singola fermata è stata completata (include prova di consegna)
- stop.failed — Un tentativo di consegna non è riuscito
- driver.location — Aggiornamenti GPS del driver in tempo reale
Ti interessa l'accesso anticipato? Contattaci.