Outbound Webhook
Eventos de ciclo de vida da Ordem de Serviço entregues em tempo real.
Esta página descreve o modo Webhook (push). Para o modo alternativo, ver Polling.
A DirectLuz notifica o sistema externo em dois ciclos:
- Ciclo do alerta — sempre que uma solicitação inbound é aceita (independentemente de virar OS imediatamente), o sistema externo recebe
Alert.Received. Se o alerta for cancelado antes de virar OS, recebe tambémAlert.Cancelled. - Ciclo da OS — quando o alerta é convertido em Ordem de Serviço, o sistema externo recebe
ServiceOrder.Createde todas as transições subsequentes (StatusChanged,Completed,Cancelled).
Esse desenho garante que o parceiro tem feedback contínuo mesmo nos casos em que a cidade configura triagem manual: ele recebe o Alert.Received imediato confirmando o registro, e só depois (quando a equipe operacional triagear) recebe o ServiceOrder.Created correspondente.
O receptor pode optar por consumir apenas os eventos de interesse via enabledEvents, mas todos são enviados por padrão.
Cadastro do endpoint receptor
O parceiro integrador informa à DirectLuz, no momento do cadastro do sistema externo:
| Parâmetro | Descrição |
|---|---|
webhookUrl | URL HTTPS de produção que receberá os eventos |
webhookSecret | Segredo compartilhado utilizado para a assinatura HMAC-SHA256 |
enabledEvents | Lista de eventos que o parceiro deseja receber (opcional — padrão: todos) |
URL e segredo podem ser atualizados a qualquer momento pelo painel administrativo.
Cabeçalhos enviados pela DirectLuz
| Cabeçalho | Conteúdo |
|---|---|
Content-Type | application/json; charset=utf-8 |
User-Agent | DirectLuz-Webhook/1.0 |
X-Event-Type | Identificador do evento (ex.: ServiceOrder.Completed) |
X-Directluz-Signature | sha256=<hex> — HMAC-SHA256 do corpo cru |
X-Directluz-Tenant | Identificador do tenant emissor |
X-Directluz-Delivery | UUID único por tentativa de entrega (varia entre retries) |
X-Directluz-Event-Id | UUID único do evento (estável entre retries — chave de idempotência no lado receptor) |
Eventos cobertos
| Evento | Gatilho |
|---|---|
Alert.Cancelled | Alerta cancelado antes de virar OS (modo triagem manual, descartado pela operação) |
ServiceOrder.Created | Alerta convertido em Ordem de Serviço (imediato se cidade está em AutoCreate; após triagem em ManualTriage) |
ServiceOrder.StatusChanged | Toda transição de status intermediária (OPEN → IN_PROGRESS, IN_PROGRESS → PAUSED, PAUSED → IN_PROGRESS etc.) |
ServiceOrder.Completed | Ordem de Serviço concluída pela equipe de campo |
ServiceOrder.Cancelled | Ordem de Serviço cancelada antes da execução |
Eventos de Alerta carregam o objeto alert; eventos de OS carregam o objeto serviceOrder. Em ambos os casos, o protocolNumber (protocolo externo enviado originalmente) aparece no nível raiz do evento.
Payload — Alert.Cancelled
{
"eventId": "4c5d6e7f-8a9b-4c1d-9e2f-3a4b5c6d7e8f",
"eventType": "Alert.Cancelled",
"occurredAt": "2026-05-20T17:10:00Z",
"protocolNumber": "EXT-2026-001234",
"alert": {
"id": "f4d2a1b9-3c5e-4a7d-8e1c-9b2f5d6a7c4e",
"alertNumber": 1042,
"assetType": "POLE",
"cancelledAt": "2026-05-20T17:10:00Z",
"reason": "Solicitação duplicada — já registrada no protocolo EXT-2026-001210"
}
}Payload — ServiceOrder.Created
{
"eventId": "f1a3c2e4-5b7d-4c9a-8d3e-2f6a1b9c4d7e",
"eventType": "ServiceOrder.Created",
"occurredAt": "2026-05-20T13:42:05Z",
"protocolNumber": "EXT-2026-001234",
"serviceOrder": {
"id": "8c2b4a1f-3d6e-4b9a-bc2f-5a7d8e1c9b3a",
"internalProtocol": "OS-00042",
"assetType": "POLE",
"status": "OPEN",
"priority": "Medium",
"createdAt": "2026-05-20T13:42:05Z"
}
}Payload — ServiceOrder.StatusChanged
{
"eventId": "9c2d3e1f-4a6b-4d8e-9f1a-3b5c7d8e9f0a",
"eventType": "ServiceOrder.StatusChanged",
"occurredAt": "2026-05-21T09:00:00Z",
"protocolNumber": "EXT-2026-001234",
"serviceOrder": {
"id": "8c2b4a1f-3d6e-4b9a-bc2f-5a7d8e1c9b3a",
"internalProtocol": "OS-00042",
"assetType": "POLE",
"previousStatus": "OPEN",
"status": "IN_PROGRESS",
"changedAt": "2026-05-21T09:00:00Z"
}
}Payload — ServiceOrder.Completed
{
"eventId": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"eventType": "ServiceOrder.Completed",
"occurredAt": "2026-05-21T15:08:42Z",
"protocolNumber": "EXT-2026-001234",
"serviceOrder": {
"id": "8c2b4a1f-3d6e-4b9a-bc2f-5a7d8e1c9b3a",
"internalProtocol": "OS-00042",
"assetType": "POLE",
"status": "COMPLETED",
"result": "Resolved",
"closedAt": "2026-05-21T15:08:00Z",
"slaBreached": false,
"closure": {
"categoryCode": "TROCA_LAMPADA",
"categoryName": "Troca de lâmpada",
"notes": "Lâmpada substituída e relé testado",
"location": {
"latitude": -7.114,
"longitude": -34.831
}
},
"attachments": [
{
"type": "photo",
"kind": "after",
"url": "https://blob.directluz.com.br/tenants/{tenant}/os/00042/depois-1.jpg"
}
]
}
}Payload — ServiceOrder.Cancelled
{
"eventId": "7d8e9f0a-1b2c-4d3e-9f4a-5b6c7d8e9f0a",
"eventType": "ServiceOrder.Cancelled",
"occurredAt": "2026-05-21T10:30:00Z",
"protocolNumber": "EXT-2026-001234",
"serviceOrder": {
"id": "8c2b4a1f-3d6e-4b9a-bc2f-5a7d8e1c9b3a",
"internalProtocol": "OS-00042",
"assetType": "POLE",
"status": "CANCELLED",
"cancelledAt": "2026-05-21T10:30:00Z",
"reason": {
"code": "DUPLICATE_REQUEST",
"description": "Protocolo duplicado — atendimento já vinculado a OS-00038"
}
}
}Reentrega e tratamento de falhas
A DirectLuz considera entregue qualquer resposta 2xx recebida em até 30 segundos.
| Resposta do receptor | Comportamento da DirectLuz |
|---|---|
2xx | Entrega confirmada |
4xx (exceto 408 e 429) | Falha permanente. O evento é marcado como processado com erro e não é reenviado |
408, 429, 5xx | Falha transitória. Reentrega agendada com backoff exponencial |
| Timeout (> 30 s) | Falha transitória. Reentrega agendada com backoff exponencial |
Política de backoff
| Tentativa | Intervalo mínimo até a próxima |
|---|---|
| 1 | 2 minutos |
| 2 | 4 minutos |
| 3 | 8 minutos |
| 4 | 16 minutos |
| 5 | 32 minutos |
| 6 | 64 minutos |
| 7+ | 120 minutos (teto) |
Após 10 tentativas sem sucesso, o evento é movido para a fila interna de mensagens não entregues (DLQ). Reenvios manuais podem ser solicitados via canal de suporte.
Ordenação de eventos
Em cenários de retentativa, é possível que um evento mais recente chegue antes de um evento anterior do mesmo agregado. O receptor deve utilizar occurredAt como referência temporal canônica.
Idempotência no receptor
O cabeçalho X-Directluz-Event-Id (e equivalentemente o campo eventId no corpo) é estável entre tentativas. O receptor deve persistir essa chave e ignorar eventos duplicados.