Resolva rotas de entrega em segundos
Informe os pontos, escolha entre TSP, VRP ou matriz de distâncias e receba o resultado otimizado direto no navegador — com mapa, resumo e JSON para integrar. Sem cadastro.
Fluxo
Como funciona
Três passos e o resultado aparece no mapa e no JSON.
Informe os pontos
Digite lat/lng, importe um CSV/JSON ou busque por endereço.
Escolha e otimize
Selecione o tipo de problema (TSP, VRP ou matriz) e clique em Otimizar.
Visualize o resultado
Rota desenhada no mapa, resumo em números e JSON para baixar.
Problema
O que você quer resolver?
Cada tipo gera um payload diferente. Você só preenche os pontos.
Origem (depósito)
Paradas
| Nome | Latitude | Longitude | ||
|---|---|---|---|---|
| 1 | ||||
| 2 | ||||
| 3 |
Mapa
Carregando mapa…
Arraste os marcadores para ajustar. Para inserir pontos, ative "Adicionar ponto no mapa" e clique onde quiser.
Rota única (TSP)
Euclidiana (linha reta) · 3 pontos · origem definida
Integração
Usar via API
A mesma otimização disponível por HTTP. Jobs são assíncronos: envie, faça polling e receba o resultado.
Documentação interativa e testável
Explore e teste todos os endpoints (jobs, status, resultado e saúde) direto no Swagger UI.
Criar o job
POST /api/v1/jobs/{tipo} — retorna 202 com o id do job em PENDING.
Acompanhar o status
GET /api/v1/jobs/{id} — faça polling até DONE ou ERROR.
Receber o resultado
GET /api/v1/jobs/{id}/output — ou receba um POST no webhook.
Por tipo de problema
TSP — Rota única
Caixeiro viajante: visita todas as paradas partindo da origem, na ordem que minimiza o trajeto, e retorna ao início.
Corpo do request
Envelope { webhookUrl, input }. webhookUrl é opcional.
{ "webhookUrl": "https://seu-servidor.com/hook", "input": { "matrixType": "EUCLIDIAN", "origin": { "lat": -23.5505, "lng": -46.6333 }, "stops": [ { "id": "p1", "name": "Parada 1", "location": { "lat": -23.5614, "lng": -46.6559 } }, { "id": "p2", "name": "Parada 2", "location": { "lat": -23.5874, "lng": -46.6576 } }, { "id": "p3", "name": "Parada 3", "location": { "lat": -23.5343, "lng": -46.6339 } } ] }}Resposta 202
202 Created — guarde o id para acompanhar.
{ "id": "c8d3525c-ff82-4ec9-9c50-d4f753e85502", "type": "TSP", "status": "PENDING", "inputUrl": "http://localhost:8080/api/v1/jobs/.../input", "outputUrl": null, "statusUrl": "http://localhost:8080/api/v1/jobs/...", "createdAt": "2026-09-02T01:02:36Z", "startedAt": null, "finishedAt": null, "processingTimeMs": null}curl de exemplo
curl -X POST http://localhost:8080/api/v1/jobs/tsp \ -H 'Content-Type: application/json' \ -d '{ "webhookUrl": "https://seu-servidor.com/hook", "input": { "matrixType": "EUCLIDIAN", "origin": { "lat": -23.5505, "lng": -46.6333 }, "stops": [ { "id": "p1", "name": "Parada 1", "location": { "lat": -23.5614, "lng": -46.6559 } }, { "id": "p2", "name": "Parada 2", "location": { "lat": -23.5874, "lng": -46.6576 } }, { "id": "p3", "name": "Parada 3", "location": { "lat": -23.5343, "lng": -46.6339 } } ] } }'Campos
webhookUrlURL que recebe um POST quando o job termina.
input.matrixType"EUCLIDIAN" (linha reta) ou "STREET" (OSRM).
input.origin{ lat, lng } do depósito (origem da rota).
input.stops[]Paradas: id, name e location { lat, lng }. Mínimo 2.
Resultado: paradas otimizadas (optimized_stops), distância total em metros (distance_meters) e a rota (route_line).
VRP — Frota de veículos
Roteiriza a entrega distribuindo os clientes entre os veículos, respeitando o máximo de paradas, peso e volume de cada um.
Corpo do request
Envelope { webhookUrl, input } com clients e vehicles.
{ "webhookUrl": "https://seu-servidor.com/hook", "input": { "matrixType": "EUCLIDIAN", "origin": { "lat": -23.5505, "lng": -46.6333 }, "clients": [ { "id": "c1", "name": "Cliente 1", "location": { "lat": -23.5614, "lng": -46.6559 }, "volumeLiters": 10, "weightKg": 120 }, { "id": "c2", "name": "Cliente 2", "location": { "lat": -23.5874, "lng": -46.6576 }, "volumeLiters": 25, "weightKg": 340 } ], "vehicles": [ { "name": "Van", "maxDeliveries": 10, "maxWeightKg": 1000, "maxVolumeLiters": 200 }, { "name": "Carro", "maxDeliveries": 5, "maxWeightKg": 400, "maxVolumeLiters": 80 } ] }}Resposta 202
202 Created — o campo type vem como VRP.
{ "id": "c8d3525c-ff82-4ec9-9c50-d4f753e85502", "type": "TSP", "status": "PENDING", "inputUrl": "http://localhost:8080/api/v1/jobs/.../input", "outputUrl": null, "statusUrl": "http://localhost:8080/api/v1/jobs/...", "createdAt": "2026-09-02T01:02:36Z", "startedAt": null, "finishedAt": null, "processingTimeMs": null}curl de exemplo
curl -X POST http://localhost:8080/api/v1/jobs/vrp \ -H 'Content-Type: application/json' \ -d '{ "webhookUrl": "https://seu-servidor.com/hook", "input": { "matrixType": "EUCLIDIAN", "origin": { "lat": -23.5505, "lng": -46.6333 }, "clients": [ { "id": "c1", "name": "Cliente 1", "location": { "lat": -23.5614, "lng": -46.6559 }, "volumeLiters": 10, "weightKg": 120 }, { "id": "c2", "name": "Cliente 2", "location": { "lat": -23.5874, "lng": -46.6576 }, "volumeLiters": 25, "weightKg": 340 } ], "vehicles": [ { "name": "Van", "maxDeliveries": 10, "maxWeightKg": 1000, "maxVolumeLiters": 200 }, { "name": "Carro", "maxDeliveries": 5, "maxWeightKg": 400, "maxVolumeLiters": 80 } ] } }'Campos
webhookUrlURL que recebe um POST quando o job termina.
input.matrixType"EUCLIDIAN" (linha reta) ou "STREET" (OSRM).
input.origin{ lat, lng } do depósito (saída das rotas).
input.clients[]Clientes: id, name, location { lat, lng }, volumeLiters (L) e weightKg (kg). Mínimo 1.
input.vehicles[]Veículos: name, maxDeliveries, maxWeightKg e maxVolumeLiters. Mínimo 1.
Resultado: uma rota por veículo (routes), com clientes, distância, peso e volume de cada rota.
Matriz de distâncias
Calcula as distâncias entre todos os pares de pontos informados — não usa origem: a matriz cobre todos os pares.
Corpo do request
Envelope { webhookUrl, input } com as coordenadas.
{ "webhookUrl": "https://seu-servidor.com/hook", "input": { "matrixType": "EUCLIDIAN", "coordinates": [ { "lat": -23.5614, "lng": -46.6559 }, { "lat": -23.5874, "lng": -46.6576 }, { "lat": -23.5343, "lng": -46.6339 } ] }}Resposta 202
202 Created — o campo type vem como DISTANCE_MATRIX.
{ "id": "c8d3525c-ff82-4ec9-9c50-d4f753e85502", "type": "TSP", "status": "PENDING", "inputUrl": "http://localhost:8080/api/v1/jobs/.../input", "outputUrl": null, "statusUrl": "http://localhost:8080/api/v1/jobs/...", "createdAt": "2026-09-02T01:02:36Z", "startedAt": null, "finishedAt": null, "processingTimeMs": null}curl de exemplo
curl -X POST http://localhost:8080/api/v1/jobs/distance-matrix \ -H 'Content-Type: application/json' \ -d '{ "webhookUrl": "https://seu-servidor.com/hook", "input": { "matrixType": "EUCLIDIAN", "coordinates": [ { "lat": -23.5614, "lng": -46.6559 }, { "lat": -23.5874, "lng": -46.6576 }, { "lat": -23.5343, "lng": -46.6339 } ] } }'Campos
webhookUrlURL que recebe um POST quando o job termina.
input.matrixType"EUCLIDIAN" (linha reta) ou "STREET" (OSRM).
input.coordinates[]Pontos { lat, lng } — a matriz é entre todos os pares. Mínimo 2.
Resultado: matriz N×N de distâncias em metros (matrix) mais as coordenadas.
Acompanhar o job e receber o resultado
Faça polling no status até DONE (ou ERROR) e depois baixe o resultado. Todos os campos da entidade job vêm no status.
Resposta 200 (status)
status: PENDING → RUNNING → DONE | ERROR.
{ "id": "2603bbcc-5142-4e09-8cd4-0c96453e8056", "type": "TSP", "status": "DONE", "inputUrl": "http://localhost:8080/api/v1/jobs/.../input", "outputUrl": "http://localhost:8080/api/v1/jobs/.../output", "statusUrl": "http://localhost:8080/api/v1/jobs/...", "webhookUrl": null, "errorMessage": null, "processingTimeMs": 2, "createdAt": "2026-09-02T01:02:36Z", "startedAt": null, "finishedAt": "2026-09-02T01:02:36Z", "inputPath": "inputs/....json", "outputPath": "solutions/....json"}Resultado — GET /api/v1/jobs/{id}/output
Disponível quando o status é DONE (exemplo TSP).
{ "optimized_stops": [ { "id": "p1", "customer_name": "Parada 1", "address": { "latitude": -23.5614, "longitude": -46.6559 } } ], "route_line": [ { "lat": -23.5505, "lng": -46.6333 }, { "lat": -23.5614, "lng": -46.6559 } ], "distance_meters": 33595.49, "time_to_solve_ms": 0.23}Webhook opcional
Se webhookUrl for enviado no POST, o backend chama essa URL com um POST quando o job termina — não precisa de polling.
Rate limit por IP
~10 jobs/min, ~100 consultas/min e ~30 geocodificações/min. Em excesso, a API responde 429.