Webhooks (de saída)

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

4 min de leitura
Imprimir esta secção

Os webhooks são a metade «push» das integrações: em vez de o seu sistema consultar o FreeMaint, é o FreeMaint que faz um POST para o seu URL assim que algo acontece. Configuram-se em Definiçõ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 — foi criada uma ordem de trabalho
  • work_order.completed — uma ordem de trabalho passou a Concluída
  • work_order.status_changed — uma ordem de trabalho mudou para qualquer estado; o payload traz new_status. Dispara além de work_order.completed, que se mantém inalterado
  • request.created — foi submetido um pedido de manutenção
  • request.status_changed — um pedido foi aprovado, recusado ou cancelado
  • part.low_stock — uma peça desceu ao ponto de encomenda ou abaixo
  • 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 encomenda ou abaixo, incluindo as que nunca se movimentaram
  • part.out_of_stock_summary — o mesmo resumo diário, para as peças a zero
  • part.consumed — uma peça foi consumida numa ordem de trabalho, ou devolvida
  • compliance.chain_divergence — a cadeia de hash de auditoria quebrou (Enterprise)
  • asset.downtime_started — foi aberta uma paragem de máquina
  • asset.downtime_ended — foi fechada uma paragem de máquina; a duração já pode ser imputada
  • report.daily_summary — os trabalhos concluídos do dia, uma vez por dia à hora que escolher
  • purchase_order.created — foi criada uma encomenda de compra; a carga útil contém a encomenda (reference, status, total_cost, currency, expected_date, erp_reference) e o fornecedor
  • purchase_order.status_changed — uma encomenda de compra mudou de estado (aprovada, encomendada, cancelada…); a carga útil contém previous_status e new_status
  • purchase_order.received — foi recebida uma entrega de uma nota de encomenda (enviado em cada entrega, incluindo as parciais); a carga útil 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 se espera mercadoria e RECEIVED quando a encomenda está completa ou fechada

part.consumed — espelhar o stock num ERP

É o evento a subscrever quando outro sistema (ERP, faturação, stocks, contabilidade) tem de refletir o que a manutenção consumiu de facto. quantity tem sinal: negativo quando a peça sai para o trabalho, positivo quando é devolvida ao retirá-la da ordem de trabalho — assim um estorno no FreeMaint produz o documento de devolução correspondente do outro lado. stock_movement_id é estável entre tentativas e reenvios: use-o como chave de idempotência e 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 este evento. É intencional — uma correção de existências que o seu próprio sistema escreve no FreeMaint nunca lhe deve voltar como eco e ser lançada duas vezes. Só o consumo registado numa ordem de trabalho dentro do FreeMaint gera part.consumed. A peça inclui também custom_reference: o seu próprio código para ela, o customReference definido com createPart ou updatePart, para que um sistema que gere o catálogo concilie cada linha sem manter uma tabela de identificadores 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": "Substituição de rolamento" }, "asset": { "id": 91, "name": "Desnatadeira 2" }, "location": { "id": 7, "name": "Armazém da fábrica" }, "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>, em que v1 é o HMAC-SHA256 da cadeia «<t>.<corpo em bruto>» com o segredo do seu webhook como chave. Verifique sobre o corpo EM BRUTO, antes de qualquer parsing JSON ou re-serialização. Enviamos também 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 recuo 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 o estado e o código de resposta. Qualquer entrega já concluída pode ser reenviada a partir daí: reenvia-se o mesmo payload guardado, pelo que as chaves de negócio que contém (incluindo stock_movement_id) permanecem iguais e um recetor que deduplica corretamente não lança em duplicado. É assim que se recupera depois de o seu endpoint estar em baixo ou ter recusado um pedido por engano.

Fotografias (opcional)

Quando «Incluir fotografias» está ativo num webhook (desativado por predefinição), os objetos "work_order" e "request" incluem uma lista "photos": até 4 ligações HTTPS para imagens JPG, PNG, GIF ou WebP, as mais recentes primeiro. Cada ligação abre a imagem sem sessão iniciada durante 7 dias, por isso guarde o ficheiro do seu lado se precisar dele por mais tempo. Um reenvio volta a enviar as mesmas ligações. Os outros eventos e webhooks não mudam. Para "work_order.created" e "request.created", um webhook com «Incluir fotografias» é enviado 90 segundos após o evento (o campo "timestamp" mantém a hora do evento), para incluir as fotografias carregadas logo a seguir ao registo.

Requisitos do URL

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

Limites

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

Dica

Verifique o cabeçalho X-FreeMaint-Signature em cada pedido, contra o corpo em bruto, para que uma chamada forjada não possa movimentar stock no seu ERP.

Esta página foi útil?