DirectLuzDirectLuzDocs
Ordens de Serviço

Inbound API

Registrar solicitações no DirectLuz vindas de sistemas externos.

Endpoint

POST /api/external/service-orders

URL completa em produção: https://app-directluz-v2-backend-prod.azurewebsites.net/api/api/external/service-orders

Cada solicitação recebida vira um Alerta no DirectLuz. Dependendo da política da cidade, esse alerta pode virar uma Ordem de Serviço (OS) imediatamente ou aguardar triagem manual da equipe operacional. O sistema externo sempre recebe 201 quando o alerta é aceito — a existência (ou não) de OS é refletida na resposta.

Cabeçalhos

CabeçalhoObrigatórioDescrição
Content-TypeSimapplication/json
X-Api-KeySimChave de API emitida pela DirectLuz
Idempotency-KeyRecomendadoUUID v4 único por solicitação. Permite reentrega segura
Accept-LanguageNãopt-BR por padrão

Estrutura do payload

CampoTipoObrigatórioDescrição
protocolNumberstringSimIdentificador único da solicitação no sistema externo. Reenvios com o mesmo protocolNumber atualizam o alerta existente em vez de duplicar
assetTypestring (enum)SimTipo de ativo sobre o qual a OS atuará. Valor aceito nesta versão: POLE. Requisições com valor não reconhecido recebem 422
requestedAtstring (ISO 8601)SimData e hora em que a solicitação foi registrada na origem
requesterobjectSimDados do solicitante
requester.namestringSimNome do solicitante
requester.phonestring (E.164)NãoTelefone ou WhatsApp de contato
lampTypestringNãoTipo de lâmpada relatado (ex.: LED, Sodio, VaporDeMercurio). Aplicável quando assetType = POLE
reasonCodestringNãoCódigo do motivo do alerta no sistema do parceiro. O DirectLuz mantém uma tabela de tradução por parceiro (DE/PARA) para mapear esse código ao motivo interno apropriado. Se vier ausente, vazio ou desconhecido, o alerta é criado com o motivo padrão EXTERNAL_OTHER (prioridade Média, SLA 24h) e o operador classifica na triagem
addressobjectSimLocalização da solicitação. Pode conter desde um único campo até o conjunto completo
address.streetstringSimLogradouro. Único campo de endereço obrigatório
address.numberstringNãoNúmero da residência mais próxima. Aceita S/N ou variantes
address.neighborhoodstringNãoBairro
address.referencestringNãoPonto de referência informado pelo cidadão
address.latitudenumberNãoLatitude WGS-84. Quando ausente, a DirectLuz realiza geocodificação a partir dos demais campos
address.longitudenumberNãoLongitude WGS-84. Quando ausente, a DirectLuz realiza geocodificação a partir dos demais campos
problemobjectSimDescrição do problema
problem.descriptionstringSimTexto descrevendo o problema reportado
problem.additionalNotesstringNãoObservação adicional
attachmentsarrayNãoLista de anexos (fotografias do logradouro/ativo). Ver seção de Anexos

Sobre o motivo do alerta (reasonCode)

O parceiro envia o código que ele já usa internamente (ex.: LAMP_OUT, POLE_DAMAGED). A operação da cidade cadastra no painel administrativo um mapeamento DE/PARA entre esses códigos e os motivos internos do DirectLuz — assim, o parceiro não precisa conhecer ou conformar-se à taxonomia interna. Quando um código novo (ainda não mapeado) chega, o alerta é criado com o motivo padrão EXTERNAL_OTHER para não bloquear a integração; o operador pode reclassificar manualmente e o administrador cadastra o mapeamento para os próximos.

Sobre o nível de detalhe do endereço

O sistema externo recebe solicitações de cidadãos com nível de detalhe variável. A DirectLuz aceita ambos os extremos: o único campo de endereço obrigatório é address.street.

Sobre coordenadas geográficas

Quando o payload não contém address.latitude e address.longitude, a DirectLuz realiza geocodificação interna a partir dos campos textuais. Se a geocodificação falhar (provider indisponível, endereço ambíguo), a solicitação continua sendo aceita (201) — o alerta fica visível na caixa de entrada operacional do DirectLuz com a marcação "endereço não geolocalizado", e um operador resolve manualmente, ou um job periódico re-tenta a geocodificação automaticamente. O sistema externo não precisa fazer nada diferente nesse cenário.

Exemplo de requisição — payload completo

POST /api/external/service-orders HTTP/1.1
Host: api.directluz.com.br
Content-Type: application/json
X-Api-Key: dlz_live_8f2c4a1b9e7d3a5c6b8e1f9d2c4a7b5e
Idempotency-Key: 9f4d2c1a-7b6e-4a8d-9c1f-2e5b8d3a4c7f

{
  "protocolNumber": "EXT-2026-001234",
  "assetType": "POLE",
  "requestedAt": "2026-05-20T13:42:00Z",
  "requester": {
    "name": "Maria da Silva",
    "phone": "+5583999998888"
  },
  "lampType": "LED",
  "reasonCode": "LAMP_OUT",
  "address": {
    "street": "Av. Exemplo",
    "number": "1320",
    "neighborhood": "Centro",
    "reference": "Em frente ao mercadinho",
    "latitude": -7.114,
    "longitude": -34.831
  },
  "problem": {
    "description": "Poste apagado há três dias",
    "additionalNotes": "À noite a rua fica muito escura"
  },
  "attachments": [
    {
      "type": "photo",
      "url": "https://parceiro.exemplo.gov.br/files/abc123.jpg",
      "filename": "logradouro.jpg",
      "contentType": "image/jpeg"
    }
  ]
}

Exemplo de payload com endereço parcial

{
  "protocolNumber": "EXT-2026-001235",
  "assetType": "POLE",
  "requestedAt": "2026-05-20T14:10:00Z",
  "requester": { "name": "João Pereira" },
  "address": { "street": "Rua das Trincheiras" },
  "problem": { "description": "Lâmpada queimada" }
}

Resposta de sucesso

201 Created — solicitação registrada. O conteúdo da resposta depende da política de intake configurada pela cidade.

A resposta sempre inclui um objeto alert com os dados do alerta criado a partir das informações da requisição.

Modo automático (OS gerada imediatamente)

Quando a cidade está configurada para abrir OS automaticamente, o alerta é criado e já vinculado a uma OS. O campo internalProtocol traz o número humano-legível da OS gerada. O id raiz refere-se à OS; o alerta fica em alert.

{
  "id": "8c2b4a1f-3d6e-4b9a-bc2f-5a7d8e1c9b3a",
  "internalProtocol": "OS-00042",
  "protocolNumber": "EXT-2026-001234",
  "assetType": "POLE",
  "status": "OPEN",
  "priority": "Medium",
  "createdAt": "2026-05-20T13:42:05Z",
  "alert": {
    "id": "3e7f1a2b-9c4d-4e8a-b1f2-6d5c8a9b0e1f",
    "alertNumber": 42,
    "alertReasonCode": "LAMP_OUT",
    "alertReasonName": "Lâmpada apagada",
    "requesterName": "Maria da Silva",
    "requesterPhone": "+5583999998888",
    "description": "Poste apagado há três dias",
    "additionalNotes": "À noite a rua fica muito escura",
    "lampType": "LED",
    "externalRequestedAt": "2026-05-20T13:42:00Z",
    "latitude": -7.114,
    "longitude": -34.831,
    "status": "Linked",
    "attachments": [
      {
        "success": true,
        "blobPath": "service-orders-external/cidade/3e7f1a2b.../f9d8e7c6...jpg",
        "filename": "logradouro.jpg",
        "contentType": "image/jpeg",
        "sizeBytes": 124500,
        "error": null
      }
    ]
  }
}

Modo manual (alerta aguardando triagem)

Quando a cidade exige triagem manual, o alerta é registrado e fica aguardando classificação operacional. A OS só é gerada depois — quando isso acontecer, o sistema externo recebe um webhook ServiceOrder.Created. O id raiz refere-se ao alerta nesse cenário; internalProtocol é omitido até o alerta virar OS.

{
  "id": "5a3d1c9f-2b4e-4a8d-9c1f-7e6b5d8a3c4f",
  "protocolNumber": "EXT-2026-001234",
  "assetType": "POLE",
  "status": "RECEIVED",
  "createdAt": "2026-05-20T13:42:05Z",
  "alert": {
    "id": "5a3d1c9f-2b4e-4a8d-9c1f-7e6b5d8a3c4f",
    "alertNumber": 42,
    "alertReasonCode": "LAMP_OUT",
    "alertReasonName": "Lâmpada apagada",
    "requesterName": "Maria da Silva",
    "requesterPhone": "+5583999998888",
    "description": "Poste apagado há três dias",
    "additionalNotes": "À noite a rua fica muito escura",
    "lampType": "LED",
    "externalRequestedAt": "2026-05-20T13:42:00Z",
    "latitude": -7.114,
    "longitude": -34.831,
    "status": "Pending",
    "attachments": [
      {
        "success": true,
        "blobPath": "service-orders-external/cidade/5a3d1c9f.../a1b2c3d4...jpg",
        "filename": "logradouro.jpg",
        "contentType": "image/jpeg",
        "sizeBytes": 124500,
        "error": null
      }
    ]
  }
}

200 OK — solicitação já havia sido registrada (idempotência ou reenvio com mesmo protocolNumber). Retorna o resultado original sem efeito colateral.

Campos da resposta

CampoOrigemDescrição
idDirectLuz (interno)UUID v4 da entidade criada — OS quando modo automático, alerta quando triagem manual
internalProtocolDirectLuz (interno)OS-NNNNN. Presente apenas no modo automático
protocolNumberSistema externoEco do protocolo informado na requisição
assetTypeEco do payloadTipo de ativo (POLE nesta versão)
statusDirectLuzOPEN (OS criada) ou RECEIVED (alerta aguardando triagem)
priorityDirectLuzPresente apenas no modo automático
createdAtDirectLuzData/hora UTC de criação da entidade principal
alert.idDirectLuz (interno)UUID v4 do alerta criado
alert.alertNumberDirectLuz (interno)Número sequencial interno do alerta
alert.alertReasonCodeDirectLuz (interno)Código do motivo interno aplicado ao alerta (ex.: LAMP_OUT, EXTERNAL_OTHER)
alert.alertReasonNameDirectLuz (interno)Nome legível do motivo interno
alert.requesterNameEco do payloadNome do solicitante
alert.requesterPhoneEco do payloadTelefone do solicitante (E.164)
alert.descriptionEco do payloadDescrição do problema (problem.description)
alert.additionalNotesEco do payloadObservações adicionais (problem.additionalNotes)
alert.lampTypeEco do payloadTipo de lâmpada informado
alert.externalRequestedAtEco do payloadData/hora UTC da solicitação original (requestedAt)
alert.latitudeDirectLuzLatitude WGS-84 resolvida (vinda do payload ou geocodificação). null se não foi possível geolocalizar
alert.longitudeDirectLuzLongitude WGS-84 resolvida. null se não foi possível geolocalizar
alert.statusDirectLuzStatus interno do alerta no DirectLuz. Ver tabela de valores abaixo
alert.attachmentsDirectLuzArray com o resultado do processamento de cada anexo enviado. Sempre presente (pode ser [])
alert.attachments[].successDirectLuztrue se o anexo foi armazenado com sucesso; false em caso de falha
alert.attachments[].blobPathDirectLuzCaminho interno no storage da DirectLuz. null se falhou
alert.attachments[].filenameEco do payloadNome do arquivo
alert.attachments[].contentTypeEco do payloadTipo MIME do anexo
alert.attachments[].sizeBytesDirectLuzTamanho em bytes do arquivo armazenado. null se falhou
alert.attachments[].errorDirectLuzDescrição do erro quando success é false; null quando bem-sucedido

Valores de alert.status

O campo reflete o estado interno do alerta no DirectLuz no momento da resposta.

ValorDescrição
PendingAlerta registrado e aguardando triagem manual por um operador. Estado inicial quando a política da cidade é triagem manual
LinkedAlerta vinculado a uma Ordem de Serviço — a OS foi criada automaticamente (modo automático) ou manualmente por um operador
ResolvedOS vinculada ao alerta foi concluída. O problema foi atendido
CancelledAlerta descartado por um operador antes de ser vinculado a uma OS

Anexos e fotografias

Cada item da lista attachments deve conter:

CampoTipoObrigatórioDescrição
typestringSimAtualmente apenas photo
urlstring (HTTPS)Sim, se contentBase64 não enviadoURL pública ou assinada com expiração mínima de 24 horas
contentBase64stringSim, se url não enviadoConteúdo binário codificado em base64. Limite de 5 MB por anexo
filenamestringNãoNome original do arquivo
contentTypestringSimimage/jpeg, image/png ou image/webp

A DirectLuz baixa o conteúdo do anexo e mantém cópia em storage próprio. Anexos cuja URL retorne falha após três tentativas são descartados e registrados em log para reconsulta manual.

Atenção com contentBase64: envie apenas o conteúdo binário codificado em base64 puro — sem o prefixo data:image/jpeg;base64,. Exemplo correto: "/9j/4AAQSkZJRgAB...".

O resultado de cada anexo é retornado no array alert.attachments da resposta. Use o campo error para diagnosticar falhas sem precisar de acesso ao servidor.

Erros

Ver lista completa em Response Codes.

On this page