Documentação API
Tudo o que precisa para integrar a sua plataforma de entregas com o RouteMate.
Conteúdo
Primeiros passos
A Integration API do RouteMate permite importar jobs de entrega de forma programática, otimizar rotas automaticamente e consultar o estado dos jobs a partir dos seus sistemas atuais.
URL base
https://api.routemate.app/v1Como funciona
- Criar uma integração — Na aplicação web do RouteMate, vá a Integrações e clique em Criar integração. Receberá um client_id e um client_secret.
- Obter um token de acesso — Troque as suas credenciais por um bearer token temporário válido durante 1 hora.
- Importar um job — Envie as suas paragens de entrega por POST. O RouteMate geocodifica os endereços, otimiza a ordem da rota e atribui o job a um motorista.
- Consultar o estado — Verifique o progresso do job a qualquer momento para ver quais paragens já foram concluídas.
Requisitos
- Uma conta RouteMate no plano Team ou Enterprise
- Uma organização criada na aplicação web do RouteMate
- Uma integração ativa com credenciais de cliente
Fluxo de client credentials
A API utiliza credenciais de cliente OAuth2. O seu secret nunca é armazenado: apenas um hash SHA-256 fica guardado nos nossos servidores.
Modelo de segurança
- Os client secrets são hashados com SHA-256 e nunca armazenados em texto simples
- Os tokens de acesso são opacos (não são JWT) e válidos por 1 hora
- Os tokens são de utilização única e limitados à sua integração
- Todos os pedidos devem ser feitos por HTTPS
- Inclua o token em todos os pedidos: Authorization: Bearer <token>
Importante: O seu client_secret é mostrado apenas uma vez quando cria a integração. Guarde-o de forma segura, por exemplo em variáveis de ambiente ou num gestor de segredos. Se o perder, terá de o regenerar no dashboard do RouteMate.
Obter token de acesso
/v1/integration-tokenCorpo do pedido
| Field | Type | Required | Description |
|---|---|---|---|
| client_id | string | Yes | O client ID da sua integração (começa por rm_ci_) |
| client_secret | string | Yes | O client secret da sua integração (começa por rm_cs_) |
Pedido de exemplo
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..."
}'Resposta de sucesso 200
{
"access_token": "rm_at_e5988dd1b91a4ff3827c5d2ed416ccbe37ae227a",
"token_type": "Bearer",
"expires_in": 3600
}Respostas de erro
400Falta client_id ou client_secret
401Credenciais inválidas (secret incorreto ou client_id desconhecido)
403A integração foi desativada
Importar job e paragens
/v1/integration-importCabeçalhos do pedido
| Field | Type | Required | Description |
|---|---|---|---|
| Authorization | string | Yes | Bearer <access_token> |
| Content-Type | string | Yes | application/json |
| Idempotency-Key | string | No | Chave única para evitar importações duplicadas (válida durante 24 horas) |
Corpo do pedido — Campos do job
| Field | Type | Required | Description |
|---|---|---|---|
| external_job_id | string | Yes | O seu identificador único para este job (tem de ser único por integração) |
| title | string | Yes | Título do job (por exemplo, Morning Deliveries - Zone A) |
| driver_email | string | Yes | Email do motorista a atribuir. Se tiver uma conta RouteMate, verá a rota na aplicação. Caso contrário, será criado um convite. |
| scheduled_date | string | No | Data agendada em formato ISO (YYYY-MM-DD) |
| timezone | string | No | Fuso horário IANA (por exemplo, Australia/Brisbane ou America/New_York) |
| metadata | object | No | Dados personalizados em formato chave-valor associados ao job |
| stops | array | Yes | Array de objetos de paragem (ver Campos da paragem abaixo) |
Pedido de exemplo
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
}
]
}'Resposta de sucesso 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: o array stops é devolvido na ordem de entrega otimizada conforme sort_order, não na ordem em que foi enviado.
Códigos de aviso
| Field | Type | Required | Description |
|---|---|---|---|
| ROUTE_OPTIMIZED | info | No | A rota foi otimizada com sucesso com distância e duração |
| ADDRESS_GEOCODED | info | No | Uma ou mais paragens foram geocodificadas a partir do texto da morada |
| DRIVER_AUTO_ADDED | info | No | O motorista já tinha uma conta RouteMate e foi adicionado automaticamente à sua organização |
| DRIVER_NOT_FOUND | warning | No | Não foi encontrada uma conta RouteMate para este email. Foi criado um convite. |
| GEOCODE_FAILED | warning | No | Não foi possível geocodificar a morada de uma paragem. Forneça latitude/longitude em alternativa. |
Consultar estado do job
/v1/integration-jobsParâmetros de consulta
| Field | Type | Required | Description |
|---|---|---|---|
| external_job_id | string | No | O seu ID externo do job (o mesmo fornecido durante a importação) |
| job_id | string | No | O UUID interno do job no RouteMate |
É necessário fornecer pelo menos external_job_id ou job_id.
Pedido de exemplo
curl "https://api.routemate.app/v1/integration-jobs?external_job_id=BATCH-2026-03-09-A" \
-H "Authorization: Bearer rm_at_your_token_here"Resposta de sucesso 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"
}Estados do job
| Field | Type | Required | Description |
|---|---|---|---|
| pending | status | No | Job criado, mas o motorista ainda não foi atribuído ou resolvido |
| assigned | status | No | O motorista foi atribuído e pode ver a rota na aplicação |
| in_progress | status | No | O motorista iniciou a rota |
| completed | status | No | Todas as paragens foram entregues |
Campos da paragem
Lista completa dos campos disponíveis para cada paragem no pedido de importação.
| Field | Type | Required | Description |
|---|---|---|---|
| external_stop_id | string | Yes | O seu identificador único para esta paragem (tem de ser único dentro do job) |
| address | string | Yes | Morada completa. Será geocodificada se latitude/longitude não forem fornecidas. |
| latitude | number | No | Latitude em graus decimais. Ignora a geocodificação se for enviada com longitude. |
| longitude | number | No | Longitude em graus decimais. Ignora a geocodificação se for enviada com latitude. |
| label | string | No | Etiqueta visível (por exemplo, nome do cliente ou número da encomenda) |
| notes | string | No | Instruções de entrega para o motorista |
| service_type | string | No | Tipo de serviço (por exemplo, delivery, pickup ou service_call) |
| duration_minutes | number | No | Duração estimada do serviço nesta paragem, em minutos |
| time_window_start | string | No | Hora mais cedo para entrega (datetime ISO 8601) |
| time_window_end | string | No | Hora limite para entrega (datetime ISO 8601) |
| priority | number | No | Nível de prioridade (número menor = prioridade maior). Predefinição: 0 |
| parcel_count | number | No | Número de volumes desta paragem. Predefinição: 1 |
| metadata | object | No | Dados personalizados em formato chave-valor associados a esta paragem |
Dica: Dica: fornecer latitude e longitude diretamente é mais rápido e fiável do que geocodificação.
Otimização de rotas
Cada importação otimiza automaticamente a sequência de entrega para reduzir distância e tempo.
Como funciona a otimização
- Todas as paragens sem coordenadas são geocodificadas a partir do texto da morada
- A primeira paragem é tratada como origem e a última como destino
- Todas as paragens intermédias são otimizadas para o percurso mais curto usando a Google Routes API
- O campo sort_order de cada paragem é atualizado para refletir a sequência otimizada
- São calculados a polilinha da rota, a distância total e a duração estimada
Campos da resposta
| Field | Type | Required | Description |
|---|---|---|---|
| optimization.total_distance_km | number | No | Distância total da rota em quilómetros |
| optimization.total_duration_minutes | number | No | Tempo total estimado de condução em minutos |
| optimization.encoded_polyline | string | No | Google Encoded Polyline para apresentar a rota no mapa |
Nota: Nota: a otimização exige pelo menos 2 paragens com coordenadas válidas. Se a geocodificação falhar em algumas paragens, a rota será otimizada apenas com as paragens geocodificadas com sucesso.
Idempotência
Repita pedidos falhados em segurança sem criar jobs duplicados.
Inclua um cabeçalho Idempotency-Key com um valor único nos pedidos de importação. Se a mesma chave for enviada dentro de 24 horas, a API devolverá a resposta em cache em vez de criar um job duplicado.
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 '{ ... }'Boa prática: Inclua sempre um Idempotency-Key em produção. Use uma chave determinística para evitar duplicados em retries de rede.
Tratamento de erros
Todos os erros devolvem um corpo JSON com um campo error.
{
"error": "Rate limit exceeded",
"retry_after_seconds": 45
}
// ou para erros de validação:
{
"error": {
"code": "VALIDATION_ERROR",
"messages": [
"external_job_id is required",
"stops[0].address is required"
]
}
}| Estado | Significado | Ação |
|---|---|---|
| 200 | Sucesso | O pedido foi concluído com sucesso |
| 400 | Pedido inválido | Verifique as mensagens de erro e corrija o corpo do pedido |
| 401 | Não autorizado | O seu token é inválido ou expirou. Obtenha um novo. |
| 403 | Proibido | A sua integração foi desativada. Contacte o seu administrador. |
| 404 | Não encontrado | O job ou o endpoint não existe |
| 405 | Método não permitido | Use o método HTTP correto (POST ou GET) |
| 429 | Demasiados pedidos | Aguarde retry_after_seconds antes de tentar novamente |
| 500 | Erro do servidor | Tente novamente com exponential backoff. Contacte o suporte se persistir. |
Rate limits
Os limites são aplicados por integração numa janela móvel de 1 minuto.
| Plano | Pedidos / minuto | Máx. paragens / importação |
|---|---|---|
| Team | 60 | 200 |
| Enterprise | Custom | Custom |
Quando limitado por taxa, a API devolve HTTP 429 com um campo retry_after_seconds.
Exemplos de código completos
Exemplos prontos a copiar para linguagens comuns. Todos mostram o fluxo completo: autenticar, importar e consultar.
#!/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
Receba notificações em tempo real quando as entregas forem concluídas.
O suporte a webhooks está a chegar. Poderá registar um URL e receber notificações POST para eventos como:
- job.completed — Todas as paragens de um job foram entregues
- stop.completed — Uma única paragem foi concluída (inclui prova de entrega)
- stop.failed — Uma tentativa de entrega falhou
- driver.location — Atualizações GPS do motorista em tempo real
Interessado em acesso antecipado? Contacte-nos.