Pular para o conteúdo
Veltra Ajuda
Manual da APIPlaybookEntrar

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, use POST .../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 devolve 401.
  • Endereço base: o contrato usa http://localhost:8080 para o ambiente local. O endereço do seu ambiente é combinado na entrega das chaves. Nos exemplos abaixo, a variável BASE guarda esse endereço.
  • Cabeçalho Idempotency-Key: obrigatório em todo envio de manifesto (POST e PUT). Veja a seção sobre repetição.

As duas chaves levam a dois ambientes que nunca se misturam:

ChaveO 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 é 409 com o código TESTE_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
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#

CampoObrigatórioRegra
tiposimENTREGA, 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.
numeroExternosimNúmero do manifesto no seu sistema (até 60 caracteres). É único por transportadora e ambiente. No PUT deve ser igual ao do caminho.
motoristasimcpf (11 dígitos, com ou sem máscara, com dígitos verificadores válidos) e nome.
veiculosimplaca, com ou sem hífen.
filialOrigemSigla, filialDestinoSiglasó em TRANSFERENCIASiglas cadastradas no Veltra.
documentossimPelo menos 1 documento.

Em cada documento:

CampoObrigatórioRegra
modelosimNúmero: 57 para CT-e, 55 para NF-e. Envie como número, não como texto.
numerosimNúmero do documento (até 20 caracteres).
chavesim para CT-e44 posições. O Veltra confere o dígito verificador.
cnpjEmbarcadorsó fora do CT-eCNPJ do embarcador, dono da NF. Obrigatório quando o modelo não é 57.
destinatariosimcnpjCpf, nome e endereco (logradouro, municipio e uf são obrigatórios).
nfVinculadaspara CT-eAs NF que o CT-e transporta; cada uma com numero e cnpjEmbarcador.
tarefanãoENTREGA ou COLETA. Omitida: coleta em manifesto de coleta e entrega nos demais tipos.
volumes, peso, prazoEntreganãopeso 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:

curl
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"
    }
  ]
}
JSON

Resposta 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
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.

curl
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
    }
  ]
}
JSON

Repetir 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çãoResultado
Mesma Idempotency-Key e mesmo corpo200 com a resposta original, sem gravar nada de novo.
Mesma Idempotency-Key com corpo diferente409.
numeroExterno que já existe, com outra Idempotency-Key, num POST409. 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.

curl
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"
    }
  ]
}
JSON

Resposta 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ódigo DOCUMENTO_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
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
curl "$BASE/integracao/v1/manifestos/173999" \
  -H "X-Veltra-Api-Key: SUA_CHAVE_AQUI"
Paradas, documentos, fotos e linha do tempo do manifesto.
Paradas, documentos, fotos e linha do tempo do manifesto.

Devolve o manifesto na versão atual, com o status de cada documento. O status é controlado por documento, não pelo manifesto.

Manifesto com uma baixa e uma ocorrência registradas.
Manifesto com uma baixa e uma ocorrência registradas.
Manifestos recebidos pela API, com filtros e situação.
Manifestos recebidos pela API, com filtros e situação.

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):

CampoO que é
id, numeroExterno, tipoIdentificação do manifesto.
ambienteTESTE ou PRODUCAO, conforme a chave usada.
versaoAtual1 na criação; sobe 1 a cada alteração.
quantidadeParadas, quantidadeDocumentosTotais do manifesto.
documentosCada documento com seu status (PENDENTE, EM_TRANSPORTE, ENTREGUE, ENTREGUE_PARCIAL, DEVOLVIDO ou CANCELADO).
errosDocumentos 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_INVALIDAChave com tamanho ou dígito verificador errado.
CHAVE_CTE_OBRIGATORIACT-e (modelo 57) sem chave.
MODELO_INCOMPATIVELModelo diferente do que a chave indica.
CNPJ_INVALIDOCNPJ com dígito verificador errado.
DESTINATARIO_INVALIDODestinatário sem CNPJ ou CPF, nome ou endereço.
DOCUMENTO_JA_BAIXADOTentativa de remover um documento que já teve baixa, no PUT.
OUTROOutro 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ódigoQuando
400Dados inválidos no cabeçalho do manifesto, ou nenhum documento aceito.
401Chave ausente, errada ou revogada.
403Chave de Teste tentando criar ou alterar filiais, ou chave de consulta suspensa (CHAVE_SUSPENSA) na configuração de prazo.
404Manifesto não encontrado, ou de outro ambiente, ou de outra transportadora.
409Conflito 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.

Regras da operação: raio de chegada, quilometragem e recebedor.
Regras da operação: raio de chegada, quilometragem e recebedor.

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.