store.loog.ai — API v1
API HTTP+JSON para integração programática com os serviços da Loog. Esta v1 cobre o produto vpo-sem-parar (Vale-Pedágio Obrigatório via Sem Parar). Próximos produtos: ciot-ailog, cte-*, mdfe-* — todos seguirão a mesma taxonomia.
Base URL
https://store.loog.ai/api/v1
Não há subdomain por ambiente — o ambiente (HMLG ou PROD) é definido pelo token.
Autenticação
Todas as requests precisam de um API token no header:
Authorization: Bearer loog_prod_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Ou, opcionalmente:
X-Loog-Token: loog_prod_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Como obter um token
- Acesse https://store.loog.ai/configuracoes/api-tokens com um usuário gestor/admin do seu tenant
- Clique "Novo token", dê um nome descritivo (ex: "ERP SAP", "Querocarga", "Mobile App") e escolha o ambiente
- Copie o token imediatamente — ele só aparece uma vez. Depois fica só o hash no banco.
Estrutura do token
loog_{env}_{base64url(32 bytes aleatórios)}
loog_hmlg_*— só atua em HMLG (homologação, dados fake, sem cobrança)loog_prod_*— atua em PROD (emite VPO real, debita saldo)
Um token PROD nunca consegue acessar dados/viagens de HMLG e vice-versa — isolamento estrito.
Códigos de erro de autenticação
| Status | Significado |
|---|---|
401 Token ausente |
Header não veio ou está malformatado |
401 Token inválido |
Token não bate com nenhum hash ativo |
401 Token revogado |
Token foi revogado pelo admin do tenant |
401 Token expirado |
Passou da data expires_at |
403 Token sem permissão pro serviço "X" |
Token foi criado sem scope para esse produto |
Taxonomia de endpoints
/api/v1/{produto}/{ação}[/{id}]
{produto}é o serviço Loog:vpo-sem-parar,ciot-ailog(futuro), etc.{ação}é o verbo:route-preview,emit,status,cancel, etc.{id}opcional dependendo da ação (status e cancel precisam, emit e preview não)
Endpoints disponíveis na v1
| Método | Endpoint | Descrição |
|---|---|---|
| POST | /v1/vpo/sem-parar/route-preview |
Calcula praças+custo de uma rota (sem emitir) |
| POST | /v1/vpo/sem-parar/verificar-placa |
Verifica se a placa está apta (TAG Sem Parar ativa) |
| POST | /v1/vpo/sem-parar/emit |
Emite um VPO completo |
| GET | /v1/vpo/sem-parar/list |
Lista VPOs do tenant (paginado, filtros) |
| GET | /v1/vpo/sem-parar/status/{viagemId} |
Consulta status + recibo de uma viagem emitida |
| POST | /v1/vpo/sem-parar/cancel/{viagemId} |
Cancela uma viagem (estorna créditos em prod) |
| GET | /v1/vpo/sem-parar/saldo |
Saldo de créditos pré-pagos Loog do tenant |
1. Preview de rota — calcular custo antes de emitir
POST /api/v1/vpo/sem-parar/route-preview
Útil pra mostrar ao usuário do seu sistema (ERP, marketplace) quanto vai custar o VPO antes de pagar. Não emite nada, não debita saldo.
Request
{
"origem": { "lat": -18.9186, "lng": -48.2772 },
"destino": { "lat": -23.5505, "lng": -46.6333 },
"paradas": [
{ "lat": -19.7472, "lng": -47.9381 }
],
"eixos": 6
}
Campos:
origem(obrigatório):{ lat, lng }numéricosdestino(obrigatório): idemparadas(opcional): array de{ lat, lng }— paradas intermediárias na ordem da viagemeixos(opcional, default 6): número de eixos do veículo (2 a 10)
Response 200
{
"ok": true,
"env": "prod",
"totalKm": 870,
"custoTotal": 235.67,
"eixos": 6,
"pracas": [
{
"id": 572,
"praca": "UBERABA KM 104+900 SUL",
"rodovia": "BR 050",
"km": 104.9,
"concessionaria": "MGO RODOVIAS",
"tarifa": 15.80,
"lat": -19.754353,
"lng": -47.933698
},
{ "id": 574, "praca": "DELTA KM 198+060 SUL", "rodovia": "BR 050", "tarifa": 11.20, /* ... */ }
],
"segmentos": [
{ "from": "-18.9186,-48.2772", "to": "-19.7472,-47.9381", "custo": 27.00, "pracas": 2, "km": 110 },
{ "from": "-19.7472,-47.9381", "to": "-23.5505,-46.6333", "custo": 208.67, "pracas": 10, "km": 760 }
]
}
Erros
| Status | Mensagem |
|---|---|
| 400 | origem e destino devem ter { lat, lng } numéricos |
| 502 | Falha roteirizar segmento N — Sem Parar fora do ar ou rota sem pedágio |
2. Emitir VPO
POST /api/v1/vpo/sem-parar/emit
Cria (ou atualiza) motorista, veículo e rota; emite o VPO no Sem Parar; debita o saldo. Operação atômica — ou tudo dá certo, ou tudo falha.
Request
{
"motorista": {
"cpfCnpj": "32984580151",
"nome": "Adenilson Ferreira da Silva",
"rntrc": "004398915",
"telefone": "+5511999999999"
},
"veiculo": {
"placa": "ABC1D23",
"eixos": 6,
"tipo": "cavalo"
},
"rota": {
"origem": { "lat": -18.9186, "lng": -48.2772, "label": "Uberlândia/MG" },
"destino": { "lat": -23.5505, "lng": -46.6333, "label": "São Paulo/SP" },
"paradas": []
},
"periodo": {
"inicio": "2026-06-01",
"fim": "2026-06-05"
},
"referencia_externa": "PEDIDO-12345"
}
Campos:
motorista.cpfCnpj(obrigatório): só números, 11 ou 14 dígitos, DV válidomotorista.nome(obrigatório): razão social ou nome completomotorista.rntrc(opcional): se não passar, é resolvido pelo Sem Parar via lookup do CPFveiculo.placa(obrigatório): 7 caracteres alfanuméricos (formato Mercosul ou antigo)veiculo.eixos(obrigatório): 2 a 10rota.{origem,destino}.lat,lng(obrigatório): coordenadasrota.{origem,destino}.label(opcional): rótulo legível pra aparecer no reciborota.paradas(opcional): paradas intermediáriasperiodo.inicio/fim(obrigatório): YYYY-MM-DD, máximo 15 dias de janelareferencia_externa(opcional): seu ID interno (contrato, pedido). Aparece em/statuspra correlação.
Response 201
{
"ok": true,
"viagemId": "75e64d34-4667-41d3-9220-09f32ebdf3cd",
"env": "prod",
"sem_parar_codigo": 103243030,
"nsu": 1780016186869,
"custoTotal": 235.67,
"confirmada": true,
"status": "emitida"
}
sem_parar_codigo é o número que precisa entrar no campo VPO do MDF-e do cliente.
Erros
| Status | Mensagem | Causa |
|---|---|---|
| 400 | motorista.cpfCnpj inválido (DV ou tamanho) |
DV não bate ou não é 11/14 dígitos |
| 400 | veiculo.placa deve ter 7 caracteres |
Placa malformada |
| 400 | Rota sem praças de pedágio |
A rota não passa por pedágios |
| 402 | Saldo insuficiente |
Créditos pré-pagos zerados |
| 502 | Falha ao vincular placa ao embarcador |
RNTRC inativo ou inconsistente |
| 502 | Falha na compra (com timeout: true) |
Timeout do Sem Parar — consulte status antes de retentar |
3. Consultar status + recibo
GET /api/v1/vpo/sem-parar/status/{viagemId}
Consulta o estado atual no Sem Parar + recibo oficial. Idempotente, sem efeitos colaterais (exceto sincronizar status local se mudou).
Response 200
{
"ok": true,
"viagemId": "75e64d34-4667-41d3-9220-09f32ebdf3cd",
"env": "prod",
"referencia_externa": "PEDIDO-12345",
"status_local": "emitida",
"sem_parar_codigo": 103243030,
"nsu": 1780016186869,
"status": {
"codigo": 2,
"label": "Confirmada",
"success": true
},
"recibo": {
"success": true,
"cnpjEmissor": "07.604.556/0001-36",
"nomeEmissor": "EMPRESA BRASILEIRA DE BEBIDAS E ALIMENTOS S/A",
"cnpjTransp": "039.350.207-40",
"nomeTransp": "JOAQUIM JOSE FERNANDES",
"nomeRota": "ASTOLFO DUTRA/MG → RIO DE JANEIRO/RJ",
"catVeiculo": "02 EIXOS ROD DUPLA",
"dataCompra": "2026-05-28T21:56:29-03:00",
"dataExp": "2026-05-31",
"dataViagem": "2026-05-28",
"total": "65.93",
"tipo": "ROTA PLANEJADA",
"pracas": [
{
"nomePraca": "BR116, KM789+900, SUL, LEOPOLDINA",
"nomeRodovia": "BR116",
"nomeConcessionaria": "ECORIOMINAS",
"placa": "DVT1B37",
"tag": "0740177920",
"tarifa": "27.55"
}
]
}
}
Códigos de status Sem Parar
| Código | Label | Significado |
|---|---|---|
| 1 | Comprada | VPO criado, ainda não confirmado pela cabine |
| 2 | Confirmada | VPO ativo e válido |
| 8 | Cancelada | Foi cancelada (pela embarcadora ou pelo Sem Parar) |
| 9 | Encerrada | Motorista passou em todas as praças ou venceu prazo |
Observação importante sobre o cnpjTransp no recibo
O CPF/CNPJ que aparece em cnpjTransp NÃO é necessariamente o mesmo que você enviou em motorista.cpfCnpj na emissão. O Sem Parar resolve o RNTRC vinculado à placa na base da ANTT e devolve o CPF do titular real do RNTRC. Esse é o CPF que vai aparecer no MDF-e e em fiscalizações.
3b. Listar VPOs
GET /api/v1/vpo/sem-parar/list
Lista os VPOs do seu tenant no ambiente do token (um token hmlg só vê
viagens de homologação; prod só vê produção). Ideal para a tela de listagem.
Query params (todos opcionais)
| Param | Default | Observação |
|---|---|---|
limit |
50 | itens por página (máx 100) |
offset |
0 | deslocamento para paginação |
status |
— | filtra por status (emitida, cancelada, erro, rascunho…) |
referencia_externa |
— | filtra pelo seu ID externo (igualdade) |
Response 200
{
"ok": true,
"total": 137,
"limit": 50,
"offset": 0,
"vpos": [
{
"viagemId": "d8ad700f-8f6f-4ef4-9bc7-f82fae00e6ce",
"status": "emitida",
"env": "prod",
"referencia_externa": "PEDIDO-4471",
"placa": "ABC1D23",
"eixos": 5,
"transportador": "TRANSPORTES EXEMPLO LTDA",
"origem": "Uberlândia/MG",
"destino": "Araguari/MG",
"custo_total": 11,
"antt_id_vpo": "89616552778700127661",
"sem_parar_codigo": "104620273",
"data_inicio": "2026-06-22",
"data_fim": "2026-07-06",
"created_at": "2026-06-19T14:08:27Z"
}
]
}
Para o detalhe completo (recibo, praças, status atual no Sem Parar), use
GET /v1/vpo/sem-parar/status/{viagemId}com oviagemIdretornado aqui. Para buscar pelo seu identificador, passe?referencia_externa=....
Verificar aptidão da placa
POST /api/v1/vpo/sem-parar/verificar-placa
Antes de emitir, verifica se a placa tem TAG Sem Parar ativa (apta a receber Vale-Pedágio). Evita tentar emitir para um veículo que vai falhar.
Request
{ "placa": "ABC1D23" }
Response 200
{
"ok": true,
"placa": "ABC1D23",
"apto": true,
"temTag": true,
"tag": "0740177920",
"proprietario": "JOAQUIM JOSE FERNANDES",
"eixos": 5,
"statusCodigo": 0,
"motivo": "Apto: a placa possui TAG Sem Parar ativa e pode receber Vale-Pedágio."
}
apto: true→ pode emitir.apto: false→ não emita (oriente o titular a regularizar a TAG).statusCodigo:0= apto,4= sem TAG/não encontrada.
4. Cancelar VPO
POST /api/v1/vpo/sem-parar/cancel/{viagemId}
Cancela uma viagem emitida ou em uso. Em ambiente PROD, estorna automaticamente o valor para o saldo de créditos da Loog.
Response 200
{
"ok": true,
"viagemId": "75e64d34-4667-41d3-9220-09f32ebdf3cd",
"status": "cancelada"
}
Erros
| Status | Mensagem | Causa |
|---|---|---|
| 400 | Status "encerrada" — só cancela emitida/em_uso |
A viagem já foi consumida em praça |
| 403 | Token de ambiente "prod" não pode cancelar viagem do ambiente "hmlg" |
Mismatch de env |
5. Saldo de créditos
GET /api/v1/vpo/sem-parar/saldo
Retorna o saldo de créditos pré-pagos Loog do seu tenant. Útil pra exibir o
saldo disponível e bloquear a emissão antes mesmo de chamar /emit (que também
valida saldo e devolve 402 Saldo insuficiente). O saldo é por tenant, não
por ambiente — em HMLG não há débito real, mas o número reflete o saldo que
valeria em PROD. Adicionar saldo é feito na store (https://store.loog.ai/creditos).
Response 200
{
"ok": true,
"env": "hmlg",
"saldo_centavos": 1500000,
"saldo": 15000,
"saldo_formatado": "R$ 15.000,00"
}
Boas práticas
1. Use HMLG primeiro
Antes de ir a PROD, teste todo o fluxo em HMLG (token loog_hmlg_*). Não há cobrança, não há débito de saldo. AVISO: o Sem Parar tem instabilidade conhecida no HMLG — se cair na call, o nosso endpoint indica que você pode usar PROD com placas de teste pra validar.
2. Use referencia_externa
Sempre passe seu ID interno (pedido, contrato, frete) em referencia_externa no /emit. Ele aparece no /status — fica fácil correlacionar com seu sistema sem precisar guardar o mapeamento.
3. Idempotência
Se /emit der timeout (502 com timeout: true), NÃO retente cegamente — primeiro consulte por referencia_externa (use o endpoint /status quando disponível) ou via dashboard. O Sem Parar pode ter emitido com sucesso mesmo retornando timeout pra nós.
4. Polling de status
Pra acompanhar consumo (motorista passando pelas praças), faça polling a cada 5-15 minutos no /status. Não é Webhook (ainda) — em roadmap.
5. Rate limit
Não publicamos limite estrito ainda — esperamos uso razoável de até 50 req/min por token. Avise se precisar de mais.
Exemplos práticos
cURL — preview
curl -X POST https://store.loog.ai/api/v1/vpo/sem-parar/route-preview \
-H "Authorization: Bearer loog_prod_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"origem": { "lat": -18.9186, "lng": -48.2772 },
"destino": { "lat": -23.5505, "lng": -46.6333 },
"eixos": 6
}'
Node.js (fetch nativo)
const TOKEN = process.env.LOOG_API_TOKEN; // loog_prod_...
async function emitirVpo(payload) {
const r = await fetch("https://store.loog.ai/api/v1/vpo/sem-parar/emit", {
method: "POST",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const j = await r.json();
if (!r.ok) throw new Error(`${r.status}: ${j.error}`);
return j;
}
// Uso:
const resp = await emitirVpo({
motorista: { cpfCnpj: "32984580151", nome: "Adenilson Ferreira" },
veiculo: { placa: "ABC1D23", eixos: 6 },
rota: {
origem: { lat: -18.9186, lng: -48.2772, label: "Uberlândia/MG" },
destino: { lat: -23.5505, lng: -46.6333, label: "São Paulo/SP" },
},
periodo: { inicio: "2026-06-01", fim: "2026-06-05" },
referencia_externa: "PEDIDO-12345",
});
console.log("VPO emitido:", resp.sem_parar_codigo);
Python (requests)
import os, requests
TOKEN = os.environ["LOOG_API_TOKEN"]
BASE = "https://store.loog.ai/api/v1"
def emitir_vpo(payload):
r = requests.post(
f"{BASE}/vpo-sem-parar/emit",
json=payload,
headers={"Authorization": f"Bearer {TOKEN}"},
)
r.raise_for_status()
return r.json()
Roadmap
- Webhooks para eventos
vpo.consumed/vpo.cancelled(eliminar polling) - Listagem de VPOs + busca por
referencia_externa(GET /vpo/sem-parar/list) - Endpoint de relatório (extrato, totalizadores) por período
- Endpoint CIOT Ailog (
/ciot-ailog/emite congêneres)
Sugestões e bugs: comercial@loog.ai