Dokumentacja API
Wszystko, czego potrzebujesz, aby zintegrować swoją platformę dostaw z RouteMate.
Spis treści
Pierwsze kroki
API integracyjne RouteMate pozwala programowo importować zlecenia dostaw, automatycznie optymalizować trasy i sprawdzać status zleceń z poziomu istniejących systemów.
Bazowy URL
https://api.routemate.app/v1Jak to działa
- Utwórz integrację — W aplikacji webowej RouteMate przejdź do Integracje i kliknij Utwórz integrację. Otrzymasz client_id i client_secret.
- Pobierz token dostępu — Wymień dane uwierzytelniające na tymczasowy bearer token ważny przez 1 godzinę.
- Zaimportuj zlecenie — Wyślij przystanki dostawy przez POST. RouteMate geokoduje adresy, optymalizuje kolejność trasy i przypisuje zlecenie kierowcy.
- Sprawdź status — W dowolnym momencie zobacz postęp zlecenia i sprawdź, które przystanki są już ukończone.
Wymagania
- Konto RouteMate w planie Team lub Enterprise
- Organizacja utworzona w aplikacji webowej RouteMate
- Aktywna integracja z danymi client credentials
Przepływ client credentials
API korzysta z OAuth2 client credentials. Twój secret nigdy nie jest przechowywany w postaci jawnej — na naszych serwerach zapisujemy jedynie hash SHA-256.
Model bezpieczeństwa
- Client secrets są hashowane algorytmem SHA-256 i nigdy nie są przechowywane jawnym tekstem
- Tokeny dostępu są niejawne (to nie JWT) i są ważne przez 1 godzinę
- Tokeny są jednorazowe i ograniczone do Twojej integracji
- Wszystkie żądania muszą być wykonywane przez HTTPS
- Dołącz token do każdego żądania: Authorization: Bearer <token>
Ważne: Twój client_secret jest wyświetlany tylko raz przy tworzeniu integracji. Zapisz go bezpiecznie, na przykład w zmiennych środowiskowych lub menedżerze sekretów. Jeśli go utracisz, musisz wygenerować go ponownie w panelu RouteMate.
Pobierz token dostępu
/v1/integration-tokenTreść żądania
| Field | Type | Required | Description |
|---|---|---|---|
| client_id | string | Yes | Client ID Twojej integracji (zaczyna się od rm_ci_) |
| client_secret | string | Yes | Client secret Twojej integracji (zaczyna się od rm_cs_) |
Przykładowe żądanie
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..."
}'Poprawna odpowiedź 200
{
"access_token": "rm_at_e5988dd1b91a4ff3827c5d2ed416ccbe37ae227a",
"token_type": "Bearer",
"expires_in": 3600
}Odpowiedzi błędów
400Brakuje client_id lub client_secret
401Nieprawidłowe dane uwierzytelniające (błędny secret lub nieznany client_id)
403Integracja została wyłączona
Importuj zlecenie i przystanki
/v1/integration-importNagłówki żądania
| Field | Type | Required | Description |
|---|---|---|---|
| Authorization | string | Yes | Bearer <access_token> |
| Content-Type | string | Yes | application/json |
| Idempotency-Key | string | No | Unikalny klucz zapobiegający duplikatom importu (ważny 24 godziny) |
Treść żądania — Pola zlecenia
| Field | Type | Required | Description |
|---|---|---|---|
| external_job_id | string | Yes | Twój unikalny identyfikator tego zlecenia (musi być unikalny w obrębie integracji) |
| title | string | Yes | Tytuł zlecenia (np. Morning Deliveries - Zone A) |
| driver_email | string | Yes | Email kierowcy do przypisania. Jeśli ma konto RouteMate, zobaczy trasę w aplikacji. W przeciwnym razie zostanie utworzone zaproszenie. |
| scheduled_date | string | No | Zaplanowana data w formacie ISO (YYYY-MM-DD) |
| timezone | string | No | Strefa czasowa IANA (np. Australia/Brisbane lub America/New_York) |
| metadata | object | No | Niestandardowe dane klucz-wartość dołączone do zlecenia |
| stops | array | Yes | Tablica obiektów przystanków (zobacz pola przystanku poniżej) |
Przykładowe żądanie
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
}
]
}'Poprawna odpowiedź 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" }
]
}Uwaga: Uwaga: tablica stops jest zwracana w zoptymalizowanej kolejności dostaw według sort_order, a nie w kolejności wysłania.
Kody ostrzeżeń
| Field | Type | Required | Description |
|---|---|---|---|
| ROUTE_OPTIMIZED | info | No | Trasa została pomyślnie zoptymalizowana wraz z dystansem i czasem |
| ADDRESS_GEOCODED | info | No | Jeden lub więcej przystanków zostało zgeokodowanych na podstawie adresu |
| DRIVER_AUTO_ADDED | info | No | Kierowca miał konto RouteMate i został automatycznie dodany do Twojej organizacji |
| DRIVER_NOT_FOUND | warning | No | Nie znaleziono konta RouteMate dla tego adresu email. Utworzono zaproszenie. |
| GEOCODE_FAILED | warning | No | Nie udało się zgeokodować adresu przystanku. Zamiast tego podaj latitude/longitude. |
Sprawdź status zlecenia
/v1/integration-jobsParametry zapytania
| Field | Type | Required | Description |
|---|---|---|---|
| external_job_id | string | No | Twój zewnętrzny ID zlecenia (podany podczas importu) |
| job_id | string | No | Wewnętrzny UUID zlecenia w RouteMate |
Musisz podać co najmniej external_job_id lub job_id.
Przykładowe żądanie
curl "https://api.routemate.app/v1/integration-jobs?external_job_id=BATCH-2026-03-09-A" \
-H "Authorization: Bearer rm_at_your_token_here"Poprawna odpowiedź 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"
}Statusy zlecenia
| Field | Type | Required | Description |
|---|---|---|---|
| pending | status | No | Zlecenie zostało utworzone, ale kierowca nie został jeszcze przypisany lub rozpoznany |
| assigned | status | No | Kierowca został przypisany i może zobaczyć trasę w aplikacji |
| in_progress | status | No | Kierowca rozpoczął trasę |
| completed | status | No | Wszystkie przystanki zostały dostarczone |
Pola przystanku
Pełna lista pól dostępnych dla każdego przystanku w żądaniu importu.
| Field | Type | Required | Description |
|---|---|---|---|
| external_stop_id | string | Yes | Twój unikalny identyfikator tego przystanku (musi być unikalny w obrębie zlecenia) |
| address | string | Yes | Pełny adres uliczny. Zostanie zgeokodowany, jeśli latitude/longitude nie zostaną podane. |
| latitude | number | No | Szerokość geograficzna w stopniach dziesiętnych. Pomija geokodowanie, jeśli podano także longitude. |
| longitude | number | No | Długość geograficzna w stopniach dziesiętnych. Pomija geokodowanie, jeśli podano także latitude. |
| label | string | No | Etykieta wyświetlana użytkownikowi (np. nazwa klienta lub numer zamówienia) |
| notes | string | No | Instrukcje dostawy dla kierowcy |
| service_type | string | No | Typ usługi (np. delivery, pickup lub service_call) |
| duration_minutes | number | No | Przewidywany czas obsługi na tym przystanku w minutach |
| time_window_start | string | No | Najwcześniejszy czas dostawy (ISO 8601 datetime) |
| time_window_end | string | No | Najpóźniejszy czas dostawy (ISO 8601 datetime) |
| priority | number | No | Poziom priorytetu (mniejsza liczba = wyższy priorytet). Domyślnie: 0 |
| parcel_count | number | No | Liczba paczek dla tego przystanku. Domyślnie: 1 |
| metadata | object | No | Niestandardowe dane klucz-wartość dołączone do tego przystanku |
Wskazówka: Wskazówka: bezpośrednie przekazywanie latitude i longitude jest szybsze i bardziej niezawodne niż geokodowanie.
Optymalizacja trasy
Każdy import automatycznie optymalizuje kolejność dostaw, aby zminimalizować dystans i czas jazdy.
Jak działa optymalizacja
- Wszystkie przystanki bez współrzędnych są geokodowane na podstawie tekstu adresu
- Pierwszy przystanek jest traktowany jako punkt początkowy, a ostatni jako punkt docelowy
- Wszystkie przystanki pośrednie są optymalizowane pod kątem najkrótszej trasy przejazdu przy użyciu Google Routes API
- Pole sort_order dla każdego przystanku jest aktualizowane tak, aby odzwierciedlało zoptymalizowaną kolejność
- Obliczane są polilinia trasy, całkowity dystans i szacowany czas
Pola odpowiedzi
| Field | Type | Required | Description |
|---|---|---|---|
| optimization.total_distance_km | number | No | Łączny dystans trasy w kilometrach |
| optimization.total_duration_minutes | number | No | Szacowany łączny czas jazdy w minutach |
| optimization.encoded_polyline | string | No | Google Encoded Polyline do wyświetlenia trasy na mapie |
Uwaga: Uwaga: optymalizacja wymaga co najmniej 2 przystanków z prawidłowymi współrzędnymi. Jeśli geokodowanie nie powiedzie się dla części przystanków, trasa zostanie zoptymalizowana tylko z użyciem tych, które udało się zgeokodować.
Idempotencja
Bezpiecznie ponawiaj nieudane żądania bez tworzenia duplikatów zleceń.
Dodaj do żądań importu nagłówek Idempotency-Key z unikalną wartością. Jeśli ten sam klucz zostanie wysłany ponownie w ciągu 24 godzin, API zwróci zapisaną odpowiedź zamiast tworzyć duplikat zlecenia.
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 '{ ... }'Dobra praktyka: Zawsze używaj Idempotency-Key w produkcji. Użyj deterministycznego klucza, aby ponowienia sieciowe nie tworzyły duplikatów.
Obsługa błędów
Wszystkie błędy zwracają odpowiedź JSON z polem error.
{
"error": "Rate limit exceeded",
"retry_after_seconds": 45
}
// lub dla błędów walidacji:
{
"error": {
"code": "VALIDATION_ERROR",
"messages": [
"external_job_id is required",
"stops[0].address is required"
]
}
}| Status | Znaczenie | Działanie |
|---|---|---|
| 200 | Sukces | Żądanie zostało wykonane poprawnie |
| 400 | Nieprawidłowe żądanie | Sprawdź komunikaty o błędzie i popraw treść żądania |
| 401 | Brak autoryzacji | Token jest nieważny lub wygasł. Pobierz nowy. |
| 403 | Zabronione | Integracja została wyłączona. Skontaktuj się z administratorem. |
| 404 | Nie znaleziono | Zlecenie lub endpoint nie istnieje |
| 405 | Niedozwolona metoda | Użyj właściwej metody HTTP (POST lub GET) |
| 429 | Za dużo żądań | Poczekaj retry_after_seconds przed ponowną próbą |
| 500 | Błąd serwera | Spróbuj ponownie z exponential backoff. Jeśli problem się utrzymuje, skontaktuj się ze wsparciem. |
Limity żądań
Limity są stosowane dla każdej integracji w ruchomym oknie 1 minuty.
| Plan | Żądania / minuta | Maks. przystanków / import |
|---|---|---|
| Team | 60 | 200 |
| Enterprise | Custom | Custom |
Przy ograniczeniu liczby żądań API zwraca HTTP 429 z polem retry_after_seconds.
Pełne przykłady kodu
Gotowe do wklejenia przykłady dla popularnych języków. Wszystkie pokazują pełny przepływ: uwierzytelnienie, import i zapytanie.
#!/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 .Webhooki
Otrzymuj powiadomienia w czasie rzeczywistym, gdy dostawy zostaną zakończone.
Obsługa webhooków pojawi się wkrótce. Będzie można zarejestrować URL i otrzymywać powiadomienia POST dla zdarzeń takich jak:
- job.completed — Wszystkie przystanki w zleceniu zostały dostarczone
- stop.completed — Pojedynczy przystanek został ukończony (z potwierdzeniem dostawy)
- stop.failed — Próba dostawy zakończyła się niepowodzeniem
- driver.location — Aktualizacje GPS kierowcy w czasie rzeczywistym
Chcesz uzyskać wcześniejszy dostęp? Skontaktuj się z nami.