Documentação técnica · API v1

Referência da API de Parceiros — vale para os dois modelos

Autenticação, endpoints, payloads, erros e webhooks. Preços e recursos de cada plano estão nas páginas dos modelos — aqui é só o que o seu programador precisa.

BASE URL https://rotapro.net.br/v1
Autenticação Ping POST /v1/resolve Sessões (Modelo 2) Webhooks Erros

# Autenticação

Toda chamada exige sua API key no header — server-to-server apenas, nunca exponha a key no front-end ou no app. A key é gerada (e revogada) por você mesmo no painel do parceiro e exibida uma única vez na emissão.

Authorization: Bearer rl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Key ausente ou inválida → 401. Limite de requisições excedido → 429 (padrão 60 req/min, ajustável por contrato). Período de teste encerrado → 402 (500 pedidos grátis / 30 dias — depois disso, liberação de produção via contrato).

# Teste de conexão

GET/v1/ping

curl -H "Authorization: Bearer rl_live_SUA_KEY" https://rotapro.net.br/v1/ping
{ "success": true, "message": "pong", "partner": { "nome": "Sua Plataforma", "slug": "sua-plataforma" }, "ts": "..." }

# Gerar rota

POST/v1/resolve

Recebe até 25 pedidos por chamada e devolve endereços geocodificados, ordem otimizada de entrega e link do Google Maps. Stateless: nada fica gravado — quem guarda o resultado é você.

origin é obrigatório. É o endereço do estabelecimento de onde as entregas partem — a âncora que desambigua ruas parecidas, valida cidade/raio e ordena as paradas. Geocodifique uma vez, guarde lat/lng e reutilize. Vários estabelecimentos? Envie o origin correspondente em cada chamada. Sem ele → 400 ORIGIN_REQUIRED.

Requisição

{
  "origin": { "lat": -26.4851, "lng": -49.0713, "city": "Guaramirim", "uf": "SC" },
  "orders": [
    {
      "external_id": "pedido-8841",
      "structured": {
        "numero_pedido": "8841",
        "cliente_nome": "Maria Silva",
        "telefone": "47999990000",
        "localizador": "ABC123",
        "valor_total": 54.90,
        "forma_pagamento": "PIX",
        "endereco": {
          "logradouro": "Rua 28 de Agosto", "numero": "2200",
          "bairro": "Centro", "cidade": "Guaramirim",
          "uf": "SC", "cep": "89270-000",
          "complemento": "Apto 32", "referencia": "Próximo ao mercado"
        }
      }
    },
    { "external_id": "pedido-8842", "text": "texto integral da comanda..." },
    { "external_id": "pedido-8843", "image": { "fileName": "comanda.jpg", "data": "<base64>" } }
  ]
}

Formas de entrada (exatamente uma por pedido)

FormaQuando usarObservações
structuredVocê já tem os campos no seu sistemaMais rápido e preciso. Só endereco é obrigatório. Sem custo adicional
textSó tem o texto cru da comandaMáx. 20.000 caracteres. Processado por IA, sem custo adicional
imageSó tem foto/scan da comandaBase64, máx. ~6 MB. OCR + IA — adicional de R$ 0,05/pedido (repasse do custo de processamento)

Resposta 200

{
  "success": true,
  "mapsLink": "https://www.google.com/maps/dir/?api=1&travelmode=driving&waypoints=...&destination=...",
  "mapsAppLink": "https://www.google.com/maps/dir/?api=1&...",
  "orders": [
    {
      "external_id": "pedido-8841",
      "order": 1,
      "numero_pedido": "8841",
      "cliente_nome": "Maria Silva",
      "telefone": "47999990000",
      "valor_total": 54.90,
      "forma_pagamento": "PIX",
      "troco": null,
      "endereco": { "logradouro": "Rua 28 de Agosto", "numero": "2200", "bairro": "Centro", "cidade": "Guaramirim", "uf": "SC" },
      "lat": -26.4702,
      "lng": -49.0028,
      "number_not_confirmed": false,
      "city_mismatch": false
    }
  ],
  "rejected": [
    { "external_id": "pedido-8842", "reason": "NO_GOOGLE_RESULTS" }
  ]
}
CampoSignificado
orders[]Já na ordem otimizada de entrega (order: 1, 2, 3...)
mapsLinkAbre a rota completa no Google Maps, paradas na ordem certa
number_not_confirmedtrue = o número exato não foi confirmado pelo geocoder; a coordenada é do logradouro — avise o entregador
city_mismatchtrue = a cidade encontrada difere da informada, mas está dentro do raio aceitável
rejected[]Pedidos não roteirizáveis, com o motivo — não bloqueiam os demais. Motivos: INSUFFICIENT_DATA, NO_GOOGLE_RESULTS, EXTRACT_FAILED, EXTRACT_EMPTY
Boas práticas: prefira structured quando tiver os dados · cacheie o origin geocodificado · sempre envie external_id (é como você reconcilia resposta e rejeitados) · trate os rejected no seu operador · agrupe pedidos da mesma leva numa única chamada — a ordenação só faz sentido com os pedidos juntos.

# Sessões — App do Entregador (recurso do Modelo 2)

Mesmo payload do /v1/resolve — mas em vez de devolver só os dados, a RotaLink cria uma sessão de entrega e devolve a URL que o seu app abre no webview do entregador (com a sua marca). Guia completo com código Android/iOS, acompanhamento e segurança: baixe no painel do parceiro.

EndpointO que faz
POST/v1/sessionsCria a sessão (resolve os endereços) e devolve session_id + url assinada. ⚠️ A url só aparece nesta resposta — guarde-a. Validade: 12h
GET/v1/sessions/:idStatus da corrida: delivery_status por pedido (pendenteentregue), telefone coletado, completed automático na última entrega
POST/v1/sessions/:id/refreshNova URL/token (sessão expirada ou token vazado). Sessão concluída não renova (404)
Campos que mudam a experiência do entregador: telefone do cliente habilita os 4 botões de aviso por WhatsApp · localizador (iFood) habilita copiar em 1 clique + abrir o site de confirmação · sem telefone, o entregador coleta na porta e o número volta pra você via GET/webhook.

# Webhooks (Modelo 2 · tempo real)

Configure a URL no painel (card Webhooks, com botão "Enviar teste"). Todo POST vem assinado — valide antes de processar.

EventoQuando dispara
delivery.confirmedEntregador confirmou uma entrega (session_id, external_id, numero_pedido, delivered_at)
phone.collectedWhatsApp coletado na porta (session_id, external_id, telefone)
session.completedÚltima entrega da rota concluída (session_id, total_orders)
webhook.testBotão de teste do painel
HeaderUso
X-RotaLink-Signaturesha256=<hmac> — HMAC-SHA256 do corpo bruto com o signing secret (exibido uma vez ao salvar a URL)
X-RotaLink-DeliveryID único da entrega — use para idempotência (retries reenviam o mesmo id)

Esperamos 2xx em até 8s. Falhou? Retry com backoff exponencial (30s → 1h), até 8 tentativas.

# Erros

HTTPerrorSignificado
400ORIGIN_REQUIREDorigin ausente ou sem lat/lng nem endereco
400ORDERS_REQUIREDorders vazio ou ausente
400TOO_MANY_ORDERSMais de 25 pedidos na chamada
400INVALID_ORDERItem sem forma de entrada válida (detalhe em message)
401INVALID_API_KEYKey ausente, inválida ou revogada
402TRIAL_EXHAUSTEDPeríodo de teste (500 pedidos / 30 dias) encerrado — fale com a RotaLink para liberar produção
403MODEL_NOT_ENABLEDSessões fazem parte do Modelo 2 — troque de plano no painel
422ORIGIN_NOT_GEOCODEDEndereço de origem não geocodificável
422NO_VALID_ADDRESSESNenhum pedido pôde ser geocodificado (rejected traz os motivos)
429RATE_LIMIT_EXCEEDEDLimite de req/min excedido
500INTERNAL_ERRORErro interno — repita a chamada

Específicos de sessões

HTTPerrorSignificado
401INVALID_SESSION_TOKENToken da URL inválido
401SESSION_EXPIREDSessão expirou (12h) — use o refresh
410SESSION_COMPLETEDRota já concluída
404SESSION_NOT_FOUNDID inexistente, de outro parceiro — ou, no refresh, sessão já concluída