Trilha · Módulo 4
Manifestos pela API
Manifestos pela API
Este módulo é para quem desenvolve a integração do sistema da transportadora (TMS ou sistema legado). Ele mostra, com exemplos que você copia e cola, como enviar um manifesto ao Veltra, repetir o envio sem duplicar, alterar e cancelar. Todos os valores dos exemplos são fictícios. A lista completa de rotas e campos está na referência da API de entrada.
Antes de começar, a transportadora precisa ter as filiais cadastradas, como mostra o módulo 2, e saber o que o motorista vê no app, como mostra o módulo 3.
Como funciona, em poucas linhas#
- Um manifesto (uma viagem, um romaneio) é enviado inteiro, numa chamada, em JSON.
- O Veltra não recebe XML: recebe as chaves e os dados essenciais de cada documento.
- O envio é idempotente: repetir a mesma chamada não duplica nada.
- Para alterar, reenvie o manifesto inteiro com
PUT. Para cancelar, usePOST .../cancelar. - O Veltra monta as paradas sozinho, agrupando os documentos pelo destinatário (CNPJ ou CPF) e pelo endereço.
Conseguir a chave de entrada#
Abra Chaves de consulta no portal
No menu do portal, entre em Integrações e depois em Chaves de consulta; as chaves do TMS ficam na seção Chaves do TMS. A tela é restrita a quem tem perfil de administrador da transportadora.
Gere a chave
Use Criar chave, escolha um Nome que ajude você a reconhecê-la (por exemplo, "TMS teste") e o Ambiente: Teste ou Produção, e confirme em Gerar chave. A chave de Produção só é emitida para transportadora ativa; fora disso o portal avisa que não foi possível emitir.
Copie a chave na hora
O valor completo da chave aparece uma única vez, logo depois de gerada. Depois disso, a lista mostra só o prefixo. Guarde a chave num cofre de segredos do seu sistema. Nunca coloque a chave em código versionado, em log ou em e-mail. Se ela vazar, revogue na mesma tela e gere outra.
Nos exemplos deste módulo, SUA_CHAVE_AQUI é um texto de mentira: troque pela sua chave real.
Autenticação, endereço e ambientes#
- Cabeçalho de autenticação:
X-Veltra-Api-Key: SUA_CHAVE_AQUI. Chave ausente, errada ou revogada devolve401. - Endereço base: o contrato usa
http://localhost:8080para o ambiente local. O endereço do seu ambiente é combinado na entrega das chaves. Nos exemplos abaixo, a variávelBASEguarda esse endereço. - Cabeçalho
Idempotency-Key: obrigatório em todo envio de manifesto (POSTePUT). Veja a seção sobre repetição.
As duas chaves levam a dois ambientes que nunca se misturam:
| Chave | O que acontece com o manifesto |
|---|---|
| Teste | É gravado como manifesto de teste (aparece na aba "Teste" em Manifestos). Nunca chega ao app de motoristas reais, nunca dispara webhook de produção e é apagado depois de cerca de 30 dias. Use para desenvolver e homologar. |
| Produção | É gravado como manifesto real. |
Idempotência, número do manifesto e vínculo de documentos são separados por ambiente: o mesmo numeroExterno pode existir uma vez em teste e uma vez em produção. Consultar com a chave de teste só enxerga manifestos de teste, e o contrário também.
Dois cuidados que dependem da situação da conta:
- Se o teste grátis da transportadora acabou, a chave de Produção não grava manifesto novo e a resposta é
409com o códigoTESTE_ENCERRADO. A chave de teste não é afetada. O reenvio idempotente de um manifesto que já foi gravado continua devolvendo o resultado gravado, sem erro. O módulo 1 explica o período de teste. - A chave de Teste só lê filiais. Para criar ou alterar filiais pela API é preciso a chave de Produção; com a de teste a resposta é
403.
Passo 1: ter as filiais cadastradas#
O manifesto de transferência cita as filiais pela sigla externa, a mesma que você cadastrou no portal. Sigla desconhecida recusa o manifesto inteiro com 400. O jeito mais simples é cadastrar as filiais no portal (módulo 2). Se preferir pela API, use a chave de Produção.
Exemplo de cadastro de filial (nome e siglaExterna são obrigatórios; a siglaExterna não pode se repetir na transportadora, senão a resposta é 409):
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"
}'Pela API o endereço da filial não é localizado no mapa automaticamente: sem latitude e longitude, a filial fica sem pino até alguém ajustar no portal. Para listar as filiais use GET /integracao/v1/filiais.
Passo 2: enviar o primeiro manifesto#
Há três tipos de uso. Em todos, a ordem da lista documentos é a ordem sugerida das paradas.
Campos que mais importam#
| Campo | Obrigatório | Regra |
|---|---|---|
tipo | sim | ENTREGA, COLETA ou TRANSFERENCIA. Existe também ROTA, para o caminhão que sai com entregas e coletas juntas; ENTREGA e COLETA continuam aceitos e são tratados como ROTA. Não muda depois de criado. |
numeroExterno | sim | Número do manifesto no seu sistema (até 60 caracteres). É único por transportadora e ambiente. No PUT deve ser igual ao do caminho. |
motorista | sim | cpf (11 dígitos, com ou sem máscara, com dígitos verificadores válidos) e nome. |
veiculo | sim | placa, com ou sem hífen. |
filialOrigemSigla, filialDestinoSigla | só em TRANSFERENCIA | Siglas cadastradas no Veltra. |
documentos | sim | Pelo menos 1 documento. |
Em cada documento:
| Campo | Obrigatório | Regra |
|---|---|---|
modelo | sim | Número: 57 para CT-e, 55 para NF-e. Envie como número, não como texto. |
numero | sim | Número do documento (até 20 caracteres). |
chave | sim para CT-e | 44 posições. O Veltra confere o dígito verificador. |
cnpjEmbarcador | só fora do CT-e | CNPJ do embarcador, dono da NF. Obrigatório quando o modelo não é 57. |
destinatario | sim | cnpjCpf, nome e endereco (logradouro, municipio e uf são obrigatórios). |
nfVinculadas | para CT-e | As NF que o CT-e transporta; cada uma com numero e cnpjEmbarcador. |
tarefa | não | ENTREGA ou COLETA. Omitida: coleta em manifesto de coleta e entrega nos demais tipos. |
volumes, peso, prazoEntrega | não | peso em kg; prazoEntrega no formato AAAA-MM-DD. |
Campos que não constam no contrato são ignorados. Cuidado com o inverso: um campo obrigatório com o nome errado é tratado como ausente e gera erro. Os nomes diferenciam maiúsculas de minúsculas (por exemplo, cnpjEmbarcador, nunca cnpj_embarcador).
A chave do CT-e tem 44 posições (normalmente só dígitos; os 12 caracteres do CNPJ de quem emitiu podem ter letras). Nos exemplos ela está dividida em duas partes dentro de uma variável do shell, só para caber melhor na tela; o resultado é a chave inteira.
Entrega#
Um CT-e com uma NF, para um destinatário:
BASE="http://localhost:8080"
CHAVE_CTE="3526091122233300018157""0010000123451876543215"
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": "173999",
"motorista": { "cpf": "529.982.247-25", "nome": "Motorista Exemplo da Silva" },
"veiculo": { "placa": "ABC-1D23" },
"documentos": [
{
"modelo": 57,
"chave": "$CHAVE_CTE",
"numero": "12345",
"serie": "1",
"destinatario": {
"cnpjCpf": "11444777000161",
"nome": "Mercado Exemplo Ltda",
"endereco": { "logradouro": "Rua das Flores 120", "bairro": "Centro", "municipio": "Campinas", "uf": "SP" }
},
"nfVinculadas": [
{ "numero": "45678", "serie": "1", "cnpjEmbarcador": "12345678000195" }
],
"volumes": 12,
"peso": 350.5,
"prazoEntrega": "2026-10-02"
}
]
}
JSONResposta esperada: 201, com o manifesto na versão 1. Se vários CT-e forem para o mesmo destinatário e o mesmo endereço, o Veltra cria uma parada só, com todos os documentos.
Coleta#
A coleta normalmente ainda não tem CT-e: o documento é a NF (modelo 55), identificada por numero, serie e cnpjEmbarcador. A chave da NF é opcional. O destinatario é o local onde o motorista vai buscar, com o CNPJ ou CPF de quem entrega a carga.
curl -X POST "$BASE/integracao/v1/manifestos" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-H "Idempotency-Key: 0192f3a4-5b6c-7d8e-9f01-23456789abce" \
-H "Content-Type: application/json" \
-d '{
"tipo": "COLETA",
"numeroExterno": "COL-173999",
"motorista": { "cpf": "529.982.247-25", "nome": "Motorista Exemplo da Silva" },
"veiculo": { "placa": "ABC-1D23" },
"documentos": [
{
"modelo": 55,
"numero": "45678",
"serie": "1",
"cnpjEmbarcador": "12345678000195",
"destinatario": {
"cnpjCpf": "12345678000195",
"nome": "Indústria Exemplo S.A.",
"endereco": { "logradouro": "Avenida Industrial 1000", "municipio": "Sumaré", "uf": "SP" }
},
"volumes": 20,
"peso": 800
}
]
}'Quando o CT-e for emitido depois, ele chega em outro manifesto com as mesmas NF e o Veltra vincula sozinho o CT-e às NF pelas chaves.
Para uma viagem mista (entrega e coleta no mesmo manifesto), diga em cada documento o que o motorista faz, com "tarefa": "COLETA" ou "tarefa": "ENTREGA". Se a coleta e a entrega forem no mesmo destinatário e endereço, ficam na mesma parada, cada documento com a sua tarefa.
Transferência entre filiais#
Envie as siglas das duas filiais. Os documentos são normalmente CT-e (com chave) e o destinatario é a filial de destino, com o CNPJ e o endereço dela.
CHAVE_CTE="3526091122233300018157""0010000123451876543215"
curl -X POST "$BASE/integracao/v1/manifestos" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-H "Idempotency-Key: 0192f3a4-5b6c-7d8e-9f01-23456789abcf" \
-H "Content-Type: application/json" \
-d @- <<JSON
{
"tipo": "TRANSFERENCIA",
"numeroExterno": "TRF-173999",
"motorista": { "cpf": "529.982.247-25", "nome": "Motorista Exemplo da Silva" },
"veiculo": { "placa": "XYZ-9A87" },
"filialOrigemSigla": "CPS",
"filialDestinoSigla": "SJC",
"documentos": [
{
"modelo": 57,
"chave": "$CHAVE_CTE",
"numero": "12345",
"serie": "1",
"destinatario": {
"cnpjCpf": "11222333000181",
"nome": "Transportadora Exemplo - Filial SJC",
"endereco": { "logradouro": "Rodovia Presidente Dutra km 150", "municipio": "São José dos Campos", "uf": "SP" }
},
"nfVinculadas": [
{ "numero": "45678", "serie": "1", "cnpjEmbarcador": "12345678000195" }
],
"volumes": 12,
"peso": 350.5
}
]
}
JSONRepetir o envio sem duplicar: Idempotency-Key#
Se a rede cair ou der tempo esgotado e você não souber se o envio chegou, repita a mesma chamada com a mesma Idempotency-Key. O Veltra guarda a chave por pelo menos 72 horas, separada por transportadora e ambiente.
| Situação | Resultado |
|---|---|
Mesma Idempotency-Key e mesmo corpo | 200 com a resposta original, sem gravar nada de novo. |
Mesma Idempotency-Key com corpo diferente | 409. |
numeroExterno que já existe, com outra Idempotency-Key, num POST | 409. Para alterar, use PUT. |
Gere um valor novo (recomendado: UUID) a cada versão do manifesto que você enviar. Os valores dos exemplos acima são só ilustração: use os seus.
Alterar um manifesto#
Alterar é reenviar o manifesto completo com PUT. O numeroExterno do corpo precisa ser igual ao do caminho, e a Idempotency-Key deve ser nova se o conteúdo mudou. Exemplo: o mesmo manifesto de entrega, com outro peso.
CHAVE_CTE="3526091122233300018157""0010000123451876543215"
curl -X PUT "$BASE/integracao/v1/manifestos/173999" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
-H "Idempotency-Key: 0192f3a4-5b6c-7d8e-9f01-23456789abd0" \
-H "Content-Type: application/json" \
-d @- <<JSON
{
"tipo": "ENTREGA",
"numeroExterno": "173999",
"motorista": { "cpf": "529.982.247-25", "nome": "Motorista Exemplo da Silva" },
"veiculo": { "placa": "ABC-1D23" },
"documentos": [
{
"modelo": 57,
"chave": "$CHAVE_CTE",
"numero": "12345",
"serie": "1",
"destinatario": {
"cnpjCpf": "11444777000161",
"nome": "Mercado Exemplo Ltda",
"endereco": { "logradouro": "Rua das Flores 120", "bairro": "Centro", "municipio": "Campinas", "uf": "SP" }
},
"nfVinculadas": [
{ "numero": "45678", "serie": "1", "cnpjEmbarcador": "12345678000195" }
],
"volumes": 12,
"peso": 360,
"prazoEntrega": "2026-10-02"
}
]
}
JSONResposta esperada: 200, com versaoAtual somada de 1. O que vale saber:
- Documentos novos são acrescentados; documentos que saíram da lista são marcados como removidos. O Veltra guarda o histórico por versão.
- Reenviar exatamente o conteúdo da versão atual não cria versão nova.
- Um documento que já teve baixa ou ocorrência não é removido: o resto da alteração é aplicado e a resposta traz o motivo em
erros[](códigoDOCUMENTO_JA_BAIXADO). Um comprovante nunca some. - Tirar só uma NF de dentro de um CT-e não gera versão e não remove o vínculo já gravado; NF nova dentro de um CT-e existente é acrescentada.
- Trocar motorista, veículo ou ajudantes é permitido. Trocar o tipo do manifesto não (
400). - Manifesto que não existe no ambiente da chave, ou que é de outra transportadora, devolve
404.
Cancelar#
Cancela só o que ainda não foi entregue ou coletado, documento por documento. O que já foi feito permanece, com o comprovante. Os documentos cancelados saem do app do motorista. O corpo é opcional; o motivo (até 500 caracteres) fica registrado na linha do tempo de cada documento cancelado.
curl -X POST "$BASE/integracao/v1/manifestos/173999/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" }'Cancelar de novo um manifesto já cancelado devolve 200 com a mesma situação.
Consultar#
curl "$BASE/integracao/v1/manifestos/173999" \
-H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"
Devolve o manifesto na versão atual, com o status de cada documento. O status é controlado por documento, não pelo manifesto.


Ler as respostas e os erros#
Resposta de sucesso (201 na criação, 200 na alteração, no reenvio idempotente, no cancelamento e na consulta):
| Campo | O que é |
|---|---|
id, numeroExterno, tipo | Identificação do manifesto. |
ambiente | TESTE ou PRODUCAO, conforme a chave usada. |
versaoAtual | 1 na criação; sobe 1 a cada alteração. |
quantidadeParadas, quantidadeDocumentos | Totais do manifesto. |
documentos | Cada documento com seu status (PENDENTE, EM_TRANSPORTE, ENTREGUE, ENTREGUE_PARCIAL, DEVOLVIDO ou CANCELADO). |
erros | Documentos recusados nesta chamada. Ausente ou vazio quando tudo foi aceito. |
Erro num documento não derruba o manifesto. Só aquele documento é recusado, o resto é gravado e a resposta lista o motivo em erros[], com documentoIndex (a posição, começando em 0, na lista documentos que você enviou). Se todos os documentos forem recusados, ou se o erro for no cabeçalho do manifesto (por exemplo, CPF do motorista inválido), o manifesto inteiro é recusado com 400.
Código em erros[] | Quando |
|---|---|
CHAVE_INVALIDA | Chave com tamanho ou dígito verificador errado. |
CHAVE_CTE_OBRIGATORIA | CT-e (modelo 57) sem chave. |
MODELO_INCOMPATIVEL | Modelo diferente do que a chave indica. |
CNPJ_INVALIDO | CNPJ com dígito verificador errado. |
DESTINATARIO_INVALIDO | Destinatário sem CNPJ ou CPF, nome ou endereço. |
DOCUMENTO_JA_BAIXADO | Tentativa de remover um documento que já teve baixa, no PUT. |
OUTRO | Outro motivo; leia o texto em motivo. |
Erros de requisição vêm no formato application/problem+json (RFC 9457), com title, status e detail. Os códigos HTTP:
| Código | Quando |
|---|---|
400 | Dados inválidos no cabeçalho do manifesto, ou nenhum documento aceito. |
401 | Chave ausente, errada ou revogada. |
403 | Chave de Teste tentando criar ou alterar filiais, ou chave de consulta suspensa (CHAVE_SUSPENSA) na configuração de prazo. |
404 | Manifesto não encontrado, ou de outro ambiente, ou de outra transportadora. |
409 | Conflito de idempotência, manifesto já existente ou TESTE_ENCERRADO. |
Prazo de entrega#
O relatório de pontualidade e o alerta de prazo vencido usam o mesmo cálculo de prazo. Pelo contrato, o padrão sugerido é de 72 horas úteis, mas o valor é configurável (de 1 a 720 horas). Contam as horas de segunda a sexta-feira no fuso de São Paulo; feriados nacionais e os locais cadastrados pela transportadora não consomem horas. Depois de somadas as horas, a data vale até o fim do dia.

Você escolhe a data-base da contagem: emissão do CT-e (CTE), emissão da NF-e (NFE) ou chegada do manifesto ao Veltra (CHEGADA_MANIFESTO). Para isso, o documento pode trazer cteEmitidoEm, e cada NF em nfVinculadas pode trazer nfeEmitidoEm; o prazoEntrega do documento continua aceito. Se a data-base escolhida não existir no documento, vale a chegada do manifesto. É possível definir um número de horas diferente por município e UF.
Também há a origem do prazo: TMS_QUANDO_VIER (se o TMS enviar prazoEntrega, ele prevalece) ou SEMPRE_CONFIGURADO (vale sempre o prazo calculado pela configuração).
O TMS pode ler e gravar essa configuração com a mesma chave, em GET e PUT /v1/saida/configuracao-prazo. A mudança vale para as cargas que chegarem depois. Antes de ativar em produção, confirme com a transportadora o calendário local e a regra de prazo.
Roteiro para homologar#
Faça estes passos com a chave de Teste. Só peça a chave de Produção quando todos passarem.
Envie o exemplo de entrega
Use um numeroExterno de teste. Espere 201.
Repita a mesma chamada
Mesmo corpo e mesma Idempotency-Key. Espere 200 e nada duplicado.
Provoque o conflito
Envie o mesmo numeroExterno com outra Idempotency-Key. Espere 409.
Altere com PUT
Mude o peso de um CT-e, ou tire um CT-e da lista, e reenvie com uma Idempotency-Key nova. Espere 200 e confira a nova versão com a consulta. Lembre que tirar só uma NF de dentro de um CT-e não cria versão.
Envie uma chave adulterada
Mude um dígito da chave de um CT-e. Espere erros[] com CHAVE_INVALIDA e o resto do manifesto aceito.
Cancele o manifesto de teste
Use POST .../cancelar. Espere 200.
Passe para produção
Com tudo certo, gere a chave de Produção em Integrações > Chaves de consulta e troque a chave no seu sistema.
Próximo módulo: Webhooks e chaves de acesso. Para consultar cada rota em detalhe, veja a referência da API de entrada.