Pular para o conteúdo
Veltra Ajuda
Manual da APIPlaybookEntrar

Trilha · Módulo 5

Webhooks e chaves de acesso

Webhooks e chaves de acesso

Este módulo é para quem integra o sistema da transportadora (TMS), de um embarcador ou de um destinatário ao Veltra, para ler o que foi registrado (baixas, ocorrências, comprovantes) e ser avisado quando algo acontece. Para enviar manifestos, veja o módulo 4, "Manifestos pela API".

As listas completas de rotas, campos e eventos ficam nas referências geradas do contrato: referência de leitura e referência de webhooks. Aqui você aprende o caminho, na ordem em que se usa.

Tipos de chave e o que cada uma enxerga#

Toda leitura usa uma chave de API no cabeçalho X-Veltra-Api-Key. A chave é emitida pela transportadora, pertence a um ambiente (Teste ou Produção) e só enxerga dados desse ambiente. Cada chave tem uma finalidade:

Embarcadores cadastrados e seus acessos.
Embarcadores cadastrados e seus acessos.
FinalidadePara quemO que enxerga
INTEGRACAO_TMSo TMS da transportadoratodos os eventos e documentos da transportadora, manifestos, PDF, pacote e XML do evento 110180, e a posição dos veículos (posicao.lote)
CONSULTA_EMBARCADORum embarcadorsó os documentos das raízes de CNPJ cadastradas na chave; não vê manifestos, PDF, pacote, XML nem posição
CONSULTA_DESTINATARIOum destinatário pessoa jurídicasó os documentos das raízes de CNPJ cadastradas na chave; não vê manifestos, PDF, pacote, XML nem posição

Pontos que costumam gerar dúvida:

  • A raiz do CNPJ é o início de 8 caracteres, o que cobre matriz e filiais. CPF não entra no escopo da chave, por causa da LGPD; destinatário pessoa física acompanha pelo link sem login.
  • Uma chave de consulta que pede algo fora das suas raízes recebe 404, como se o documento não existisse. Rotas só do TMS respondem 403 para as outras finalidades.
  • As chaves de consulta só leem; não gravam nada.
  • A chave que a transportadora emite em Chaves de API (/chaves-api) é a do TMS, com a finalidade INTEGRACAO_TMS. Ela serve para enviar manifestos e também para ler a API de saída.
  • Existe ainda a finalidade ENTRADA_TRANSPORTADORA, prevista para o embarcador que contrata o Veltra como cliente próprio e recebe os dados das transportadoras parceiras. Ela não lê a API de saída, e esse caminho ainda está em decisão (ADR 0014), então não conte com ele agora.

Emitir, listar e revogar chaves#

Emita a chave do TMS no portal

Um administrador entra em Chaves de API (/chaves-api), informa o nome (por exemplo, "TMS produção") e escolhe o ambiente. A chave de Produção só pode ser emitida quando a transportadora está ativa; em homologação, o portal avisa que não é possível.

Formulário para gerar uma chave de API do TMS, escolhendo o ambiente.
Formulário para gerar uma chave de API do TMS, escolhendo o ambiente.

Copie a chave na hora

O valor completo aparece uma única vez, na criação. Depois só o prefixo fica visível. Guarde o valor em um cofre de segredos, nunca no código nem em log. Se perder, revogue e emita outra.

Lista de chaves de API; só o início da chave aparece, nunca o valor completo.
Lista de chaves de API; só o início da chave aparece, nunca o valor completo.

Revogue quando precisar

Na mesma tela, o administrador revoga a chave. O sistema que a usa perde o acesso.

Por API, o mesmo caminho é feito por /v1/api-keys: POST emite, GET lista (só o prefixo, nunca o valor, inclusive as revogadas) e DELETE /v1/api-keys/{id} revoga. Esse cadastro usa o login do portal, não a chave de API. Para testar se a sua chave está certa, chame GET /v1/api-keys/atual: ela devolve a transportadora e o ambiente da chave que fez a chamada.

curl
curl -H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
  https://SEU_ENDERECO_AQUI/v1/api-keys/atual

Chaves de consulta para embarcador e destinatário#

As chaves de consulta são emitidas pelo administrador, pela API do portal em /v1/integracoes/chaves. Para CONSULTA_EMBARCADOR e CONSULTA_DESTINATARIO é obrigatório informar:

  • o nome da chave;
  • as raízes de CNPJ (escopoCnpjs, 8 caracteres cada, ao menos uma);
  • a data de expiração (expiraEm);
  • o limite de chamadas por minuto (limitePorMinuto, de 1 a 600).

O valor da chave também aparece uma única vez. A revogação, em /v1/integracoes/chaves/{id}/revogacao, tem efeito imediato.

A chave de consulta de Produção faz parte de um módulo habilitado na conta. Se o módulo não estiver contratado, a emissão responde 409 com o código MODULO_NAO_HABILITADO no campo codigo. Se o módulo for desligado depois, as chaves já emitidas não são revogadas: elas ficam suspensas (403 com o código CHAVE_SUSPENSA) e voltam a funcionar quando o módulo for contratado de novo. O custo desse módulo é explicado no módulo 7, "Plano e pagamento", sem valores neste texto.

Ler eventos e documentos#

Estas são as rotas de leitura (/v1/saida). Elas são descritas na referência de leitura:

RotaPara que serve
GET /v1/saida/eventoslista de eventos, com cursor
GET /v1/saida/documentos/{id}situação de um documento
GET /v1/saida/manifestos e /v1/saida/manifestos/{id}manifestos (só TMS)
GET /v1/saida/comprovantes/{id}/pdfPDF do comprovante (só TMS)
GET /v1/saida/comprovantes/{id}/pacotepacote ZIP de evidências (TMS)
GET /v1/saida/eventos-cte/{id}/xmlXML do evento 110180 do CT-e (TMS)
GET /v1/saida/openapi/{finalidade}OpenAPI filtrado para a finalidade da sua chave

Leitura incremental com alteradoDesde#

Primeira leitura

Chame GET /v1/saida/eventos sem alteradoDesde. O parâmetro limite vai de 1 a 200 e, por padrão, é 50.

curl
curl -H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
  "https://SEU_ENDERECO_AQUI/v1/saida/eventos?limite=50"

Guarde o cursor

A resposta traz itens (os eventos, no mesmo envelope dos webhooks) e proximoCursor. Processe os itens e guarde o proximoCursor.

Continue de onde parou

Na próxima rodada, mande o cursor guardado em alteradoDesde.

curl
curl -H "X-Veltra-Api-Key: SUA_CHAVE_AQUI" \
  "https://SEU_ENDERECO_AQUI/v1/saida/eventos?alteradoDesde=CURSOR_GUARDADO_AQUI"

Regras que evitam surpresa:

  • O cursor é opaco: não monte nem edite.
  • O Veltra só devolve eventos alterados há pelo menos 5 segundos. Por isso um evento recém-registrado 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. Trate pelo id do evento: processar duas vezes deve dar o mesmo resultado.
  • As chaves de consulta não recebem o tipo posicao.lote.

PDF, pacote e XML do evento 110180#

Baixe o PDF e o pacote pelo comprovanteId que vem em dados do evento comprovante.emitido. O PDF só leva a assinatura ICP-Brasil quando a transportadora ativou a validação opcional, como explica o módulo 6. Para provar que o arquivo não mudou, confira o código SHA-256 dele. O pacote ZIP reúne o PDF, o manifesto da evidência e os arquivos de apoio.

Chaves de consulta (embarcador ou destinatário) não baixam PDF, pacote nem XML pela API de saída: a resposta é 403.

O XML do evento 110180 só existe quando o perfil da transportadora o gera; sem ele, a resposta é 404. O Veltra não transmite esse evento à SEFAZ: o XML é entregue ao TMS para uso dele. O Veltra também não transmite o evento 110190 (insucesso).

OpenAPI da sua finalidade#

GET /v1/saida/openapi/{finalidade} devolve, em YAML, o OpenAPI com só as rotas que a sua chave pode chamar. Use-o para gerar o cliente. Uma chave de consulta só obtém o OpenAPI da sua própria finalidade; pedir o de outra resulta em 403.

Erros#

As respostas de erro seguem application/problem+json (RFC 9457). Os mais comuns:

CódigoSignificado
400cursor ou limite inválido
401chave ausente ou inválida
403finalidade sem permissão para a rota, ou chave suspensa
404não encontrado ou fora do escopo da chave
429limite de chamadas por minuto da chave excedido (quando a chave tem limite); respeite o cabeçalho Retry-After

Receber webhooks#

O que é e por que usar#

Um webhook é um aviso automático. Pense em pedir à portaria: "me ligue quando o meu pacote chegar", em vez de ir lá de hora em hora perguntar. Quando algo acontece (uma baixa, uma ocorrência, um comprovante), o Veltra faz um POST HTTP para um endereço do sistema que você cadastrar, com os dados do fato.

Comparado a consultar de tempos em tempos, o webhook avisa em poucos segundos e não gasta chamadas à toa. Por segurança, use os dois: o webhook para a velocidade e a leitura incremental (alteradoDesde, descrita acima) para conferir se nada ficou para trás. A assinatura segue o formato Standard Webhooks, conforme o ADR 0022. O guia técnico completo, com todos os eventos, exemplos de corpo e código de verificação em cinco linguagens, está na referência de webhooks. Este módulo é o passo a passo na tela.

Cadastrar o endereço e guardar o segredo#

Só um administrador cadastra webhooks. A tela fica em Integrações > Webhooks (/integracoes/webhooks).

Peça ao desenvolvedor o endereço

Ele precisa de um endereço público que comece com https:// (por exemplo, https://SEU_ENDERECO_AQUI/webhooks/veltra) e que responda rápido. Endereços internos (de rede privada) são recusados.

Clique em Criar webhook e preencha

  • Nome do assinante: um nome que diga quem recebe, como "TMS da matriz".
  • Quem recebe: "Sistema da transportadora (TMS)" ou "Terceiro (embarcador, cliente)". O terceiro precisa das raízes de CNPJ e não recebe PDF nem canhoto, a menos que seja o tomador do documento.
  • URL de destino: o endereço do passo 1.
  • Eventos: marque só o que o sistema vai usar. As posições dos veículos (posicao.lote) aparecem só para o TMS, em lotes por veículo, no campo "Enviar posição a cada" (5, 10 ou 15 minutos).
  • E-mail de contato técnico: use uma caixa que alguém lê. É por ele que o Veltra avisa se o webhook for desativado.

Guarde o segredo agora

Ao salvar, aparece a janela "Guarde o segredo agora". O segredo aparece uma única vez. Clique em "Copiar segredo", guarde em um cofre de segredos (nunca no código nem em mensagem de e-mail ou chat), marque "Já guardei o segredo" e clique em "Concluir". Se perder, use "Girar segredo".

Entregue o segredo ao desenvolvedor, de forma segura

O segredo parece com whsec_ seguido de um texto. O desenvolvedor usa o segredo inteiro para conferir que cada aviso veio mesmo do Veltra (próxima seção).

Clique em Enviar teste

Veja a seção "Testar". Se o teste voltar com sucesso, o webhook está pronto.

Os eventos disponíveis são 8: parada.chegada, parada.saida, baixa.registrada, ocorrencia.registrada, comprovante.emitido, evento_cte.estado_alterado, posicao.lote e veiculo.km_registrado (km do veículo, só para o assinante TMS). A referência traz o formato de cada um. Eventos de Teste nunca chegam a webhooks de Produção, e vice-versa.

O mesmo cadastro existe na API do portal, para quem prefere automatizar: /v1/integracoes/webhooks (lista e criação) e /v1/integracoes/webhooks/{id} (ver, editar, excluir).

O que chega ao sistema#

Cada aviso traz três cabeçalhos:

CabeçalhoConteúdo
webhook-ididentificador da entrega; é o mesmo em todas as retentativas dela
webhook-timestampsegundos Unix; muda a cada tentativa
webhook-signaturev1, seguido do HMAC-SHA256 em Base64; durante a rotação do segredo, duas assinaturas separadas por espaço

O corpo é JSON no envelope { id, tipo, versao, ocorridoEm, ambiente, dados }. Os campos de dados de cada tipo, com um exemplo completo, estão na referência de webhooks.

Verificar a assinatura#

Sempre verifique antes de processar. Sem isso, qualquer pessoa que descubra o endereço poderia enviar eventos falsos. Esta parte é do desenvolvedor; aqui está o resumo para você conferir se ele fez:

Ler o corpo exatamente como chegou

Os bytes crus da requisição, sem fazer parse e serializar de novo: qualquer espaço a mais muda a assinatura.

Conferir o relógio

Recusar se webhook-timestamp estiver a mais de 5 minutos do relógio do servidor, para trás ou para a frente.

Montar a string assinada

webhook-id, um ponto, webhook-timestamp, um ponto e o corpo (bytes UTF-8).

Calcular o HMAC-SHA256

Com o segredo: tirar o prefixo whsec_ e decodificar o Base64 para obter os bytes da chave.

Comparar em tempo constante

Com cada assinatura v1 do cabeçalho webhook-signature, usando a função de comparação em tempo constante da linguagem (nunca ==).

Recusar se nenhuma conferir

Responder 401 e não processar. Cuidado: o Veltra não tenta de novo um 401, então um segredo errado joga os eventos na fila de falhas.

O código pronto, em Node.js, Python, Java, PHP e C#, está na seção 5 da referência de webhooks. Os segredos de teste devem ser sempre o seu (SEU_SEGREDO_AQUI), nunca um valor copiado de outro lugar.

O que o endereço deve responder#

O endereço deve responder 2xx em poucos segundos e processar depois. O Veltra espera até 5 segundos para conectar e 10 para a resposta.

RespostaResultado
2xxentregue
429, 5xx, sem resposta, demora, certificado inválidofalha temporária: tenta de novo mais tarde
410a entrega esgota na hora e o webhook fica Pausado
3xx (redirecionamento) ou outro 4xxfalha definitiva: sem nova tentativa, vai direto para a fila de falhas

Para "tente de novo mais tarde", o sistema deve responder 503, nunca 400.

Quando falha: tentativas e fila de falhas#

Nas falhas temporárias, o Veltra tenta de novo com estes intervalos: 1 minuto, 5 minutos, 30 minutos, 2 horas, 12 horas e depois 12 horas (cada um com variação de 80% a 120%). Se a resposta trouxer Retry-After maior que o intervalo, vale o Retry-After (no máximo 72 horas). Passadas 72 horas desde a primeira tentativa (cerca de 10 tentativas), a entrega vira "Tentativas esgotadas" e vai para a fila de falhas. Nada é apagado.

Duas travas automáticas:

  • Resposta 410 pausa o webhook.
  • 20 entregas esgotadas seguidas deixam o webhook Desativado automaticamente, e o Veltra envia um e-mail ao contato técnico. Um webhook desativado não volta com "Retomar": crie outro.

Corrija a causa

Veja o código HTTP do histórico, conserte o endereço, o segredo ou o servidor.

Abra a aba Fila de falhas

Na página do webhook, a aba Fila de falhas lista só as entregas esgotadas.

Clique em Reenviar

Use Reenviar em uma entrega, ou Reenviar todas (N) no topo. O reenvio usa o mesmo webhook-id e o mesmo corpo, e a janela de 72 horas recomeça. Pela API: POST /v1/integracoes/webhooks/{id}/entregas/{entregaId}/reenvio, que responde 202.

Repetição e ordem#

Como pode haver repetição (por exemplo, a resposta 2xx se perdeu na rede), o sistema deve tratar pelo webhook-id: se já processou, responder 2xx sem refazer. A ordem não é garantida: use o ocorridoEm do corpo para saber qual fato é mais recente. Nunca assuma que a baixa chega antes do comprovante.

Girar o segredo sem perder eventos#

Clique em Girar segredo

Na página do webhook, Girar segredo e confirme. Pela API: POST /v1/integracoes/webhooks/{id}/rotacao-segredo. O novo segredo aparece uma única vez: guarde-o.

Troque o segredo no sistema em até 24 horas

Durante 24 horas, cada entrega leva duas assinaturas no webhook-signature: a do segredo novo e a do anterior, separadas por espaço. O código de verificação da referência aceita qualquer uma das duas, então nada é perdido enquanto o desenvolvedor troca.

Depois das 24 horas

Só o segredo novo vale. Evite girar duas vezes seguidas: o segredo do primeiro giro deixa de valer na hora.

Testar#

Na página do webhook, clique em Enviar teste. O resultado aparece na tela, como "Teste entregue: o assinante respondeu 200 em 120 ms" ou "O teste falhou" com o motivo. O evento de teste tem o tipo webhook.teste e "ambiente": "TESTE", é assinado como uma entrega real e vai ao endereço do próprio webhook; não aparece no histórico de entregas. Se o endereço for interno, o teste falha com o motivo ENDERECO_RECUSADO. Pela API: POST /v1/integracoes/webhooks/{id}/teste.

Para o desenvolvedor trabalhar na própria máquina, a referência explica como usar um túnel (Cloudflare Tunnel, ngrok ou localtunnel) e traz um roteiro com curl e openssl para assinar uma chamada de teste sem depender do Veltra.

Acompanhar, pausar e excluir#

Em Integrações > Webhooks você vê, para cada webhook, o nome, a URL, os eventos, a situação e a última entrega:

  • Ativo: recebendo.
  • Pausado: você pausou, ou o endereço respondeu 410. Nenhuma entrega sai enquanto estiver pausado; os eventos desse período não são apagados e são distribuídos depois do Retomar, sem garantia de ordem. Confira pela leitura incremental se nada ficou para trás.
  • Desativado automaticamente: por 20 entregas esgotadas seguidas.

A aba Histórico de entregas mostra, por entrega, o horário, o evento, o ID da entrega (o identificador da entrega no Veltra, com botão de copiar, e não o cabeçalho webhook-id), a situação (Entregue, Aguardando nova tentativa, Falhou, Teste ou Tentativas esgotadas), o código HTTP, o número de tentativas e a duração. As ações são Enviar teste, Pausar e Retomar (.../pausa e .../retomada na API), Editar, Girar segredo, Reenviar e Excluir. Excluir desativa o webhook: ele deixa de receber eventos.

Se algo der errado#

SintomaCausa provávelO que fazer
Todas as entregas "Tentativas esgotadas" com código 401segredo errado no sistema, ou corpo alterado antes de verificarconfirmar o segredo, ler o corpo cru e usar Reenviar todas
Entregas esgotadas com 404 ou 400rota errada; 4xx não é retentadocorrigir a rota e usar Reenviar
Webhook "Pausado" sem ninguém ter pausadoo endereço respondeu 410corrigir o endereço e usar Retomar
Webhook "Desativado automaticamente"20 entregas esgotadas seguidascorrigir a causa e criar um novo webhook
Muitas entregas "Falhou" sem códigoo servidor não responde em 10 segundos, DNS ou certificado inválidoresponder rápido e processar depois
O mesmo evento duas vezesnormal: repetiçãotratar pelo webhook-id
Recusa depois de girar o segredosistema ainda com o segredo antigo depois de 24 horasatualizar para o segredo mais novo

Mais causas e correções estão na seção 13 da referência de webhooks.

Webhook e consulta, juntos#

Pelo princípio de paridade do ADR 0013, o que o portal mostra também existe na leitura pela API e nos eventos de webhook, no mesmo envelope e com o mesmo id. Receba pelo webhook, trate pelo webhook-id e, a cada hora ou a cada dia, leia GET /v1/saida/eventos?alteradoDesde=CURSOR_GUARDADO_AQUI para recuperar o que possa ter se perdido. O webhook leva só identificadores; para o PDF, o pacote ou o XML do evento 110180, use a leitura.

Boas práticas de segurança#

  • Guarde chaves e segredos em cofre; nunca em repositório, código ou log.
  • Use uma chave por sistema e por ambiente, com nome que identifique quem a usa; assim a revogação é cirúrgica.
  • Para consulta de terceiros, dê a menor abrangência possível: poucas raízes de CNPJ, expiração curta e limite de chamadas baixo.
  • Verifique sempre a assinatura do webhook e o relógio antes de processar, e deduplique pelo webhook-id.
  • Guarde o segredo do webhook em cofre, gire-o periodicamente e mantenha o e-mail de contato técnico em uma caixa que alguém lê.
  • Os dados de motoristas, destinatários e localização que passam por essas integrações são dados pessoais; trate-os conforme a LGPD nos seus sistemas.