Integrações/Webhooks
Homologação

Webhooks

Receba eventos e adapte as notificações ao seu sistema.

Configure em Admin → Unidades → Tokens de API → Webhook de retorno.

Evento Quando é gerado
report.signed Assinatura, retificação ou recebimento externo do laudo
study.received Primeiro estudo estável disponibilizado ao RIS, após a janela sem novas imagens

É possível selecionar os eventos, definir os destinos, configurar autenticação por header e adaptar o JSON enviado. A prévia utiliza dados sintéticos e não chama o sistema de destino.

O receptor confirma o recebimento com HTTP 2xx. Há timeout de 10 segundos e até seis novas tentativas, em 2, 4, 8, 16, 32 e 64 minutos. O corpo preparado permanece igual nas repetições; o receptor deve tratar entregas repetidas sem duplicar sua operação.

O template usa a representação padrão do laudo, com URL quando disponível. Ele não carrega o PDF em base64 nem anexos binários. SOAP, outras formas de autenticação ou transporte e mensagens que exigem binários embutidos podem precisar de um conector específico.

Ativar um evento não envia retroativamente todos os exames antigos. A reintegração manual disponível é exclusiva de laudos. Os logs da credencial ajudam a acompanhar chamadas recebidas e tentativas de entrega.

Eventos e destinos

  • report.signed: assinatura, retificação e recebimento externo do laudo, nos mesmos pontos do callback anterior. A reintegração manual continua exclusiva de laudos.
  • study.received: primeiro study-stable disponibilizado ao RIS, após a janela de 60 segundos sem novas imagens. Não exige laudo. É uma notificação por organização/credencial/StudyInstanceUID, não por instância DICOM.
  • Exames cancelados não geram entregas. Um exame já laudado pode receber seu primeiro vínculo DICOM sem alteração do estado do laudo. Um UID diferente não substitui o vínculo de um exame laudado/atribuído.
  • webhookUrlStudy: null usa a URL de laudo, escolha explícita no formulário. Sem destino efetivo não há entrega.
  • Assinaturas de evento são avaliadas na geração. Alterar URL/autenticação afeta entregas pendentes; apagar o destino ou revogar a credencial interrompe a entrega. Template e corpo seguem o snapshot descrito abaixo.

O registro durável mobilemed_study_receipts guarda o primeiro estudo estável inclusive sem assinantes. Ativar a assinatura depois não faz uma onda posterior entregar retroativamente o recebimento. Esse histórico começa no primeiro study-stable processado após instalar a funcionalidade: não inventamos o histórico anterior. UID já vinculado por study-started não significa que o primeiro study-stable já ocorreu. A transação do consumidor grava recibo e entregas conjuntamente; rollback permite tentar novamente. A unicidade inclui registros logicamente excluídos.

API administrativa

PATCH /api/v1/units/:unitId/api-clients/:clientId

{
  "webhookEvents": ["report.signed", "study.received"],
  "webhookUrlReport": "https://sistema.exemplo/laudos",
  "webhookUrlStudy": "https://sistema.exemplo/imagens",
  "webhookPayloadTemplates": {
    "report.signed": {
      "evento": {"$path": ["event"]},
      "numero": {"$path": ["study", "accessionNumber"]},
      "resultado": {"$path": ["study", "report", "content"]},
      "origem": {"$literal": "Themis"}
    },
    "study.received": {
      "pedido": {"$path": ["source", "pedido", "numero"], "$default": null},
      "estudo": {"$path": ["study", "studyUID"]}
    }
  }
}

GET da lista de credenciais e resposta do PATCH incluem os três campos novos. Omissão preserva; webhookEvents:null restaura ["report.signed"], [] desliga novos eventos; webhookPayloadTemplates:null restaura {}. A URL nula limpa o destino específico. webhookAuthHeaderName/webhookAuthHeaderValue mantêm o contrato anterior: valor omitido ou vazio preserva; valor nulo remove. Remover o nome do header remove também seu valor. A resposta contém apenas webhookConfigured e o nome, nunca o valor cifrado ou decifrado.

POST /api/v1/units/:unitId/api-clients/:clientId/webhook-preview responde 200 { "payload": <JSON> }, sem chamada externa ou leitura de exames reais:

{
  "event": "study.received",
  "template": {"ativo": {"$path": ["source", "ativo"]}},
  "context": {"source": {"ativo": false}}
}

template omitido usa o template salvo; template:null produz JSON null. useDefaultTemplate:true permite visualizar o formato padrão ao remover um template no editor. context é opcional e aceita somente study, source, eventId, occurredAt e sentAt, até 65536 bytes de JSON UTF-8. O evento sempre vem de event. Sem contexto usam-se dados fictícios estáveis. A UI mostra a prévia sintética, permite salvar e reabrir os valores.

Linguagem de templates

Objetos, arrays e valores JSON nativos são aceitos, inclusive na raiz (false, 0, "", null). A ausência da chave do evento no mapa escolhe o formato padrão; um valor falso ou nulo configurado nunca significa ausência.

  • {"$path":["study","report","content"]} preserva o tipo do valor; segmentos numéricos acessam índices de arrays.
  • Caminho ausente resulta em null; $default fornece um literal alternativo. Valores existentes false, 0, "" e null são preservados.
  • {"$literal": ...} inclui JSON literalmente, sem interpretar suas chaves.
  • Raízes disponíveis: event, eventId, occurredAt, sentAt, study, source.
  • Limites: mapa de templates de 65536 bytes UTF-8, profundidade 20, caminhos de 1 a 20 segmentos, segmentos de texto até 128 caracteres. Chaves especiais desconhecidas, raízes não permitidas e acesso a protótipos são recusados. Não há código, interpolação executável, loops nem chamadas externas.

study usa o perfil atual da credencial: IDs públicos numéricos para MobileMed, compatibilidade anterior no perfil legacy. O conteúdo do laudo usa a visão padrão da API (URL quando disponível), sem carregar PDF/base64 ou anexos binários. source é o objeto JSON/XML parseado do ingresso PROJECTED mais recente desse mesmo cliente e item; exclui ingressos deletados e não cruza credenciais. Reprocessamento não reordena ingressos. Só é consultado quando o template pode referenciá-lo.

Persistência e retry

Na geração ficam imutáveis: evento, UUID do evento, data de ocorrência no RIS, item, UID, versão da linguagem (1) e envelope do template {configured,value}. Na primeira preparação o worker resolve study/source e grava o corpo HTTP exato por compare-and-set. Repetições reutilizam esses mesmos bytes, incluindo sentAt, mesmo que o exame, ingresso ou template mude. SQL NULL significa não preparado; o texto null é um corpo JSON já preparado. URLs contidas no corpo mantêm a validade original; o snapshot não renova links durante retries.

As tentativas antigas sem metadados continuam no caminho de compatibilidade anterior. Sem template, novas tentativas mantêm a estrutura anterior {event,sentAt,study}. O destino e a autenticação de transporte são consultados a cada tentativa, permitindo rotação do segredo. O backoff existente e a reintegração manual de laudos permanecem.