Webhooks (de saída)

Envie os eventos do FreeMaint para os seus próprios sistemas, em tempo real

4 min de leitura
Imprimir esta seção

Webhooks são a metade «push» das integrações: em vez de o seu sistema ficar consultando o FreeMaint, é o FreeMaint que faz um POST para a sua URL assim que algo acontece. A configuração fica em Configurações da empresa > Webhooks (/company-settings/webhooks). Disponíveis a partir do Starter (100 entregas/dia; ilimitadas a partir do Business).

Eventos disponíveis

  • work_order.created — uma ordem de serviço foi criada
  • work_order.completed — uma ordem de serviço passou para Concluída
  • work_order.status_changed — uma ordem de serviço mudou para qualquer status; o payload traz new_status. Dispara além de work_order.completed, que permanece inalterado
  • request.created — uma solicitação de manutenção foi enviada
  • request.status_changed — uma solicitação foi aprovada, recusada ou cancelada
  • part.low_stock — uma peça chegou ao ponto de ressuprimento ou abaixo dele
  • part.out_of_stock — uma peça chegou a zero
  • part.low_stock_summary — um resumo diário por empresa com as peças no ponto de ressuprimento ou abaixo, inclusive as que nunca se movimentaram
  • part.out_of_stock_summary — o mesmo resumo diário, para as peças zeradas
  • part.consumed — uma peça foi consumida em uma ordem de serviço, ou devolvida
  • compliance.chain_divergence — a cadeia de hash de auditoria foi rompida (Enterprise)
  • asset.downtime_started — uma parada de máquina foi aberta
  • asset.downtime_ended — uma parada de máquina foi encerrada; a duração já pode ser apropriada
  • report.daily_summary — os trabalhos concluídos do dia, uma vez por dia no horário que você escolher
  • purchase_order.created — um pedido de compra foi criado; o payload traz o pedido (reference, status, total_cost, currency, expected_date, erp_reference) e o fornecedor
  • purchase_order.status_changed — um pedido de compra mudou de status (aprovado, pedido, cancelado…); o payload traz previous_status e new_status
  • purchase_order.received — uma entrega de um pedido de compra foi recebida (enviado a cada entrega, inclusive as parciais); o payload lista cada linha com quantity_ordered, quantity_received (esta entrega), quantity_received_total e quantity_remaining, além de receipt_id, fully_received e closed_short; new_status é PARTIALLY_RECEIVED enquanto ainda se esperam mercadorias e RECEIVED quando o pedido está completo ou encerrado

part.consumed — espelhar o estoque em um ERP

É o evento a assinar quando outro sistema (ERP, faturamento, estoque, contabilidade) precisa refletir o que a manutenção realmente consumiu. quantity tem sinal: negativo quando a peça sai para o serviço, positivo quando é devolvida ao removê-la da ordem de serviço — assim um estorno no FreeMaint gera o documento de devolução correspondente do outro lado. stock_movement_id é estável entre novas tentativas e reenvios: use-o como chave de idempotência e você nunca lançará duas vezes a mesma saída. Um ponto a saber quando o tráfego corre nos dois sentidos: a mutação GraphQL adjustStock NÃO dispara esse evento. É intencional — uma correção de estoque que o seu próprio sistema grava no FreeMaint nunca deve voltar para você como eco e ser lançada duas vezes. Só o consumo registrado em uma ordem de serviço dentro do FreeMaint gera part.consumed. A peça também traz custom_reference: o seu próprio código para ela, o customReference definido com createPart ou updatePart, para que um sistema que gerencia o catálogo concilie cada linha sem manter uma tabela de IDs do FreeMaint.

{ "event": "part.consumed", "timestamp": "2026-08-19T21:04:11.000Z", "data": { "part": { "id": 812, "name": "Rolamento 6204", "part_number": "RLM-204", "reference": "PART-812", "custom_reference": "BC-10045", "unit_cost": 12.5, "unit_of_measure": "un" }, "quantity": -2, "previous_quantity": 48, "new_quantity": 46, "work_order": { "id": 5521, "reference": "WO-2026-0412", "title": "Troca de rolamento" }, "asset": { "id": 91, "name": "Desnatadeira 2" }, "location": { "id": 7, "name": "Almoxarifado da planta" }, "user": { "id": 5627, "name": "A. Técnico" }, "stock_movement_id": 88213, "occurred_at": "2026-08-19T21:04:11.000Z" } }

Entrega e assinatura

Cada entrega é um POST com corpo JSON e um cabeçalho X-FreeMaint-Signature no formato t=<segundos unix>,v1=<hex>, onde v1 é o HMAC-SHA256 da string «<t>.<corpo bruto>» usando o segredo do seu webhook como chave. Verifique sobre o corpo BRUTO, antes de qualquer parsing JSON ou reserialização. Também enviamos X-FreeMaint-Event e X-FreeMaint-Delivery-Id. Um 2xx marca a entrega como entregue; erros de rede e 5xx são repetidos até 3 vezes com backoff exponencial (cerca de 2 s, 4 s, 8 s); um 4xx é tratado como recusa definitiva e NÃO é repetido.

Reenviar uma entrega

Cada tentativa fica no histórico de entregas do webhook, com status e código de resposta. Qualquer entrega já finalizada pode ser reenviada de lá: reenvia-se o mesmo payload armazenado, então as chaves de negócio que ele contém (incluindo stock_movement_id) permanecem iguais e um receptor que deduplica corretamente não lança em duplicidade. É assim que se recupera depois de o seu endpoint ter ficado fora do ar ou ter recusado uma requisição por engano.

Fotos (opcional)

Quando "Incluir fotos" está ativado em um webhook (desativado por padrão), os objetos "work_order" e "request" trazem uma lista "photos": até 4 links HTTPS para imagens JPG, PNG, GIF ou WebP, as mais recentes primeiro. Cada link abre a imagem sem login por 7 dias, então guarde o arquivo no seu sistema se precisar dele por mais tempo. Um reenvio manda os mesmos links. Os outros eventos e webhooks não mudam. Para "work_order.created" e "request.created", um webhook com "Incluir fotos" é enviado 90 segundos após o evento (o campo "timestamp" mantém o horário do evento), para incluir as fotos enviadas logo depois do registro.

Requisitos da URL

  • Somente https:// — http simples é recusado
  • Somente porta 443 ou 8443
  • O host precisa ser acessível publicamente — faixas loopback, privadas e CGNAT são recusadas
  • Sem credenciais na URL (https://user:pass@host é recusado)
  • Um sistema que só existe na sua rede interna precisa de um endpoint público ou de um relé (n8n, Make, Zapier) na frente

Limites

  • Starter — 100 entregas/dia por empresa
  • Business — ilimitado
  • Enterprise — ilimitado
  • O contador conta tentativas de entrega: três webhooks assinando o mesmo evento consomem três unidades
  • O contador diário é zerado às 00:00 UTC

Dica

Verifique o cabeçalho X-FreeMaint-Signature em toda requisição, contra o corpo bruto, para que uma chamada forjada não consiga movimentar estoque no seu ERP.

Esta página foi útil?