Referência da API
API por rota: guia explicado para o TMS
API por rota: guia explicado para o TMS
Esta página explica, rota por rota, a API que o sistema da transportadora (o TMS) usa para falar com o Veltra. Ela é escrita para duas pessoas: o desenvolvedor que vai fazer a integração e o operador que precisa entender o que a integração faz. Os exemplos são completos: você copia, troca SUA_CHAVE_AQUI pela sua chave e roda.
Todos os valores dos exemplos são fictícios. As chaves de acesso de documentos fiscais (44 posições) aparecem cortadas nas respostas só para caber na tela; na vida real elas vêm inteiras.
Swagger e esta página: qual usar#
O Veltra publica um Swagger (uma tela interativa gerada a partir do código). Ele e esta página se complementam:
- Swagger = o mapa interativo. Mostra as rotas, os campos e deixa você testar uma chamada na hora. Endereços:
- Tela:
https://api.veltrasolution.com/swagger-ui.html - Arquivo OpenAPI (JSON) das rotas de manifestos e filiais:
https://api.veltrasolution.com/v3/api-docs/integracao
- Tela:
- Esta página = o guia explicado. Diz quando chamar cada rota, o que acontece ao repetir, quais erros esperar e o que fazer com cada um.
O Swagger e o arquivo /v3/api-docs/integracao são públicos (não pedem chave), porque mostram só o formato das rotas, nunca dados de ninguém. Dois cuidados:
- O Swagger público cobre só as rotas
/integracao/**(filiais e manifestos). As rotas de leitura/v1/saida/**têm um OpenAPI próprio, que exige a sua chave:GET /v1/saida/openapi/INTEGRACAO_TMS(veja a rota na seção de leitura). - O contrato de referência, escrito à mão, fica em
contracts/openapi/veltra-integracao.yaml. Se o Swagger e o contrato divergirem em algum detalhe, vale o que o sistema faz, que é o que esta página descreve.
O que é a API#
A API do Veltra é um conjunto de endereços web (rotas) que falam JSON. O TMS usa em dois sentidos:
- Entrada. O TMS envia filiais e manifestos (a viagem: motorista, veículo e a lista de CT-e e NF) ao Veltra.
- Saída. O TMS lê o que aconteceu (baixas, ocorrências, comprovantes) e pode baixar o PDF, o pacote de evidências e o XML do evento do CT-e. Para ser avisado sem precisar perguntar, use também os webhooks.
Endereço base#
| Onde | Endereço base |
|---|---|
| Produção e teste (mesmo endereço) | https://api.veltrasolution.com |
| Ambiente local de desenvolvimento do Veltra | http://localhost:8080 |
A API tem um endereço único para todos os clientes (ADR 0031). O endereço do portal da sua transportadora é outro (um subdomínio com o nome do cliente), e trocar o subdomínio do portal não muda a API. Nos exemplos usamos a variável BASE:
BASE="https://api.veltrasolution.com"Como autenticar#
A autenticação do TMS é sempre por chave de API, no cabeçalho X-Veltra-Api-Key:
curl "$BASE/v1/api-keys/atual" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"Regras que o sistema aplica:
- O único cabeçalho aceito para a chave é
X-Veltra-Api-Key. Não existe chave de API emAuthorization: Bearer. - o cabeçalho
Authorizationcom a sessão do portal serve para o portal (sessão de um usuário). Não mande os dois cabeçalhos na mesma chamada: o Veltra recusa com401(uma credencial por chamada). - Cabeçalho vazio, chave desconhecida, revogada ou expirada devolve
401. Chave de uma transportadora desativada também devolve401. - Quem emite a chave é o administrador da transportadora, na tela Chaves de API do portal. O valor completo aparece uma única vez. Depois só o prefixo fica visível (por exemplo
vlt_test_a1b2c3d4). Guarde em um cofre de segredos; nunca em código versionado, em log ou em e-mail.
Tipos de chave (finalidade)#
Cada chave tem uma finalidade, que define o que ela alcança. A chave que você usa para integrar o TMS é a de finalidade INTEGRACAO_TMS.
| Finalidade | Para quem | O que alcança |
|---|---|---|
INTEGRACAO_TMS | O TMS da própria transportadora | Tudo desta página que é rota de TMS |
ENTRADA_TRANSPORTADORA | Transportadora parceira de um embarcador (ADR 0029) | Só as 4 rotas de manifesto (POST, GET, PUT e cancelar). Manifesto de outra parceira responde 404. Todo o resto responde 403 |
CONSULTA_EMBARCADOR e CONSULTA_DESTINATARIO | Embarcador ou destinatário que só consulta | Só leitura de eventos, documentos/{id} e openapi/{finalidade}, limitada às raízes de CNPJ cadastradas na chave. O resto responde 403 |
Chaves de consulta e de entrada em produção dependem de um módulo contratado. Sem ele, a resposta é 403 com o código CHAVE_SUSPENSA; a chave não é apagada e volta a funcionar quando o módulo for contratado. O custo do módulo está na página de preços e no módulo 7 da trilha, não nesta página.
Ambientes: teste e produção#
Cada chave pertence a um ambiente: TESTE ou PRODUCAO. Eles usam o mesmo endereço base; quem decide o ambiente é a chave.
| Chave de... | O que acontece |
|---|---|
| Teste | Manifestos são gravados como sandbox: nunca vão para o app de motoristas reais, nunca disparam webhook de produção, não criam motorista nem veículo no cadastro real e são apagados depois de cerca de 30 dias (junto com o registro de idempotência). Idempotência, numeroExterno e vínculo de documentos são separados por ambiente |
| Produção | Manifesto real. Só é emitida para transportadora ativa (em homologação, a emissão devolve 409) |
Exceções que pegam desenvolvedores de surpresa:
- Filiais: a chave de teste só lê filiais. Criar ou alterar filial com ela devolve
403. Use a de produção. - Configuração de prazo: é uma só por transportadora, não separa teste de produção. Gravar com a chave de teste altera a configuração real.
Formato das chamadas e das respostas#
- JSON em UTF-8. Envie
Content-Type: application/jsonquando houver corpo. - Datas:
AAAA-MM-DDpara data (prazoEntrega) e ISO 8601 com fuso para data e hora (2026-10-01T09:15:00-03:00). - Campos desconhecidos são ignorados. Cuidado com o inverso: um campo obrigatório com o nome errado conta como ausente. Os nomes diferenciam maiúsculas de minúsculas (
cnpjEmbarcador, nuncacnpj_embarcador). - Erros seguem o padrão RFC 9457 (
application/problem+json). Veja a seção de erros. - Arquivos (PDF, ZIP, XML) voltam como o arquivo, não como JSON.
- Tamanho do corpo: o servidor na frente da API aceita até 25 MB por chamada. Um manifesto aceita no máximo 1000 documentos.
Versionamento#
- A versão da API está no caminho:
/integracao/v1/...e/v1/.... - As mudanças dentro de uma versão são só aditivas: campo novo opcional, rota nova, valor novo de uma lista. Nada que já funciona deixa de funcionar. Por isso o seu código deve ignorar campos que não conhece e tratar com cuidado valores novos de listas (por exemplo, um tipo de evento novo).
- O arquivo de contrato em
contracts/openapi/veltra-integracao.yamltraz o histórico por versão.
Idempotency-Key: repetir sem duplicar#
Rede cai, resposta se perde, o TMS não sabe se o envio funcionou. Para isso existe o cabeçalho Idempotency-Key.
- É obrigatório em
POST /integracao/v1/manifestose emPUT /integracao/v1/manifestos/{numeroExterno}. Sem ele:400. - Gere um valor por tentativa lógica de envio (recomendado: um UUID) e repita o mesmo valor se precisar reenviar a mesma coisa. Tamanho: 1 a 255 caracteres.
- Mesma chave e mesmo corpo: o Veltra devolve a resposta original (
200noPOST), sem gravar nada de novo. A ordem dos campos no JSON não importa; a ordem da listadocumentosimporta. - Mesma chave com corpo diferente:
409. - A chave é separada por transportadora e por ambiente e fica guardada por no mínimo 72 horas.
- As demais rotas de escrita (
cancelar, filiais, configuração de prazo) não usamIdempotency-Key: elas são seguras para repetir por natureza (veja a observação de cada rota).
Paginação#
Só as listas de leitura (/v1/saida/eventos e /v1/saida/manifestos) são paginadas, por cursor e não por número de página:
limite: de 1 a 200 (padrão 50).alteradoDesde: o cursor. Na primeira leitura, omita. Nas seguintes, mande oproximoCursorda resposta anterior.- O cursor é opaco: guarde e devolva como veio; não monte nem edite.
- O Veltra só devolve itens alterados há pelo menos 5 segundos (janela de segurança). O mesmo item pode aparecer em duas respostas seguidas: trate pelo
id.
As listas de filiais não são paginadas: voltam inteiras.
Limites de taxa (rate limit)#
- Cada chave pode ter um limite de chamadas por minuto. Passou do limite:
429com o cabeçalhoRetry-After(em segundos). Espere esse tempo e tente de novo. - As chaves de consulta nascem com um limite por minuto definido na emissão (de 1 a 600). A chave do TMS emitida pelo portal não vem com limite configurado. Mesmo assim, programe o seu código para respeitar
429eRetry-After, e não faça laço sem pausa. - Para saber de novidades sem consultar toda hora, prefira os webhooks; para ler, use o cursor com uma pausa entre as rodadas (por exemplo, de 10 a 30 segundos).
Códigos de status comuns#
| Status | Quando | O que fazer |
|---|---|---|
200 | Deu certo (leitura, alteração, cancelamento, ou reenvio idempotente) | Seguir |
201 | Criado (manifesto novo, filial nova, chave nova) | Guardar o id devolvido |
204 | Deu certo, sem corpo (revogar chave) | Seguir |
400 | Corpo ou parâmetro inválido | Ler o campo detail, corrigir e reenviar |
401 | Chave ausente, errada, revogada, expirada, ou Authorization junto com a chave | Conferir a chave e o cabeçalho |
403 | A chave não pode usar esta rota, chave de teste tentando gravar filial, ou CHAVE_SUSPENSA | Conferir o tipo de chave e o ambiente |
404 | Não existe neste ambiente (ou é de outra transportadora ou fora do escopo da chave) | Conferir o id, o numeroExterno e o ambiente da chave |
409 | Conflito: Idempotency-Key com outro corpo, numeroExterno ou sigla repetidos, TESTE_ENCERRADO | Veja a rota |
429 | Limite de chamadas por minuto | Esperar o Retry-After |
5xx | Falha do Veltra | Tentar de novo com pausa crescente (e a mesma Idempotency-Key) |
O Veltra nunca usa 401 nem 402 por causa de cobrança.
Como é um erro#
Erros de manifestos e filiais vêm em application/problem+json:
{
"type": "https://veltra.com.br/problemas/validacao",
"title": "Requisição inválida",
"status": 400,
"detail": "motorista.cpf inválido"
}status: o código HTTP.detail: a explicação em português. Use para mostrar ao operador e para log. Não use o texto dedetailpara decidir o que o seu código faz: use ostatuse, quando existir, o campocodigo.codigo: aparece nos erros que têm código estável (TESTE_ENCERRADO,CHAVE_SUSPENSA).erros: lista de documentos recusados (manifestos).
Um aviso de franqueza: as rotas de leitura /v1/saida/** sempre respondem com o código HTTP certo, mas o formato do corpo de erro nelas pode ser o padrão do servidor em vez do problem+json. Por isso, decida sempre pelo código HTTP.
Preciso de... use a rota#
| Preciso de... | Use |
|---|---|
| Conferir se a minha chave funciona e qual ambiente ela é | GET /v1/api-keys/atual |
| Cadastrar as filiais do TMS no Veltra | POST /integracao/v1/filiais |
| Listar as filiais cadastradas | GET /integracao/v1/filiais |
| Ver uma filial | GET /integracao/v1/filiais/{id} |
| Corrigir nome, endereço ou raio de uma filial | PUT /integracao/v1/filiais/{id} |
| Enviar um manifesto novo (entrega, coleta, rota ou transferência) | POST /integracao/v1/manifestos |
| Saber a situação de um manifesto e de cada documento | GET /integracao/v1/manifestos/{numeroExterno} |
| Trocar motorista, veículo ou documentos de um manifesto já enviado | PUT /integracao/v1/manifestos/{numeroExterno} |
| Cancelar o que falta de um manifesto | POST /integracao/v1/manifestos/{numeroExterno}/cancelar |
| Saber o que aconteceu desde a última vez (baixas, ocorrências, comprovantes) | GET /v1/saida/eventos |
| Listar os manifestos que o Veltra tem | GET /v1/saida/manifestos |
Ver um manifesto pelo id do Veltra | GET /v1/saida/manifestos/{id} |
Ver a situação de um documento pelo id do Veltra | GET /v1/saida/documentos/{id} |
| Baixar o PDF do comprovante | GET /v1/saida/comprovantes/{id}/pdf |
| Baixar o pacote ZIP de evidências | GET /v1/saida/comprovantes/{id}/pacote |
| Baixar o XML do evento do CT-e (110180) | GET /v1/saida/eventos-cte/{id}/xml |
| Gerar um cliente de código só com as rotas de leitura | GET /v1/saida/openapi/{finalidade} |
| Ler a regra de prazo de entrega | GET /v1/saida/configuracao-prazo |
| Mandar para o Veltra as cidades, prazos e feriados | PUT /v1/saida/configuracao-prazo |
| Emitir, listar ou revogar chaves de API | Tela Chaves de API do portal (rotas /v1/api-keys, de administrador) |
| Ser avisado de cada novidade sem consultar toda hora | Webhooks (veja a referência de webhooks) |
Rotas que o TMS não usa#
Para você não se perder no Swagger e nos contratos: estas áreas existem, mas não são do TMS.
| Área | Quem usa | Observação |
|---|---|---|
/superadmin/** | Equipe do Veltra | Homologação de transportadoras, cobrança e alertas da plataforma |
/v1/webhooks/asaas | O serviço de cobrança | Não é chamado pelo TMS |
/v1/integracoes/webhooks/** | Administrador no portal | Cadastro e reenvio de webhooks (veja os webhooks) |
Demais rotas /v1/** | Portal web e app do motorista | Usam o login de usuário, não a chave de API |
A página de leitura e a de entrada são tabelas geradas direto do contrato. Esta página é a versão explicada delas.
Verificação da chave
GET /v1/api-keys/atual#
Para que serve: responde "quem sou eu": mostra a transportadora e o ambiente da chave que você está usando.
Quando chamar: na primeira conexão, para confirmar que a chave é a certa e que o ambiente é o esperado (teste ou produção); e em qualquer monitoramento simples do seu lado.
Cabeçalhos
| Cabeçalho | Obrigatório | Valor |
|---|---|---|
X-Veltra-Api-Key | sim | A chave do TMS (INTEGRACAO_TMS) |
Parâmetros: nenhum.
Exemplo
curl "$BASE/v1/api-keys/atual" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"Resposta de sucesso: 200
{
"transportadoraId": "0192f3a4-5b6c-7d8e-9f01-000000000100",
"apiKeyId": "0192f3a4-5b6c-7d8e-9f01-000000000101",
"apiKeyPrefixo": "vlt_test_a1b2c3d4",
"ambiente": "TESTE"
}| Campo | Tipo | Descrição |
|---|---|---|
transportadoraId | texto (uuid) | A transportadora dona da chave |
apiKeyId | texto (uuid) | O id da chave |
apiKeyPrefixo | texto | O prefixo, a parte que aparece na tela de chaves do portal |
ambiente | TESTE ou PRODUCAO | O ambiente da chave |
Erros
| Status | Quando | O que fazer |
|---|---|---|
401 | Chave ausente, errada, revogada ou expirada; ou Authorization junto | Conferir a chave e remover o Authorization |
403 | A chave não é do tipo TMS (por exemplo, chave de consulta) | Usar a chave de finalidade INTEGRACAO_TMS |
429 | Limite de chamadas por minuto | Esperar o Retry-After |
Observações: a rota só aceita chave de API. Um usuário do portal (com Authorization) não a usa.
Chaves de API (administração)
As três rotas abaixo são de administrador da transportadora, no portal, com o login de usuário (Authorization: Bearer). O TMS não as chama com a chave de API; quem emite, lista e revoga é uma pessoa, na tela Chaves de API. Elas estão aqui para o desenvolvedor entender o ciclo de vida da chave. Nos exemplos, TOKEN_DO_PORTAL é a sessão do administrador.
POST /v1/api-keys#
Para que serve: emite uma chave de API nova para a transportadora do administrador logado.
Quando chamar: ao começar a integração (uma chave de teste), ao ir para produção (uma chave de produção) e ao trocar uma chave que vazou.
Cabeçalhos: o cabeçalho Authorization com a sessão do portal (perfil de administrador) e Content-Type: application/json.
Corpo da requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
nome | texto (até 120) | sim | Nome para você reconhecer a chave, por exemplo "TMS produção" |
ambiente | TESTE ou PRODUCAO | sim | O ambiente da chave. PRODUCAO só para transportadora ativa |
curl -X POST "$BASE/v1/api-keys" \
-H "Authorization: Bearer $TOKEN_DO_PORTAL" \
-H "Content-Type: application/json" \
-d '{ "nome": "TMS teste", "ambiente": "TESTE" }'Resposta de sucesso: 201
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000101",
"nome": "TMS teste",
"ambiente": "TESTE",
"apiKeyValorEmClaro": "SUA_CHAVE_AQUI",
"apiKeyPrefixo": "vlt_test_a1b2c3d4",
"criadaEm": "2026-11-05T12:00:00Z"
}apiKeyValorEmClaro é o valor completo da chave e aparece só nesta resposta. Depois dela, só o hash fica guardado e ninguém consegue recuperar o valor.
Erros
| Status | Quando | O que fazer |
|---|---|---|
400 | Falta nome ou ambiente, ou nome acima de 120 caracteres | Corrigir o corpo |
401 | Sessão do portal ausente ou vencida | Entrar de novo |
403 | O usuário não é administrador | Pedir a um administrador |
409 | Chave de PRODUCAO para transportadora que ainda não está ativa (em homologação ou inativa) | Pedir ao Veltra para concluir a homologação |
Observações: emitir várias chaves é permitido. Revogue as que não usa mais.
GET /v1/api-keys#
Para que serve: lista as chaves da transportadora, inclusive as revogadas. Nunca mostra o valor, só o prefixo.
Quando chamar: para auditar quais chaves existem e quais já foram revogadas.
Cabeçalhos: o cabeçalho Authorization com a sessão do portal (administrador).
Parâmetros: nenhum.
curl "$BASE/v1/api-keys" \
-H "Authorization: Bearer $TOKEN_DO_PORTAL"Resposta de sucesso: 200
[
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000101",
"nome": "TMS teste",
"ambiente": "TESTE",
"apiKeyPrefixo": "vlt_test_a1b2c3d4",
"criadaEm": "2026-11-05T12:00:00Z"
}
]Em cada item, revogadaEm (data e hora) só aparece quando a chave já foi revogada. As chaves que o administrador de um embarcador emitiu para as transportadoras parceiras dele não entram nesta lista.
Erros: 401 (sem sessão) e 403 (não é administrador).
DELETE /v1/api-keys/{id}#
Para que serve: revoga uma chave. A partir desse instante, qualquer chamada com ela recebe 401.
Quando chamar: quando a chave vazou, quando alguém que a conhecia saiu da equipe, ou quando a integração antiga foi desligada.
Cabeçalhos: o cabeçalho Authorization com a sessão do portal (administrador).
Parâmetros de caminho
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | texto (uuid) | sim | O id da chave (o campo id da lista, não o prefixo) |
curl -X DELETE "$BASE/v1/api-keys/0192f3a4-5b6c-7d8e-9f01-000000000101" \
-H "Authorization: Bearer $TOKEN_DO_PORTAL"Resposta de sucesso: 204 (sem corpo).
Erros
| Status | Quando | O que fazer |
|---|---|---|
401 | Sessão ausente ou vencida | Entrar de novo |
403 | Não é administrador | Pedir a um administrador |
404 | O id não existe nesta transportadora | Conferir o id na lista |
Observações: revogar é definitivo e seguro de repetir (revogar de novo uma chave já revogada responde 204). Para trocar de chave sem parar a integração, emita a nova, troque no TMS, confirme que funciona e só então revogue a antiga.
Filiais
A filial é o ponto da transportadora (matriz, base, terminal). O manifesto de transferência cita as filiais pela sigla externa (siglaExterna), por isso elas precisam existir antes. As quatro rotas abaixo usam a mesma regra do cadastro de filiais do portal.
GET /integracao/v1/filiais#
Para que serve: lista todas as filiais da transportadora.
Quando chamar: para conferir o que já está cadastrado antes de enviar manifestos de transferência, ou para sincronizar o cadastro do TMS.
Cabeçalhos: X-Veltra-Api-Key (chave de teste ou de produção).
Parâmetros: nenhum. A lista vem completa, ordenada por nome.
curl "$BASE/integracao/v1/filiais" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"Resposta de sucesso: 200
[
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000201",
"nome": "Filial Campinas",
"siglaExterna": "CPS",
"endereco": "Rodovia Exemplo km 10, Campinas - SP",
"latitude": null,
"longitude": null,
"raioGeofenceM": 200,
"ativa": true
}
]| Campo | Tipo | Descrição |
|---|---|---|
id | texto (uuid) | O id da filial no Veltra |
nome | texto | Nome da filial |
siglaExterna | texto | A sigla que o seu TMS usa, sempre em maiúsculas |
endereco | texto ou nulo | Endereço em uma linha |
latitude, longitude | número ou nulo | O pino da filial no mapa. Nulo quando a filial foi criada pela API sem coordenadas |
raioGeofenceM | inteiro | Raio, em metros, ao redor do pino para considerar que o motorista "chegou" |
ativa | verdadeiro ou falso | Se a filial está em uso |
Erros: 401, 403 (chave que não é de TMS), 429.
Observações: a chave de teste lê as filiais reais (só não grava).
POST /integracao/v1/filiais#
Para que serve: cadastra uma filial.
Quando chamar: uma vez por filial, antes do primeiro manifesto de transferência. Para poucas filiais, é mais simples cadastrar no portal.
Cabeçalhos: X-Veltra-Api-Key (chave de produção) e Content-Type: application/json.
Corpo da requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
nome | texto (até 200) | sim | Nome da filial |
siglaExterna | texto (até 60) | sim | Identificador da filial no seu TMS. Único por transportadora. É guardado em maiúsculas, sem espaços nas pontas |
endereco | texto (até 500) | não | Endereço em uma linha |
latitude, longitude | número | não | Pino no mapa. Mande os dois juntos |
raioGeofenceM | inteiro, de 10 a 50000 | não | Raio em metros. Padrão: 200 |
ativa | verdadeiro ou falso | não | Padrão: a filial nasce ativa |
curl -X POST "$BASE/integracao/v1/filiais" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-H "Content-Type: application/json" \
-d '{
"nome": "Filial Campinas",
"siglaExterna": "CPS",
"endereco": "Rodovia Exemplo km 10, Campinas - SP",
"latitude": -22.9099,
"longitude": -47.0626,
"raioGeofenceM": 300
}'Resposta de sucesso: 201, com a filial criada (mesmos campos da lista).
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000201",
"nome": "Filial Campinas",
"siglaExterna": "CPS",
"endereco": "Rodovia Exemplo km 10, Campinas - SP",
"latitude": -22.9099,
"longitude": -47.0626,
"raioGeofenceM": 300,
"ativa": true
}Erros
| Status | Quando | O que fazer |
|---|---|---|
400 | nome ou siglaExterna em branco ou longos demais, ou raio fora de 10 a 50000 | Corrigir o campo indicado em detail |
401 | Chave inválida | Conferir a chave |
403 | Chave de teste (ela só lê cadastros) ou chave que não é de TMS | Usar a chave de produção |
409 | Já existe filial com essa siglaExterna (detail: "já existe filial com a sigla externa CPS") | Usar o PUT para alterar |
Observações
- Sem
Idempotency-Key. Repetir oPOSTcom a mesma sigla devolve409, o que protege contra duplicata. - A API não localiza o endereço no mapa. Sem
latitudeelongitude, a filial fica sem pino até alguém ajustar no portal. Se você já tem as coordenadas, mande.
GET /integracao/v1/filiais/{id}#
Para que serve: mostra uma filial pelo id do Veltra.
Quando chamar: quando você guardou o id devolvido no cadastro e quer reler os dados.
Cabeçalhos: X-Veltra-Api-Key.
Parâmetros de caminho
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | texto (uuid) | sim | O id da filial (o campo id da lista, não a sigla) |
curl "$BASE/integracao/v1/filiais/0192f3a4-5b6c-7d8e-9f01-000000000201" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"Resposta de sucesso: 200, com a filial (mesmos campos da lista).
Erros: 401, 403, 404 (a filial não existe: detail "filial não encontrada"), 429.
Observações: para achar uma filial pela sigla, leia a lista e filtre do seu lado.
PUT /integracao/v1/filiais/{id}#
Para que serve: altera os dados de uma filial.
Quando chamar: quando o nome, o endereço, o pino ou o raio mudam no TMS, ou para desativar uma filial ("ativa": false).
Cabeçalhos: X-Veltra-Api-Key (chave de produção) e Content-Type: application/json.
Parâmetros de caminho: id (uuid da filial), como na rota anterior.
Corpo da requisição: os mesmos campos do POST. nome e siglaExterna continuam obrigatórios.
curl -X PUT "$BASE/integracao/v1/filiais/0192f3a4-5b6c-7d8e-9f01-000000000201" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-H "Content-Type: application/json" \
-d '{
"nome": "Filial Campinas Norte",
"siglaExterna": "CPS",
"raioGeofenceM": 250
}'Resposta de sucesso: 200, com a filial atualizada.
Erros
| Status | Quando | O que fazer |
|---|---|---|
400 | Campo inválido (como no POST) | Corrigir |
401 | Chave inválida | Conferir a chave |
403 | Chave de teste ou que não é de TMS | Usar a chave de produção |
404 | A filial não existe | Conferir o id |
409 | A siglaExterna nova já é de outra filial | Escolher outra sigla |
Observações
- O
PUTpode ser repetido sem problema (mesmo corpo, mesmo resultado). - Se você não mandar
latitudeelongitude, o pino atual é mantido (ele nunca é apagado por omissão, e a API não localiza endereço novo no mapa). Se não mandarraioGeofenceM, o raio atual é mantido. Se não mandarativa, o estado atual é mantido. - Atenção: o texto do
enderecoé substituído pelo que você mandar. Omitido, o endereço da filial fica em branco. Mande sempre o endereço junto, mesmo que não tenha mudado. - Trocar a sigla de uma filial muda como os próximos manifestos de transferência devem citá-la.
Manifestos
Um manifesto é uma viagem: motorista, veículo e a lista de documentos (CT-e e NF) que o motorista entrega, coleta ou transfere. O Veltra não recebe XML: recebe as chaves e os dados essenciais de cada documento. A trilha de ajuda tem o passo a passo no módulo 4; aqui está o detalhe de cada rota.
POST /integracao/v1/manifestos#
Para que serve: envia um manifesto novo, em uma chamada, com todos os documentos.
Quando chamar: quando o TMS fechar a viagem e o motorista estiver para sair. O Veltra monta as paradas sozinho, agrupando os documentos por destinatário (CNPJ ou CPF) mais endereço, na ordem em que aparecem em documentos.
Cabeçalhos
| Cabeçalho | Obrigatório | Valor |
|---|---|---|
X-Veltra-Api-Key | sim | A chave do TMS (teste ou produção) |
Idempotency-Key | sim | Um UUID por tentativa lógica (veja a seção de idempotência) |
Content-Type | sim | application/json |
Parâmetros de caminho e de consulta: nenhum.
Corpo da requisição: o manifesto
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
tipo | texto | sim | ROTA (entregas e coletas juntas), TRANSFERENCIA (entre filiais), ENTREGA ou COLETA. ENTREGA e COLETA continuam aceitos e valem como ROTA. Não muda depois de criado |
numeroExterno | texto (1 a 60) | sim | O número do manifesto no seu TMS. É a chave natural: único por transportadora e ambiente |
motorista | objeto | sim | cpf (11 dígitos, com ou sem máscara, com dígitos verificadores corretos) e nome (até 200) |
veiculo | objeto | sim | placa de tração, padrão antigo ou Mercosul, com ou sem hífen |
ajudantes | lista | não | Até 2, cada um com cpf e nome. São dados do manifesto, não usuários do app |
filialOrigemSigla | texto | só em TRANSFERENCIA | siglaExterna da filial de origem. Sigla desconhecida recusa o manifesto |
filialDestinoSigla | texto | só em TRANSFERENCIA | siglaExterna da filial de destino |
chaveMdfe | texto (44) | não | Chave do MDF-e do manifesto, para rastreabilidade. Não substitui o numeroExterno |
quantidadePaletes | inteiro, 0 ou mais | não | Paletes do manifesto |
documentos | lista | sim | De 1 a 1000 documentos. A ordem é a ordem sugerida das paradas |
Cada item de documentos
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
modelo | número | sim | 55 (NF-e), 57 (CT-e) ou 58 (MDF-e). Mande como número, não como texto |
numero | texto (até 20) | sim | Número do documento |
serie | texto (até 10) | não | Série do documento |
chave | texto (44) | sim para CT-e | Chave de acesso de 44 posições. O Veltra confere o dígito verificador e o modelo. Para NF-e é opcional: sem ela, o documento é identificado por numero, serie e cnpjEmbarcador |
cnpjTransportadora | texto | não | CNPJ de quem emitiu o CT-e (só modelo 57). Ausente, o Veltra usa o CNPJ que está na chave |
cnpjEmbarcador | texto | sim se modelo não for 57 | CNPJ do dono da NF |
tomadorCnpj | texto | não | CNPJ de quem paga o frete (só CT-e). Sem ele, nenhum terceiro recebe o PDF nem o canhoto |
tarefa | texto | não | ENTREGA ou COLETA. Omitido: coleta em manifesto COLETA e entrega nos demais tipos |
embarcador | objeto | não | cnpjCpf e nome de quem embarca a mercadoria. É aceito, mas ainda não é gravado |
destinatario | objeto | sim | Veja a tabela abaixo |
nfVinculadas | lista | não (informe em CT-e) | As NF que o CT-e transporta (veja a tabela abaixo). O Veltra aceita o CT-e sem elas, mas sem as NF o vínculo não é feito |
volumes | inteiro, 0 ou mais | não | Quantidade de volumes |
peso | número, 0 ou mais | não | Peso em kg |
valor | número, 0 ou mais | não | Valor do documento, só para exibição na torre. Não entra em cálculo |
prazoEntrega | data | não | AAAA-MM-DD |
cteEmitidoEm | data e hora | não | Emissão do CT-e. Serve de data-base do prazo se a transportadora escolheu essa regra |
latitude, longitude | número | não | Coordenadas da parada. Mande as duas juntas. Sem elas, o endereço é localizado no mapa em segundo plano |
protocoloAutorizacao | texto, 15 dígitos | não | Protocolo de autorização do CT-e. Alimenta o evento 110180 |
tipoServico | texto | não | NORMAL, SUBCONTRATACAO, REDESPACHO, REDESPACHO_INTERMEDIARIO ou SERVICO_VINCULADO_MULTIMODAL |
globalizado | verdadeiro ou falso | não | CT-e globalizado. Omitido: não |
protocoloAutorizacao, tipoServico e globalizado só valem para CT-e. Em outro modelo, são ignorados e a resposta traz um aviso em erros.
destinatario (junto com o endereço, define a parada)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
cnpjCpf | texto | sim | CNPJ ou CPF, com ou sem máscara. Agrupa as paradas e identifica o link do destinatário |
nome | texto (até 200) | sim | Nome do destinatário |
email | texto | não | Para o aviso da entrega ao destinatário. É dado pessoal |
endereco | objeto | sim | logradouro, municipio e uf são obrigatórios; numero, complemento, bairro e cep são opcionais |
Cada item de nfVinculadas
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
numero | texto (até 20) | sim | Número da NF |
cnpjEmbarcador | texto | sim | CNPJ de quem emitiu a NF |
serie | texto (até 10) | não | Série da NF |
chave | texto (44) | não | Chave da NF-e. Se vier depois, o Veltra vincula |
valor | número | não | Valor da NF, só para exibição |
nfeEmitidoEm | data e hora | não | Emissão da NF-e (data-base do prazo, se escolhida) |
Exemplo completo (curl)
BASE="https://api.veltrasolution.com"
CHAVE_CTE="3526091122233300018157""0010000123451482135762"
curl -X POST "$BASE/integracao/v1/manifestos" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-H "Idempotency-Key: 0192f3a4-5b6c-7d8e-9f01-23456789abcd" \
-H "Content-Type: application/json" \
-d @- <<JSON
{
"tipo": "ENTREGA",
"numeroExterno": "REL-2026-000123",
"motorista": { "cpf": "529.982.247-25", "nome": "Motorista Exemplo da Silva" },
"veiculo": { "placa": "ABC1D23" },
"ajudantes": [ { "cpf": "111.444.777-35", "nome": "Ajudante Exemplo" } ],
"quantidadePaletes": 4,
"documentos": [
{
"modelo": 57,
"chave": "$CHAVE_CTE",
"numero": "12345",
"serie": "1",
"cnpjTransportadora": "11222333000181",
"destinatario": {
"cnpjCpf": "11444777000161",
"nome": "Mercado Exemplo Ltda",
"email": "entrega@mercado.exemplo",
"endereco": {
"logradouro": "Rua das Flores",
"numero": "120",
"bairro": "Centro",
"municipio": "Campinas",
"uf": "SP",
"cep": "13010-000"
}
},
"nfVinculadas": [
{ "numero": "45678", "serie": "1", "cnpjEmbarcador": "12345678000195" }
],
"volumes": 12,
"peso": 350.5,
"prazoEntrega": "2026-10-02"
}
]
}
JSONA chave do CT-e foi dividida em duas partes dentro de uma variável do shell só para caber na tela; o resultado é a chave inteira de 44 posições.
Resposta de sucesso: 201 (manifesto novo, versão 1)
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000001",
"numeroExterno": "REL-2026-000123",
"tipo": "ENTREGA",
"ambiente": "TESTE",
"versaoAtual": 1,
"quantidadeParadas": 1,
"quantidadeDocumentos": 1,
"documentos": [
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000010",
"modelo": 57,
"chave": "3526091122233300018157...",
"numero": "12345",
"serie": "1",
"status": "PENDENTE",
"nfVinculadas": [
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000011",
"chave": null,
"numero": "45678",
"serie": "1",
"status": "PENDENTE"
}
]
}
],
"erros": []
}| Campo da resposta | Descrição |
|---|---|
id | O id do manifesto no Veltra. É o que a rota /v1/saida/manifestos/{id} usa |
numeroExterno, tipo | O que você enviou |
ambiente | O ambiente da sua chave |
versaoAtual | 1 na criação; sobe de 1 em 1 a cada alteração (PUT) |
quantidadeParadas | Quantas paradas o Veltra montou |
quantidadeDocumentos | Quantos documentos foram aceitos |
documentos[].id | O id do documento no Veltra. É o que /v1/saida/documentos/{id} usa. Guarde |
documentos[].status | PENDENTE, EM_TRANSPORTE, ENTREGUE, ENTREGUE_PARCIAL, DEVOLVIDO ou CANCELADO. O status é por documento (e por NF), não do manifesto inteiro |
erros | Documentos recusados e avisos desta chamada. Vazio quando tudo foi aceito |
Resposta com recusa parcial: 201. Quando alguns documentos têm problema e outros não, o Veltra grava os bons e devolve os recusados em erros. O campo documentoIndex conta a partir de 0 e aponta a posição do documento na sua lista documentos:
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000001",
"numeroExterno": "REL-2026-000123",
"tipo": "ENTREGA",
"ambiente": "TESTE",
"versaoAtual": 1,
"quantidadeParadas": 1,
"quantidadeDocumentos": 1,
"documentos": [],
"erros": [
{
"documentoIndex": 1,
"codigo": "CHAVE_INVALIDA",
"motivo": "chave de acesso: dígito verificador inválido",
"chave": "3526091122233300018157...",
"numero": "12346"
}
]
}(O campo documentos foi resumido neste exemplo; na resposta real ele traz o documento aceito.) Sempre leia erros depois de um 201: o manifesto foi criado, mas um documento pode ter ficado de fora.
Códigos de recusa de um documento (erros[].codigo)
| Código | Quando acontece | O que fazer |
|---|---|---|
CHAVE_INVALIDA | Chave com tamanho ou dígito verificador errado, ou documento que não pôde ser gravado | Corrigir a chave e reenviar com PUT |
CHAVE_CTE_OBRIGATORIA | CT-e (modelo 57) sem chave | Informar a chave do CT-e |
MODELO_INCOMPATIVEL | A chave é de um modelo diferente do modelo informado | Conferir o modelo |
CNPJ_INVALIDO | cnpjTransportadora, cnpjEmbarcador ou tomadorCnpj inválido | Corrigir o CNPJ |
DESTINATARIO_INVALIDO | destinatario.cnpjCpf ausente ou inválido, e-mail inválido, nome acima de 200, ou endereço sem logradouro, município e UF | Corrigir o destinatário |
DOCUMENTO_JA_BAIXADO | Só no PUT: você tirou do manifesto um documento que já tem baixa | O documento fica (veja o PUT) |
OUTRO | Outras regras: modelo fora de 55, 57 e 58; numero em branco ou longo; tarefa inválida; só latitude sem longitude; valores negativos; protocoloAutorizacao sem 15 dígitos; tipoServico inválido; documento repetido no manifesto | Ler o motivo |
Erros da chamada inteira
| Status | Quando | O que fazer |
|---|---|---|
400 | Falta o cabeçalho Idempotency-Key (detail: "cabeçalho Idempotency-Key é obrigatório") | Enviar o cabeçalho |
400 | Idempotency-Key com mais de 255 caracteres | Usar um UUID |
400 | JSON ilegível (detail: "Corpo da requisição ilegível.") | Validar o JSON |
400 | Erro de cabeçalho do manifesto: tipo ausente ou fora da lista; numeroExterno ausente; motorista ou veiculo ausentes; motorista.cpf inválido; veiculo.placa inválida; mais de 2 ajudantes; chaveMdfe inválida; documentos vazio ou acima de 1000 | Corrigir o campo que o detail indica |
400 | Transferência sem filialOrigemSigla ou filialDestinoSigla, ou sigla que não existe | Cadastrar a filial antes (rota de filiais) |
400 | Todos os documentos foram recusados. type termina em documentos-invalidos e erros lista o motivo de cada um. Nada foi gravado | Corrigir os documentos e reenviar |
401 | Chave inválida | Conferir a chave |
403 | Chave sem permissão para manifesto (por exemplo, chave de consulta), ou módulo de entrada suspenso (CHAVE_SUSPENSA) | Usar a chave certa |
409 | Idempotency-Key já usada com outro corpo | Gerar uma chave nova, se for outro envio |
409 | numeroExterno já existe neste ambiente (type termina em manifesto-ja-existe) | Use PUT para alterar |
409 | codigo = TESTE_ENCERRADO: o teste grátis da transportadora acabou e a chave de produção não grava manifesto novo | A transportadora contrata no portal. A chave de teste não é afetada |
409 | Conflito de gravação simultânea (type termina em conflito) | Tentar de novo com a mesma Idempotency-Key |
429 | Limite de chamadas | Esperar o Retry-After |
Observações
- Idempotência. Reenvio com a mesma
Idempotency-Keye o mesmo corpo devolve200com a resposta original e não grava nada de novo. Isso vale também depois que o teste grátis acabou: um manifesto já gravado continua devolvendo a resposta gravada. - Deduplicação por
numeroExterno. Mandar o mesmo número com outraIdempotency-Keyé409: o Veltra entende que é um manifesto repetido e não cria outro. Para mudar um manifesto existente, use oPUT. - Coleta sem CT-e. O documento é a NF (
modelo55) comnumero,serieecnpjEmbarcador. Odestinatarioé o local onde o motorista busca. Quando o CT-e for emitido depois, ele chega em outro manifesto com as mesmas NF e o Veltra vincula sozinho. - Mesma parada. Documentos para o mesmo destinatário e o mesmo endereço ficam na mesma parada, cada um com a sua tarefa.
- Teste. O manifesto de teste não chega ao app de motoristas reais nem dispara webhook de produção.
- Limites. Até 1000 documentos, até 2 ajudantes,
numeroExternocom até 60 caracteres. - Eventos. O Veltra não dispara webhook de manifesto; para acompanhar o andamento, assine os eventos de baixa, ocorrência e parada (veja os webhooks).
GET /integracao/v1/manifestos/{numeroExterno}#
Para que serve: consulta a situação atual de um manifesto que o seu TMS enviou, com o status de cada documento e de cada NF.
Quando chamar: para conferir o que o Veltra tem depois de um envio ou de uma alteração, e para ver o andamento (PENDENTE, EM_TRANSPORTE, ENTREGUE e assim por diante).
Cabeçalhos: X-Veltra-Api-Key.
Parâmetros de caminho
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
numeroExterno | texto (1 a 60) | sim | O número do manifesto no seu TMS, o mesmo do envio |
Parâmetros de consulta: nenhum.
curl "$BASE/integracao/v1/manifestos/REL-2026-000123" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"Resposta de sucesso: 200 (mesma estrutura da resposta do envio, com documentos preenchido)
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000001",
"numeroExterno": "REL-2026-000123",
"tipo": "ENTREGA",
"ambiente": "PRODUCAO",
"versaoAtual": 2,
"quantidadeParadas": 1,
"quantidadeDocumentos": 1,
"documentos": [
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000010",
"modelo": 57,
"chave": "3526091122233300018157...",
"numero": "12345",
"serie": "1",
"status": "EM_TRANSPORTE",
"nfVinculadas": [
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000011",
"chave": null,
"numero": "45678",
"serie": "1",
"status": "EM_TRANSPORTE"
}
]
}
],
"erros": []
}Erros
| Status | Quando | O que fazer |
|---|---|---|
401 | Chave inválida | Conferir a chave |
403 | Chave sem permissão | Usar a chave de TMS |
404 | Não existe neste ambiente da chave (ou é de outra transportadora). O Veltra nunca revela se existe em outro ambiente | Conferir o numeroExterno e se a chave é a de teste ou a de produção |
Observações: a consulta é somente leitura e pode ser repetida à vontade. Uma chave de teste só enxerga manifestos de teste, e a de produção, só os de produção. Documentos removidos numa alteração não aparecem aqui. Para ser avisado da mudança de status sem consultar, use os webhooks.
PUT /integracao/v1/manifestos/{numeroExterno}#
Para que serve: altera um manifesto já enviado. Alterar é reenviar o manifesto inteiro: o Veltra compara com a versão atual, calcula o que entrou, saiu ou mudou e grava uma nova versão (versaoAtual + 1), guardando o histórico.
Quando chamar: para trocar motorista, veículo ou ajudantes no meio da rota, adicionar ou tirar documentos, ou corrigir um documento que foi recusado no envio. O que já foi feito continua registrado em nome de quem fez.
Cabeçalhos: os mesmos do POST: X-Veltra-Api-Key, Idempotency-Key (obrigatório) e Content-Type: application/json.
Parâmetros de caminho
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
numeroExterno | texto (1 a 60) | sim | O número do manifesto no seu TMS |
Corpo da requisição: o manifesto completo, com os mesmos campos do POST. O numeroExterno do corpo precisa ser igual ao do caminho, e o tipo precisa ser o mesmo do manifesto original.
CHAVE_CTE="3526091122233300018157""0010000123451482135762"
curl -X PUT "$BASE/integracao/v1/manifestos/REL-2026-000123" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-H "Idempotency-Key: 0192f3a4-5b6c-7d8e-9f01-23456789abce" \
-H "Content-Type: application/json" \
-d @- <<JSON
{
"tipo": "ENTREGA",
"numeroExterno": "REL-2026-000123",
"motorista": { "cpf": "111.444.777-35", "nome": "Outro Motorista Exemplo" },
"veiculo": { "placa": "XYZ9A87" },
"documentos": [
{
"modelo": 57,
"chave": "$CHAVE_CTE",
"numero": "12345",
"serie": "1",
"cnpjTransportadora": "11222333000181",
"destinatario": {
"cnpjCpf": "11444777000161",
"nome": "Mercado Exemplo Ltda",
"endereco": { "logradouro": "Rua das Flores", "numero": "120", "municipio": "Campinas", "uf": "SP" }
},
"nfVinculadas": [
{ "numero": "45678", "serie": "1", "cnpjEmbarcador": "12345678000195" }
]
}
]
}
JSONResposta de sucesso: 200, com a estrutura de ManifestoResponse (como no GET): versaoAtual sobe e documentos mostra a situação atual. Se algo foi recusado, vem em erros:
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000001",
"numeroExterno": "REL-2026-000123",
"tipo": "ENTREGA",
"ambiente": "PRODUCAO",
"versaoAtual": 2,
"quantidadeParadas": 1,
"quantidadeDocumentos": 2,
"documentos": [],
"erros": [
{
"documentoIndex": null,
"codigo": "DOCUMENTO_JA_BAIXADO",
"motivo": "O documento já tem baixa e não pode ser removido do manifesto",
"chave": "3526091122233300018157...",
"numero": "12346"
}
]
}(O campo documentos foi resumido neste exemplo.) documentoIndex fica null quando o documento recusado não está na sua lista, que é o caso da remoção recusada.
Erros
| Status | Quando | O que fazer |
|---|---|---|
400 | numeroExterno do corpo diferente do caminho (detail: "numeroExterno do corpo difere do informado no caminho") | Igualar os dois |
400 | Tentou mudar o tipo (detail: "o tipo do manifesto não pode mudar (atual: ...)") | Manter o tipo; para outro tipo, cancele e crie outro manifesto |
400 | Qualquer erro de cabeçalho do manifesto ou de Idempotency-Key (as mesmas regras do POST) | Corrigir |
400 | Todos os documentos recusados | Corrigir os documentos |
401 | Chave inválida | Conferir a chave |
403 | Chave sem permissão | Usar a chave de TMS |
404 | O manifesto não existe neste ambiente | Conferir o numeroExterno e o ambiente da chave |
409 | Idempotency-Key já usada com outro corpo | Gerar uma chave nova |
Observações
- Documento que sumiu mas já tem baixa ou ocorrência não é removido. O restante da alteração é aplicado e a resposta traz
DOCUMENTO_JA_BAIXADOemerros. Um comprovante nunca some. - Reenviar exatamente o conteúdo atual (mesmo com outra
Idempotency-Key) não cria versão nova: a resposta traz a mesmaversaoAtual. - Idempotência igual à do
POST: mesma chave e mesmo corpo devolve a mesma resposta. - Ambiente. O manifesto é localizado pelo ambiente da chave e a alteração nunca muda o ambiente dele.
- Um documento cancelado ou devolvido que volta no manifesto é tratado como nova tentativa e volta a
PENDENTE. Entregue continua entregue. - Uma alteração não gera webhook; a nova versão fica na linha do tempo do manifesto.
POST /integracao/v1/manifestos/{numeroExterno}/cancelar#
Para que serve: cancela o que ainda falta de um manifesto (cancelamento parcial).
Quando chamar: quando a viagem foi desfeita (veículo quebrou, carga redistribuída). Os documentos cancelados saem do app do motorista.
Cabeçalhos: X-Veltra-Api-Key. O corpo é opcional; se mandar, use Content-Type: application/json. Não precisa de Idempotency-Key.
Parâmetros de caminho
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
numeroExterno | texto | sim | O número do manifesto no seu TMS |
Corpo da requisição (opcional)
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
motivo | texto (até 500) | não | Motivo, registrado na linha do tempo de cada documento cancelado |
curl -X POST "$BASE/integracao/v1/manifestos/REL-2026-000123/cancelar" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-H "Content-Type: application/json" \
-d '{ "motivo": "Veículo quebrado; carga redistribuída em outro manifesto" }'Resposta de sucesso: 200, com a situação do manifesto depois do cancelamento. O que já foi entregue permanece:
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000001",
"numeroExterno": "REL-2026-000123",
"tipo": "ENTREGA",
"ambiente": "PRODUCAO",
"versaoAtual": 2,
"quantidadeParadas": 1,
"quantidadeDocumentos": 2,
"documentos": [
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000010",
"modelo": 57,
"chave": "3526091122233300018157...",
"numero": "12345",
"serie": "1",
"status": "CANCELADO",
"nfVinculadas": []
},
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000012",
"modelo": 57,
"chave": "3526091122233300018157...",
"numero": "12346",
"serie": "1",
"status": "ENTREGUE",
"nfVinculadas": []
}
],
"erros": []
}Erros
| Status | Quando | O que fazer |
|---|---|---|
400 | motivo com mais de 500 caracteres | Encurtar |
401 | Chave inválida | Conferir a chave |
403 | Chave sem permissão | Usar a chave de TMS |
404 | O manifesto não existe neste ambiente | Conferir o numeroExterno e o ambiente |
Observações
- Cancelar de novo é seguro: responde
200com a mesma situação, sem mudar nada. - O cancelamento é por documento: só o que ainda não foi entregue nem coletado é cancelado.
- Cancelar não gera webhook de manifesto.
Leitura de saída (/v1/saida)
Estas rotas servem para ler o que o Veltra registrou. Elas valem para o ambiente da sua chave. Para saber as regras de cada finalidade de chave, veja a tabela de finalidades no começo da página.
GET /v1/saida/eventos#
Para que serve: lista os eventos que mudaram desde a última leitura: baixa, ocorrência, comprovante, chegada e saída de parada, posição do veículo, estado do evento do CT-e, e as mudanças de manifesto.
Quando chamar: em repetição, de tempos em tempos, para manter o TMS em dia. É o jeito de "puxar" as novidades. Se preferir ser avisado, use os webhooks (os eventos têm o mesmo formato).
Cabeçalhos: X-Veltra-Api-Key.
Parâmetros de consulta
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
alteradoDesde | texto | não | O proximoCursor da resposta anterior. Omitido: começa do início |
limite | inteiro, de 1 a 200 | não | Quantos itens por resposta. Padrão: 50 |
Primeira leitura
curl "$BASE/v1/saida/eventos?limite=100" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"Próximas leituras (com o cursor guardado)
curl "$BASE/v1/saida/eventos?limite=100&alteradoDesde=CURSOR_GUARDADO_AQUI" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"Resposta de sucesso: 200
{
"itens": [
{
"id": "018f6a2e-7c31-7a3e-8c2a-000000000006",
"tipo": "baixa.registrada",
"versao": 1,
"ocorridoEm": "2026-10-22T12:00:00-03:00",
"ambiente": "PRODUCAO",
"dados": {
"paradaId": "22222222-2222-4222-8222-222222222222",
"baixaId": "44444444-4444-4444-8444-444444444444",
"documentoId": "33333333-3333-4333-8333-333333333333"
}
},
{
"id": "018f6a2e-7c31-7a3e-8c2a-000000000008",
"tipo": "comprovante.emitido",
"versao": 1,
"ocorridoEm": "2026-10-22T12:00:00-03:00",
"ambiente": "PRODUCAO",
"dados": {
"documentoId": "33333333-3333-4333-8333-333333333333",
"comprovanteId": "66666666-6666-4666-8666-666666666666"
}
}
],
"proximoCursor": "CURSOR_GUARDADO_AQUI"
}| Campo | Descrição |
|---|---|
itens | Lista de eventos no mesmo envelope dos webhooks: id, tipo, versao, ocorridoEm, ambiente, dados. O conteúdo de dados depende do tipo |
itens[].id | Identifica o evento. Use para não processar duas vezes |
itens[].tipo | Um destes: parada.chegada, parada.saida, baixa.registrada, ocorrencia.registrada, comprovante.emitido, evento_cte.estado_alterado, posicao.lote |
proximoCursor | Guarde e mande em alteradoDesde na próxima leitura. É null quando não há nada a devolver e você ainda não tinha cursor |
O formato exato de dados de cada tipo está nos esquemas de contracts/webhooks/ e na referência de webhooks.
Erros
| Status | Quando | O que fazer |
|---|---|---|
400 | limite fora de 1 a 200 (detail: "limite deve estar entre 1 e 200") | Corrigir |
400 | Cursor inventado ou alterado (detail: "cursor alteradoDesde inválido") | Use só o valor devolvido em proximoCursor |
401 | Chave inválida | Conferir a chave |
403 | Chave sem permissão, ou CHAVE_SUSPENSA (chave de consulta sem o módulo) | Usar a chave certa |
429 | Limite de chamadas | Esperar o Retry-After |
Observações
- Janela de 5 segundos. Um evento recém-criado pode demorar alguns segundos para aparecer. Não é falha; consulte de novo.
- Repetição é normal. O mesmo evento pode vir em duas respostas seguidas (por exemplo, se o seu processo caiu antes de guardar o cursor). Processar duas vezes tem de dar o mesmo resultado: trate pelo
id. - Fluxo recomendado: leia, processe os itens, só depois grave o
proximoCursor. - Posição do veículo (
posicao.lote) vai só para a chave do TMS. Chaves de embarcador e destinatário não recebem esse tipo. - Chaves de consulta só veem eventos de documentos das raízes de CNPJ cadastradas nelas.
- Leitura pura: pode ser repetida sem efeito colateral.
GET /v1/saida/manifestos#
Para que serve: lista os manifestos do ambiente da chave, com cursor.
Quando chamar: para conferir ou reconstruir a lista de manifestos que o Veltra tem (por exemplo, numa conciliação). Só a chave do TMS usa esta rota.
Cabeçalhos: X-Veltra-Api-Key.
Parâmetros de consulta: alteradoDesde e limite, como em /v1/saida/eventos.
curl "$BASE/v1/saida/manifestos?limite=50" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"Resposta de sucesso: 200
{
"itens": [
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000001",
"numero": "REL-2026-000123",
"tipoManifesto": "ENTREGA",
"atualizadoEm": "2026-10-22T15:00:00Z",
"kmSaida": 120000,
"kmChegada": 120450,
"kmRodados": 450
}
],
"proximoCursor": "CURSOR_GUARDADO_AQUI"
}| Campo | Descrição |
|---|---|
itens[].id | O id do manifesto no Veltra |
itens[].numero | O numeroExterno do seu TMS |
itens[].tipoManifesto | O tipo gravado do manifesto |
itens[].atualizadoEm | Última atualização |
itens[].kmSaida | Km do hodômetro informado pelo motorista na saída do veículo da base. null quando não foi informado |
itens[].kmChegada | Km informado na chegada. null enquanto não chegou ou não informou |
itens[].kmRodados | kmChegada - kmSaida. null quando falta um dos dois ou quando a chegada é menor que a saída (a torre recebe um alerta de km) |
proximoCursor | Cursor para a próxima leitura |
Erros: 400 (limite ou cursor inválidos), 401, 403 (chave que não é de TMS), 429.
Observações: os três campos de km vêm da viagem (saída da base) mais recente que levou o manifesto e são null para manifesto sem saída de veículo (por exemplo, uma entrega comum sem transferência). Mudar o km não muda atualizadoEm: para saber na hora que o km foi informado, assine o evento veiculo.km_registrado. É só uma lista resumida, sem os documentos. Para a situação de cada documento, use GET /integracao/v1/manifestos/{numeroExterno}. O cursor funciona como o de eventos, com a mesma janela de 5 segundos.
GET /v1/saida/manifestos/{id}#
Para que serve: mostra um manifesto pelo id do Veltra.
Quando chamar: quando você tem o id (da resposta do envio) e quer o resumo. Só a chave do TMS usa.
Cabeçalhos: X-Veltra-Api-Key.
Parâmetros de caminho
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | texto (uuid) | sim | O id do manifesto, devolvido no envio |
curl "$BASE/v1/saida/manifestos/0192f3a4-5b6c-7d8e-9f01-000000000001" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"Resposta de sucesso: 200
{
"id": "0192f3a4-5b6c-7d8e-9f01-000000000001",
"numero": "REL-2026-000123",
"tipoManifesto": "ENTREGA",
"atualizadoEm": "2026-10-22T15:00:00Z",
"kmSaida": 120000,
"kmChegada": null,
"kmRodados": null
}Os campos kmSaida, kmChegada e kmRodados são os mesmos da lista (acima) e são null quando o motorista ainda não informou o km.
Erros: 401, 403, 404 (não existe neste ambiente ou é de outra transportadora), 400 (id que não é um UUID), 429.
Observações: não traz trilha nem posição do veículo.
GET /v1/saida/documentos/{id}#
Para que serve: mostra a situação de um documento fiscal (CT-e ou NF) pelo id do Veltra.
Quando chamar: quando um evento citou o documentoId e você quer saber o estado atual desse documento.
Cabeçalhos: X-Veltra-Api-Key. Aceita a chave do TMS e as chaves de consulta.
Parâmetros de caminho
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | texto (uuid) | sim | O id do documento (documentos[].id da resposta do manifesto, ou documentoId dos eventos) |
curl "$BASE/v1/saida/documentos/33333333-3333-4333-8333-333333333333" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"Resposta de sucesso: 200
{
"id": "33333333-3333-4333-8333-333333333333",
"numero": "12345",
"status": "ENTREGUE",
"podeVerPdfECanhoto": true,
"atualizadoEm": "2026-10-22T15:05:00Z"
}| Campo | Descrição |
|---|---|
status | Estado atual do documento, por exemplo PENDENTE, EM_TRANSPORTE, ENTREGUE, CANCELADO |
podeVerPdfECanhoto | Para o TMS da transportadora, sempre true. Para chave de consulta, só é true quando o terceiro é o tomador do frete |
Erros: 401, 403, 404 (não existe neste ambiente, ou, para chave de consulta, está fora das raízes de CNPJ da chave: é a mesma resposta de "não existe"), 400 (id inválido), 429.
Observações: não traz posição, placa ou trilha do veículo.
GET /v1/saida/comprovantes/{id}/pdf#
Para que serve: baixa o PDF do comprovante de um documento. É o mesmo arquivo que o portal mostra.
Quando chamar: depois de receber o evento comprovante.emitido; o comprovanteId está em dados. Só a chave do TMS usa. Chave de consulta recebe 403.
Cabeçalhos: X-Veltra-Api-Key.
Parâmetros de caminho
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | texto (uuid) | sim | O comprovanteId do evento comprovante.emitido |
curl "$BASE/v1/saida/comprovantes/66666666-6666-4666-8666-666666666666/pdf" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-o comprovante.pdfResposta de sucesso: 200 com Content-Type: application/pdf e o cabeçalho Content-Disposition com o nome comprovante-<id>.pdf. O corpo é o arquivo.
Erros
| Status | Quando | O que fazer |
|---|---|---|
401 | Chave inválida | Conferir a chave |
403 | Chave que não é de TMS | Usar a chave de TMS |
404 | COMPROVANTE_NAO_ENCONTRADO: o comprovante não existe neste ambiente (ou é de outra transportadora). Vem em application/problem+json, com o código no campo codigo | Conferir o id (é o comprovanteId do evento comprovante.emitido) e o ambiente da chave |
409 | COMPROVANTE_AINDA_NAO_PUBLICADO: o comprovante existe, mas o PDF ainda não foi publicado. Vem em application/problem+json, com o código no campo codigo | Esperar um pouco e tentar de novo; o certo é baixar depois do evento comprovante.emitido |
429 | Limite de chamadas | Esperar o Retry-After |
Observações: o arquivo é entregue como está guardado; baixe e confira o SHA-256 se quiser provar que não mudou. O PDF só vem assinado quando a transportadora ligou a validação opcional (veja o módulo 6 da trilha). Cada download é registrado para fins de medição, e o download pode ser repetido.
GET /v1/saida/comprovantes/{id}/pacote#
Para que serve: baixa o pacote de evidências (arquivo ZIP) do comprovante: o PDF, o manifesto da evidência e os arquivos de apoio (as fotos, e os arquivos de validação quando existem).
Quando chamar: quando você precisa guardar a prova completa de uma entrega, por exemplo para auditoria ou para anexar numa disputa. Só a chave do TMS usa.
Cabeçalhos: X-Veltra-Api-Key.
Parâmetros de caminho: id (uuid), o comprovanteId, como na rota do PDF.
curl "$BASE/v1/saida/comprovantes/66666666-6666-4666-8666-666666666666/pacote" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-o comprovante.zipResposta de sucesso: 200 com Content-Type: application/zip e Content-Disposition com o nome comprovante-<id>.zip. O corpo é o arquivo.
Erros: os mesmos do PDF: 401, 403, 429, 404 (COMPROVANTE_NAO_ENCONTRADO) para comprovante inexistente e 409 (COMPROVANTE_AINDA_NAO_PUBLICADO) para comprovante ainda não publicado, ambos em application/problem+json.
Observações: o ZIP traz um arquivo LEIA-ME.txt que explica o conteúdo. Se uma foto ainda não estiver disponível, o pacote não é entregue e a resposta é um erro: tente depois.
GET /v1/saida/eventos-cte/{id}/xml#
Para que serve: baixa o XML assinado do evento 110180 (Comprovante de Entrega do CT-e), com o protocolo da SEFAZ.
Quando chamar: quando o estado do evento do CT-e chegou a REGISTRADO (evento evento_cte.estado_alterado) e o TMS quer guardar o XML. Só a chave do TMS usa.
Importante: o Veltra não transmite o evento 110190 (insucesso). Esse evento deve ser emitido pelo TMS por conta própria.
Cabeçalhos: X-Veltra-Api-Key.
Parâmetros de caminho
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | texto (uuid) | sim | O id do evento do CT-e no Veltra: o mesmo id que a tela de eventos do CT-e do portal usa |
curl "$BASE/v1/saida/eventos-cte/0192f3a4-5b6c-7d8e-9f01-000000000300/xml" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-o evento-110180.xmlResposta de sucesso: 200 com Content-Type: application/xml e o XML no corpo.
Erros
| Status | Quando | O que fazer |
|---|---|---|
401 | Chave inválida | Conferir a chave |
403 | Chave que não é de TMS | Usar a chave de TMS |
404 | Não existe neste ambiente, ou o perfil da transportadora não gerou o evento 110180 para esse documento | Confirmar o perfil com a transportadora |
429 | Limite de chamadas | Esperar o Retry-After |
Observações: o XML só existe para documentos cujo perfil da transportadora gera esse evento. O download é registrado para medição e pode ser repetido.
GET /v1/saida/openapi/{finalidade}#
Para que serve: devolve o OpenAPI filtrado (em YAML) com só as rotas que a finalidade pode chamar. Use para gerar um cliente de código sem as rotas que a sua chave não alcança.
Quando chamar: uma vez, ao começar a integração de leitura, e quando quiser regenerar o cliente.
Cabeçalhos: X-Veltra-Api-Key.
Parâmetros de caminho
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
finalidade | texto | sim | INTEGRACAO_TMS, CONSULTA_EMBARCADOR ou CONSULTA_DESTINATARIO |
curl "$BASE/v1/saida/openapi/INTEGRACAO_TMS" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-o veltra-saida-tms.yamlResposta de sucesso: 200 com Content-Type: application/yaml.
Erros
| Status | Quando | O que fazer |
|---|---|---|
400 | Finalidade desconhecida (detail: "Finalidade desconhecida.") | Usar um dos três valores |
401 | Chave inválida | Conferir a chave |
403 | A chave não recebe esse OpenAPI: chave de consulta pedindo a finalidade de outro tipo, ou pedido de ENTRADA_TRANSPORTADORA | Pedir a finalidade da própria chave |
429 | Limite de chamadas | Esperar o Retry-After |
Observações: a chave do TMS pode pedir qualquer uma das três finalidades. Chave de consulta só obtém a própria finalidade. Este arquivo é separado do Swagger público: ele cobre as rotas /v1/saida/**.
GET /v1/saida/configuracao-prazo#
Para que serve: lê a regra de prazo de entrega da transportadora: o prazo padrão, a data-base, as horas por cidade e os feriados locais.
Quando chamar: antes de gravar uma configuração nova (para não apagar o que já existe), ou para conferir o que o Veltra está usando.
Cabeçalhos: X-Veltra-Api-Key.
Parâmetros: nenhum.
curl "$BASE/v1/saida/configuracao-prazo" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"Resposta de sucesso: 200
{
"prazoPadraoHoras": 72,
"dataBase": "NFE",
"origemPrazo": "TMS_QUANDO_VIER",
"cidades": [
{ "municipio": "Campinas", "uf": "SP", "horas": 48 }
],
"feriadosLocais": [
{ "data": "2026-07-14", "nome": "Feriado municipal" }
]
}| Campo | Tipo | Descrição |
|---|---|---|
prazoPadraoHoras | inteiro, de 1 a 720 | Prazo padrão, em horas úteis (segunda a sexta, no fuso de São Paulo) |
dataBase | texto | De onde o prazo começa a contar: CTE (emissão do CT-e), NFE (emissão da NF-e) ou CHEGADA_MANIFESTO. Se a data escolhida não existir, vale a chegada do manifesto |
origemPrazo | texto | TMS_QUANDO_VIER: se o TMS mandar prazoEntrega, ele prevalece. SEMPRE_CONFIGURADO: vale sempre o prazo calculado pela configuração |
cidades | lista | Horas específicas por município e UF (cada uma de 1 a 720) |
feriadosLocais | lista | Datas que não consomem horas, além dos feriados nacionais |
Sem configuração gravada, a resposta traz o padrão: 72 horas, NFE, TMS_QUANDO_VIER, sem cidades e sem feriados.
Erros: 401, 403 (chave que não é de TMS), 429.
Observações: é a mesma configuração que o portal mostra. O portal também responde em GET /v1/configuracao-prazo; para o TMS, use a rota /v1/saida/.
PUT /v1/saida/configuracao-prazo#
Para que serve: grava a relação de cidades, prazos e feriados. Substitui toda a configuração.
Quando chamar: na implantação, e sempre que o prazo por cidade ou os feriados mudarem no TMS. A mudança vale para as cargas que chegarem depois.
Cabeçalhos: X-Veltra-Api-Key e Content-Type: application/json.
Corpo da requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
prazoPadraoHoras | inteiro, de 1 a 720 | sim | Prazo padrão em horas úteis |
dataBase | texto | sim | CTE, NFE ou CHEGADA_MANIFESTO |
origemPrazo | texto | sim | TMS_QUANDO_VIER ou SEMPRE_CONFIGURADO |
cidades | lista | sim | Pode ser vazia. Cada item: municipio (até 120), uf (2 letras), horas (de 1 a 720). Não repita município e UF |
feriadosLocais | lista | sim | Pode ser vazia. Cada item: data (AAAA-MM-DD) e nome (até 120). Não repita data |
curl -X PUT "$BASE/v1/saida/configuracao-prazo" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-H "Content-Type: application/json" \
-d '{
"prazoPadraoHoras": 72,
"dataBase": "CTE",
"origemPrazo": "SEMPRE_CONFIGURADO",
"cidades": [
{ "municipio": "Campinas", "uf": "SP", "horas": 48 },
{ "municipio": "Sumaré", "uf": "SP", "horas": 48 }
],
"feriadosLocais": [
{ "data": "2026-07-14", "nome": "Feriado municipal" }
]
}'Resposta de sucesso: 200, com a configuração gravada (mesmo formato do GET; as UFs são devolvidas em maiúsculas e os nomes sem espaços sobrando).
Erros
| Status | Quando | O que fazer |
|---|---|---|
400 | prazoPadraoHoras fora de 1 a 720; cidades ou feriadosLocais ausentes; cidade, UF ou horas inválidas; cidade repetida; feriado inválido; data de feriado repetida | Corrigir o corpo |
401 | Chave inválida | Conferir a chave |
403 | Chave que não é de TMS | Usar a chave de TMS |
429 | Limite de chamadas | Esperar o Retry-After |
Observações
- É uma substituição completa. As cidades e os feriados que você não mandar são apagados. Leia com o
GET, altere e devolva tudo. - É seguro repetir: o mesmo corpo dá o mesmo resultado.
- Configurar o prazo não substitui a conversa com a transportadora sobre calendário local e regra de prazo; combine antes de ligar em produção.
- A configuração é única da transportadora e não separa teste de produção.
Boas práticas de integração
- Guarde a chave em um cofre, nunca em código, log ou e-mail. Use uma chave por sistema, para revogar só a que vazou.
- Comece pela chave de teste e só vá para produção depois da homologação (checklist abaixo).
- Use
Idempotency-Keysempre, com um UUID gerado antes da primeira tentativa e guardado junto do registro que você está enviando. Na repetição, mande o mesmo valor. - Repita com pausa crescente em
429e em5xx: espere oRetry-Afterquando existir; senão, 1 s, 2 s, 4 s, e assim por diante, com um teto. - Não repita sem pensar em
400. Erro400não se resolve repetindo: corrija o dado. - Leia sempre
errosdepois de um201ou200de manifesto. O manifesto pode ter sido criado com documentos recusados. - Guarde os ids do Veltra (
iddo manifesto,documentos[].id) junto donumeroExternodo seu TMS. - Leia eventos com cursor, em ordem, e grave o cursor só depois de processar. Trate cada evento pelo
id. - Prefira webhooks para ser avisado e use o
GET /v1/saida/eventoscomo rede de segurança (por exemplo, uma leitura a cada poucos minutos) para recuperar o que se perdeu. - Ignore campos que você não conhece e não quebre com valores novos de listas.
- Use o
statusHTTP e ocodigopara decidir o que fazer, nunca o texto dedetail. - Registre em log o
Idempotency-Key, onumeroExternoe ostatusde cada chamada (sem a chave de API).
Erros comuns e como resolver
| Sintoma | Causa provável | Como resolver |
|---|---|---|
401 em tudo | Chave com espaço, cortada, revogada, ou transportadora desativada | Copiar de novo; conferir com GET /v1/api-keys/atual; ver a tela Chaves de API |
401 mesmo com a chave certa | Mandou também Authorization | Enviar só X-Veltra-Api-Key |
403 ao criar filial | Está usando a chave de teste | Usar a chave de produção |
403 com CHAVE_SUSPENSA | Chave de consulta ou de entrada sem o módulo contratado | Contratar o módulo no portal; a chave volta sozinha |
404 ao consultar um manifesto que você acabou de enviar | Chave de ambiente diferente (enviou com teste, consulta com produção, ou o contrário) | Usar a mesma chave nas duas chamadas |
400 "cabeçalho Idempotency-Key é obrigatório" | Faltou o cabeçalho no POST ou no PUT | Incluir Idempotency-Key |
400 "motorista.cpf inválido" | CPF com dígito verificador errado | Corrigir o CPF |
400 "filialOrigemSigla: filial com sigla externa ... não encontrada" | A filial não está cadastrada | Cadastrar a filial antes |
400 com documentos-invalidos | Todos os documentos foram recusados | Ler erros, corrigir e reenviar |
201 mas falta um documento | Ele foi recusado e está em erros | Corrigir e reenviar com PUT |
409 ao reenviar o mesmo manifesto | numeroExterno já existe | Use PUT para alterar |
409 "Idempotency-Key já usada com outro corpo" | Reusou a chave de idempotência com um manifesto diferente | Gerar uma chave nova para cada envio diferente |
409 TESTE_ENCERRADO | O teste grátis da transportadora acabou | A transportadora contrata no portal |
O evento não aparece em /v1/saida/eventos | Janela de 5 segundos, ou o cursor está à frente | Esperar e consultar de novo; guardar o cursor só depois de processar |
400 "cursor alteradoDesde inválido" | Montou ou editou o cursor | Usar só o proximoCursor devolvido |
Erro (404, 409 ou 500) no PDF ou no pacote | O comprovante não existe neste ambiente ou ainda não foi publicado | Conferir o id e o ambiente; tentar de novo depois, com pausa |
404 no XML do evento do CT-e | O perfil da transportadora não gerou o evento 110180 | Confirmar o perfil com a transportadora |
429 | Passou do limite por minuto | Esperar o Retry-After e reduzir o ritmo |
Checklist de homologação do TMS
Marque cada item com a chave de teste antes de pedir a chave de produção.
- A chave de teste funciona em
GET /v1/api-keys/atuale mostra"ambiente": "TESTE". - O TMS não manda
Authorizationjunto comX-Veltra-Api-Key. - A chave não está em código, em log nem em repositório.
- As filiais foram cadastradas (no portal, ou pela API com chave de produção) e a lista
GET /integracao/v1/filiaisconfere com o TMS. - Um manifesto de entrega foi enviado com sucesso (
201) e consultado comGET. - Um manifesto de coleta sem CT-e foi enviado.
- Um manifesto de transferência foi enviado com as siglas das duas filiais.
- O TMS lê
errosna resposta e mostra o motivo ao operador. - O reenvio com a mesma
Idempotency-Keye o mesmo corpo devolveu200e não duplicou nada. - Reenviar o mesmo
numeroExternocom outraIdempotency-Keydevolveu409, e o TMS tratou como "já enviado". - A alteração com
PUT(troca de motorista ou de documento) subiu aversaoAtual. - O cancelamento foi testado, inclusive repetido.
- O TMS trata
400,401,403,404,409,429e5xxcomo descrito nesta página. - A leitura
GET /v1/saida/eventosguarda o cursor, trata oiddo evento e tolera repetição. - O PDF e o pacote de um comprovante de teste foram baixados e abertos.
- Se o TMS usa o evento do CT-e: o XML do 110180 foi baixado (ou o
404foi tratado). - A configuração de prazo foi lida e gravada com a lista completa (sabendo que ela é única por transportadora).
- Os webhooks, se usados, verificam a assinatura (veja o módulo 5).
- A transportadora emitiu a chave de produção (tela Chaves de API) e a chave de teste continua separada.