Início

  • Visão geral
  • Referência da API

Guias

  • Comece em 5 minutos
  • Autenticação
  • Escopos
  • Paginação
  • Erros
  • Idempotência
  • Limites de requisição
  • Webhooks
  • Versionamento
  • Histórico de mudanças
Guia

Webhooks

Receber eventos e verificar a assinatura.

Um webhook é um endereço HTTPS do seu sistema que recebe um POST a cada evento da Conta. Cadastre o endereço e os eventos desejados; a entrega costuma chegar em até um minuto.

O que chega

Requisição
POST /seu/endereco HTTP/1.1
Content-Type: application/json
User-Agent: FrotaSimples-Webhooks/1
FrotaSimples-Evento-Id: evt_00000000-0000-4000-8000-000000000000
FrotaSimples-Evento-Tipo: veiculo.criado
FrotaSimples-Assinatura: t=1792540800,v1=da6a...6240

{
  "id": "evt_00000000-0000-4000-8000-000000000000",
  "tipo": "veiculo.criado",
  "versao": 1,
  "criadoEm": "2026-10-20T12:00:00.000Z",
  "conta": { "id": 123 },
  "dados": { ... }
}

dados é a mesma representação que a API devolve para o recurso — o mesmo formato da leitura na referência.

Verifique a assinatura

O cabeçalho FrotaSimples-Assinatura traz t (instante do envio, em segundos) e v1, o HMAC-SHA256 em hexadecimal de t + "." + corpo, com o segredo whsec_… mostrado ao criar o webhook. Calcule sobre o corpo cru, antes de converter o JSON; compare em tempo constante; e recuse t com mais de 5 minutos de diferença do seu relógio, para que uma entrega capturada não possa ser reenviada depois.

Node.js
import { createHmac, timingSafeEqual } from 'node:crypto'

const TOLERANCIA_S = 300 // 5 minutos

/**
 * corpoCru: o texto exato recebido (antes do JSON.parse).
 * cabecalho: o valor de FrotaSimples-Assinatura.
 * segredo: o whsec_... mostrado ao criar o webhook.
 */
export function assinaturaValida(corpoCru, cabecalho, segredo, agora = Date.now() / 1000) {
  const partes = Object.fromEntries(
    String(cabecalho || '').split(',').map((p) => p.trim().split('='))
  )
  const t = Number(partes.t)
  if (!Number.isFinite(t) || !partes.v1) return false
  if (Math.abs(agora - t) > TOLERANCIA_S) return false

  const esperado = createHmac('sha256', segredo).update(t + '.' + corpoCru).digest('hex')
  const recebido = Buffer.from(partes.v1, 'hex')
  const calculado = Buffer.from(esperado, 'hex')
  return recebido.length === calculado.length && timingSafeEqual(recebido, calculado)
}

// Express: use express.raw({ type: 'application/json' }) para ter o corpo cru.
// app.post('/webhooks/frotasimples', express.raw({ type: 'application/json' }), (req, res) => {
//   if (!assinaturaValida(req.body.toString('utf8'), req.get('FrotaSimples-Assinatura'), process.env.FS_WEBHOOK_SEGREDO)) {
//     return res.sendStatus(400)
//   }
//   const evento = JSON.parse(req.body)
//   res.sendStatus(200) // responda rápido; processe em segundo plano
// })
Python
import hashlib
import hmac
import time

TOLERANCIA_S = 300  # 5 minutos


def assinatura_valida(corpo_cru: bytes, cabecalho: str, segredo: str, agora: float | None = None) -> bool:
    """corpo_cru: os bytes exatos recebidos (request.get_data() no Flask)."""
    partes = dict(p.strip().split("=", 1) for p in (cabecalho or "").split(",") if "=" in p)
    try:
        t = int(partes["t"])
        recebido = partes["v1"]
    except (KeyError, ValueError):
        return False
    if abs((agora or time.time()) - t) > TOLERANCIA_S:
        return False

    mensagem = f"{t}.".encode() + corpo_cru
    esperado = hmac.new(segredo.encode(), mensagem, hashlib.sha256).hexdigest()
    return hmac.compare_digest(esperado, recebido)
PHP
<?php
const TOLERANCIA_S = 300; // 5 minutos

function assinatura_valida(string $corpoCru, string $cabecalho, string $segredo, ?int $agora = null): bool
{
    $partes = [];
    foreach (explode(',', $cabecalho) as $parte) {
        [$chave, $valor] = array_pad(explode('=', trim($parte), 2), 2, null);
        $partes[$chave] = $valor;
    }
    if (!isset($partes['t'], $partes['v1']) || !ctype_digit($partes['t'])) {
        return false;
    }
    $t = (int) $partes['t'];
    if (abs(($agora ?? time()) - $t) > TOLERANCIA_S) {
        return false;
    }

    $esperado = hash_hmac('sha256', $t . '.' . $corpoCru, $segredo);
    return hash_equals($esperado, $partes['v1']);
}

// $corpoCru = file_get_contents('php://input');
// $cabecalho = $_SERVER['HTTP_FROTASIMPLES_ASSINATURA'] ?? '';

Vetor de teste

Rode a sua implementação contra estes valores (ignorando a janela de 5 minutos) antes do primeiro evento real:

Vetor
{
  "segredo": "whsec_exemplo0000000000000000000000",
  "cabecalho": "t=1792540800,v1=da6afd89a62d0dc763c7e21f66df663138cc61d8ae52befdede00336dcc96240",
  "corpo": "{\"id\":\"evt_00000000-0000-4000-8000-000000000000\",\"tipo\":\"veiculo.criado\",\"versao\":1,\"criadoEm\":\"2026-10-20T12:00:00.000Z\",\"conta\":{\"id\":123},\"dados\":{\"id\":\"veh_exemplo\",\"placa\":\"ABC1D23\"}}"
}

Responda rápido e processe uma vez

  • Responda 2xx em até 10 segundos e processe depois, em segundo plano. Redirecionamento conta como falha.
  • A mesma entrega pode chegar mais de uma vez. Guarde o FrotaSimples-Evento-Id já processado e ignore repetições.
  • A ordem de chegada não é garantida; use criadoEm para ordenar.

Retentativas

Sem 2xx, a entrega é repetida 8 vezes (9 tentativas no total), com estas esperas:

TentativaEspera depois da anteriorDesde a primeira
2ª1 min1 min
3ª5 min6 min
4ª15 min21 min
5ª1 h1 h 21 min
6ª3 h4 h 21 min
7ª6 h10 h 21 min
8ª12 h22 h 21 min
9ª24 h46 h 21 min

Um endereço que passa 3 dias falhando, sem nenhuma entrega bem-sucedida, é desativado e o Proprietário da Conta recebe um e-mail. Depois de corrigir, reative o webhook na tela de Integrações.

Catálogo de eventos

Para receber um evento, a chave e o webhook precisam do escopo de leitura do recurso.

EventoQuandoEscopoVersão
veiculo.criadoVeículo cadastrado na Conta.veiculos:ler1
veiculo.atualizadoDados de um veículo alterados.veiculos:ler1
veiculo.excluidoVeículo removido da Conta.veiculos:ler1
motorista.criadoMotorista cadastrado.motoristas:ler1
motorista.atualizadoDados de um motorista alterados.motoristas:ler1
motorista.excluidoMotorista removido.motoristas:ler1
documento.criadoDocumento enviado.documentos:ler1
documento.atualizadoDocumento alterado.documentos:ler1
documento.excluidoDocumento removido.documentos:ler1
documento.vencendoDocumento entrou na janela de vencimento.documentos:ler1
multa.criadaMulta registrada.multas:ler1
multa.atualizadaMulta alterada (situação, prazo, valor).multas:ler1
multa.excluidaMulta removida.multas:ler1
lancamento.criadoLançamento financeiro criado.financeiro:ler1
lancamento.atualizadoLançamento financeiro alterado.financeiro:ler1
lancamento.excluidoLançamento financeiro removido.financeiro:ler1
fiscal.autorizadoCT-e/MDF-e/CIOT autorizado.fiscal:ler1
fiscal.canceladoDocumento fiscal cancelado.fiscal:ler1
fiscal.encerradoMDF-e encerrado.fiscal:ler1
cliente.criadoCliente do Atendimento criado.clientes:ler1
cliente.atualizadoCliente do Atendimento alterado.clientes:ler1
cliente.excluidoCliente do Atendimento removido.clientes:ler1
contato.criadoContato do Atendimento criado.contatos:ler1
contato.atualizadoContato do Atendimento alterado.contatos:ler1
contato.excluidoContato do Atendimento removido.contatos:ler1
processo.status_alteradoProcesso ANTT mudou de situação. Gerado por gatilho no banco (0167).processos:ler1
carteira.saldo_alteradoSaldo da carteira de consultas mudou (compra, consumo, estorno).carteira:ler1
motorista.documento_vencendoCNH, exame toxicológico ou curso MOPP de um motorista entrou na janela de vencimento.motoristas:ler1
fiscal.rejeitadoCT-e/MDF-e rejeitado ou denegado pela SEFAZ (o motivo vem em `motivoRejeicao`).fiscal:ler1
cliente.arquivadoCliente do Atendimento arquivado.clientes:ler1
cliente.mescladoDois clientes viraram um: `dados.sobrevivente` fica, `dados.absorvidoId` deixou de existir.clientes:ler1
contato.mescladoDuas fichas de contato viraram uma: `dados.sobrevivente` fica, `dados.absorvidoId` deixou de existir.contatos:ler1
Frota Simples

Empresa privada de tecnologia para gestão de frota. Veículos, documentos, multas e a burocracia com os órgãos em um só painel.

Serviços

  • Conheça a plataforma
  • Gestão de frota
  • Integrações
  • Gestão de Multas
  • Consultas
  • Cadastro ANTT
  • Renovação ANTT
  • Inclusão de Veículos
  • Alteração Cadastral

Suporte

  • Perguntas Frequentes
  • Status do Sistema
  • Desenvolvedores

Contato

  • [email protected]E-mail oficial
© 2026 — Todos os direitos reservados.
Política de PrivacidadeTermos de UsoAcessibilidadeCancelamento e Reembolso