{
  "openapi": "3.1.0",
  "info": {
    "title": "Themis — API de Integração (compatível MobileMed)",
    "version": "2.0.0",
    "description": "API pública de integração nas 26 rotas MobileMed. A representação depende de contractProfile: credenciais novas usam mobilemed; credenciais anteriores permanecem legacy até mudança administrativa explícita. O header api: one|mob não seleciona perfil nem altera autorização. UUIDs internos, accession, CPF e StudyUID permanecem intactos; IDs externos mobilemed são inteiros positivos estáveis por organização e recurso.\n\nToda rota, exceto /v1/doc, exige token. api é opcional; valor diferente de one/mob retorna 406. Token ausente retorna 406; desconhecido ou ambíguo retorna 404. A credencial pertence a uma unidade e acessa sua organização. Erros mobilemed não recebem statusCode, timestamp ou path; somente legacy identificado mantém esse envelope.\n\nAs decisões explícitas para fontes contraditórias são: JSON válido com message nas mutações, url no PDF e array de países; HTTP 201 em signed/countries/pdf-link mobilemed; prioridade 1..6; cancelados são omitidos no mobilemed e conservam -1 no legacy. Os estados 0..11 e as 14 marcações clínicas têm origem persistida. Não se infere malignidade de BI-RADS ou validade criptográfica de hash/status.\n\nPDF agrupado retorna um PDF base64 em content; único preserva bytes e compilação não herda assinatura criptográfica. groupedContent é extensão deprecated exclusiva de legacy. JPEG, PNG, GIF, BMP e PDF são aceitos; GIF/BMP citados geram derivada PNG, com primeiro quadro composto para GIF e original preservado.\n\nrelease persiste retenção por exame nos canais de paciente; staff e audiência physician continuam autorizados. forMedic=true abre /medico/estudo/:token, inclusive antes do laudo. Links de integração acompanham laudos futuros exclusivamente do mesmo exame/organização.\n\nWorklist mobilemed conserva JSON/XML e retorna 201 {} inclusive noop. Fonte genérica sem projeção fica RAW_ONLY. Adapters declarativos permitem prévia e reprocessamento sem alterar laudo, assinatura ou escopo de links. Legacy conserva DTO obrigatório e created201/noop200.\n\nWebhooks report.signed e study.received usam subscriptions e templates por credencial. O primeiro study-stable inicia histórico durável sem retroatividade. Template é congelado no evento e corpo HTTP na primeira preparação; retries mantêm bytes. URL e autenticação são atuais. Configuração administrativa e leitura compartilhada têm contratos complementares versionados.",
    "contact": {
      "name": "Themis Health",
      "email": "integracao@themishealth.com.br"
    },
    "license": {
      "name": "Proprietário — Themis Health"
    }
  },
  "servers": [
    {
      "url": "/"
    }
  ],
  "tags": [
    {
      "name": "Exame",
      "description": "Leitura e mutações do exame por Accession Number / StudyUID"
    },
    {
      "name": "Physician",
      "description": "Médicos executantes por CRM + UF"
    },
    {
      "name": "Result",
      "description": "Portal de entregas (paciente por CPF + nascimento)"
    },
    {
      "name": "Viewer",
      "description": "Links públicos de acesso às imagens"
    },
    {
      "name": "Worklist",
      "description": "Cadastro de exames (DICOM Modality Worklist)"
    },
    {
      "name": "Documentação",
      "description": "Esta documentação (pública)"
    },
    {
      "name": "Webhook",
      "description": "Chamadas que a plataforma faz ao sistema terceiro"
    }
  ],
  "security": [
    {
      "token": []
    }
  ],
  "paths": {
    "/v1/exam/{accessionNumber}/comment": {
      "post": {
        "tags": [
          "Exame"
        ],
        "operationId": "createComment",
        "summary": "Cria comentário no exame",
        "description": "Cria comentário para o exame. Opcionalmente muda o status do exame junto com o comentário — só é permitida a alteração quando o exame ainda não foi assinado. Opções disponíveis para `status`: 0 para novo (a ser laudado), 3 para pendente e 7 para reconvocar.\n\nSem `status`, o comentário é só registrado (vale mesmo em exame assinado). Com `status`, um exame já assinado responde 400 `Exam already signed, no changes allowed`.\n\nA doc da MobileMed ilustra o corpo de sucesso como `{ \"Comment was created successfully\" }` (JSON inválido); o Themis responde `{ \"message\": \"Comment was created successfully\" }`.",
        "x-mobilemed": {
          "name": "createComment",
          "url": "/v1/exam/:accessionNumber/comment",
          "group": "Exame",
          "description": "Cria comentario para o exame"
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number do exame",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "comment"
                ],
                "properties": {
                  "comment": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000
                  },
                  "status": {
                    "type": "integer",
                    "enum": [
                      0,
                      3,
                      7
                    ],
                    "description": "Novo status do exame (0 novo, 3 pendente, 7 reconvocar). Aceito também como string (\"3\")."
                  }
                }
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "comment": "Example of a comment body",
                    "status": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageBody"
                },
                "examples": {
                  "themis": {
                    "summary": "Comment was created successfully (Themis)",
                    "value": {
                      "message": "Comment was created successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue); Exame já assinado, sem alterações permitidas; Corpo/parâmetros inválidos (validação). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  },
                  "assinado": {
                    "summary": "exame já assinado",
                    "value": {
                      "message": "Exam already signed, no changes allowed"
                    }
                  },
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/{accessionNumber}": {
      "get": {
        "tags": [
          "Exame"
        ],
        "operationId": "find",
        "summary": "Consulta o exame pelo Accession Number",
        "description": "Consulta o exame pelo Accession Number.\n\nEstados públicos: 0 Novo, 1 Assinado, 2 Laudando, 3 Pendente, 4 Revisar, 5 Reassinado, 6 Digitado, 7 Reconvocar, 8 Digitadoia, 9 A Preparar, 10 Pré Laudado, 11 Digitando. No perfil mobilemed, exames cancelados são omitidos e a leitura direta usa o erro de exame ausente da rota; legacy conserva -1. Precedência: FINAL/SIGNED=1 ou AMENDED=5; reconvocação=7; pendência/WAITING_INFO=3; reavaliação=4; transcrição ativa com editor=11; revisão pendente=6 (8 para AI); laudo em andamento=2; rascunho AI com conteúdo=8; outro rascunho com conteúdo=10; preparação=9; REPORTING/ASSIGNED=2; demais=0.\n\nPrioridades: 1 Rotina, 2 Ambulatório, 3 Urgência, 4 Emergência, 5 Plantão, 6 Internado. Com marcacaoClinica=true: 1 Com Contraste, 2 Sem Contraste, 3 Bilateral, 4 Esquerdo, 5 Direito, 6 Não Oncológico, 7 Oncológico, 8 Precisa ser comparado, 9 Com AVC, 10 Sem AVC, 11 Oncológico Benigno, 12 Oncológico Maligno, 13 Com trauma, 14 Sem trauma. 11/12 exigem classificação explícita e incluem 7; BI-RADS não infere classificação.\n\nmobilemed usa IDs numéricos estáveis e CRM decimal positivo seguro ou null; legacy mantém UUIDs e CRM anterior. Sem format, report.content é URL assinada por uma hora ou null. format=pdf com group=true devolve um único PDF base64, inclusive com base64=false. Páginas são ordenadas por criação/id, deduplicadas; arquivo único conserva bytes. Sem laudo no solicitado, usam-se metadados do primeiro disponível. Compilação não herda assinatura criptográfica. groupedContent só existe em legacy, deprecated.\n\nformat aceita pdf, html, rtf ou text; outro valor recebe 400.",
        "x-mobilemed": {
          "name": "find",
          "url": "/v1/exam/:accessionNumber",
          "group": "Exame",
          "description": "Retorna exame de acordo com o Accession Number fornecido. Os retornos de status e prioridade poderão ser:\n\n - Status: Novo (0), Assinado (1), Laudando (2), Pendente (3), Revisar (4), Reassinado (5), Digitado (6), Reconvocar (7),\nDigitadoia (8), A Preparar (9), Pré Laudado (10) e Digitando (11);\n\n- Prioridades: Rotina (1), Ambulatório (2), Urgência (3), Emergência (4), Plantão (5) e Internado (6).\n\n- Marcações Clínicas: Com Contraste (1), Sem Contraste (2), Bilateral (3), Esquerdo (4), Direito (5), Não Oncológico (6), Oncológico (7), Precisa ser comparado (8), Com AVC (9), Sem AVC (10), Oncológico Benigno (11), Oncológico Maligno (12), Com trauma (13), Sem trauma (14)."
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number do exame",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "name": "format",
            "in": "header",
            "required": false,
            "description": "Formato do laudo a ser retornado. Opções disponíveis: pdf, html, rtf e text. Sem este header, `report.content` é a URL assinada (1 h) do PDF gravado, ou `null` se não há PDF.",
            "schema": {
              "type": "string",
              "enum": [
                "pdf",
                "html",
                "rtf",
                "text"
              ]
            }
          },
          {
            "name": "base64",
            "in": "header",
            "required": false,
            "description": "Retorno do laudo em base64. Opções disponíveis: true e false. Padrão: true quando `format` é informado.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "group",
            "in": "header",
            "required": false,
            "description": "Agrupa laudos disponíveis de itens relacionados (pai e cópias, exame principal e associados, ou mesmo StudyUID), em ordem determinística e sem duplicatas. Opções: true e false. Com format=pdf, mobilemed retorna um único PDF base64 em report.content. Em legacy, report.groupedContent é uma extensão deprecated; report.content já contém o PDF completo e não deve ser concatenado outra vez.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "marcacaoClinica",
            "in": "header",
            "required": false,
            "description": "Retorno de marcações clínicas do exame (`clinicalMarkings`). Opções disponíveis: true e false.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "study"
                  ],
                  "properties": {
                    "study": {
                      "$ref": "#/components/schemas/StudyView"
                    }
                  }
                },
                "examples": {
                  "mobilemed": {
                    "summary": "Perfil mobilemed (IDs numéricos)",
                    "value": {
                      "study": {
                        "id": 101,
                        "accessionNumber": "12345678",
                        "studyUID": "1.2.99.1.96.99.192.168.0.218",
                        "studyDate": "2026-09-18",
                        "company": {
                          "name": "CLINICA EXEMPLO"
                        },
                        "auxiliaryField01": "CAMPO AUXILIAR 01",
                        "description": "TOMOGRAFIA DE CRANIO",
                        "modality": "CT",
                        "status": {
                          "id": 1,
                          "description": "Assinado"
                        },
                        "priority": {
                          "id": 1,
                          "description": "Rotina"
                        },
                        "clinicalMarkings": [
                          {
                            "id": 2,
                            "description": "Sem Contraste"
                          },
                          {
                            "id": 3,
                            "description": "Bilateral"
                          },
                          {
                            "id": 8,
                            "description": "Precisa ser comparado"
                          },
                          {
                            "id": 14,
                            "description": "Sem trauma"
                          }
                        ],
                        "patient": {
                          "codigo_paciente": "123456",
                          "name": "NOME DO PACIENTE",
                          "birthday": "2000-12-01",
                          "sex": "M"
                        },
                        "publicViewerUrl": "https://laudos.exemplo.com.br/compartilhar/abc123",
                        "report": {
                          "id": 102,
                          "publishedAt": "2026-09-18T15:04:00.000Z",
                          "performingPhysician": {
                            "name": "NOME DO MÉDICO EXECUTANTE",
                            "crm": {
                              "code": 123456,
                              "uf": "SP"
                            },
                            "email": "medico@exemplo.com.br"
                          },
                          "content": "https://storage.exemplo.com.br/laudos/0b7e2a44.pdf?X-Amz-Signature=…"
                        }
                      }
                    }
                  },
                  "legacy": {
                    "summary": "Perfil legacy (UUIDs)",
                    "value": {
                      "study": {
                        "id": "6d2c1e0a-7f6b-4c1e-9a1a-3f2b5c8d9e01",
                        "accessionNumber": "12345678",
                        "studyUID": "1.2.99.1.96.99.192.168.0.218",
                        "studyDate": "2026-09-18",
                        "company": {
                          "name": "CLINICA EXEMPLO"
                        },
                        "auxiliaryField01": "CAMPO AUXILIAR 01",
                        "description": "TOMOGRAFIA DE CRANIO",
                        "modality": "CT",
                        "status": {
                          "id": 1,
                          "description": "Assinado"
                        },
                        "priority": {
                          "id": 1,
                          "description": "Rotina"
                        },
                        "clinicalMarkings": [
                          {
                            "id": 2,
                            "description": "Sem Contraste"
                          },
                          {
                            "id": 3,
                            "description": "Bilateral"
                          },
                          {
                            "id": 8,
                            "description": "Precisa ser comparado"
                          },
                          {
                            "id": 14,
                            "description": "Sem trauma"
                          }
                        ],
                        "patient": {
                          "codigo_paciente": "123456",
                          "name": "NOME DO PACIENTE",
                          "birthday": "2000-12-01",
                          "sex": "M"
                        },
                        "publicViewerUrl": "https://laudos.exemplo.com.br/compartilhar/abc123",
                        "report": {
                          "id": "0b7e2a44-1d6f-4a3e-8c2f-5e1d2c3b4a55",
                          "publishedAt": "2026-09-18T15:04:00.000Z",
                          "performingPhysician": {
                            "name": "NOME DO MÉDICO EXECUTANTE",
                            "crm": {
                              "code": "123456",
                              "uf": "SP"
                            },
                            "email": "medico@exemplo.com.br"
                          },
                          "content": "https://storage.exemplo.com.br/laudos/0b7e2a44.pdf?X-Amz-Signature=…"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/studyUID/{studyUID}": {
      "get": {
        "tags": [
          "Exame"
        ],
        "operationId": "findByStudyUID",
        "summary": "Consulta o exame pelo StudyUID (com exames associados)",
        "description": "Consulta o item elegível mais antigo por StudyUID na organização, com comentário, solicitante, contraste, subespecialidade, anexos e associatedExams. Os anexos usam ID numérico em mobilemed e UUID em legacy; arquivo é URL assinada ou base64 conforme header.\n\nEstados públicos: 0 Novo, 1 Assinado, 2 Laudando, 3 Pendente, 4 Revisar, 5 Reassinado, 6 Digitado, 7 Reconvocar, 8 Digitadoia, 9 A Preparar, 10 Pré Laudado, 11 Digitando. No perfil mobilemed, exames cancelados são omitidos e a leitura direta usa o erro de exame ausente da rota; legacy conserva -1. Precedência: FINAL/SIGNED=1 ou AMENDED=5; reconvocação=7; pendência/WAITING_INFO=3; reavaliação=4; transcrição ativa com editor=11; revisão pendente=6 (8 para AI); laudo em andamento=2; rascunho AI com conteúdo=8; outro rascunho com conteúdo=10; preparação=9; REPORTING/ASSIGNED=2; demais=0.\n\nPrioridades: 1 Rotina, 2 Ambulatório, 3 Urgência, 4 Emergência, 5 Plantão, 6 Internado. Com marcacaoClinica=true: 1 Com Contraste, 2 Sem Contraste, 3 Bilateral, 4 Esquerdo, 5 Direito, 6 Não Oncológico, 7 Oncológico, 8 Precisa ser comparado, 9 Com AVC, 10 Sem AVC, 11 Oncológico Benigno, 12 Oncológico Maligno, 13 Com trauma, 14 Sem trauma. 11/12 exigem classificação explícita e incluem 7; BI-RADS não infere classificação.\n\nmobilemed usa IDs numéricos estáveis e CRM decimal positivo seguro ou null; legacy mantém UUIDs e CRM anterior. Sem format, report.content é URL assinada por uma hora ou null. format=pdf com group=true devolve um único PDF base64, inclusive com base64=false. Páginas são ordenadas por criação/id, deduplicadas; arquivo único conserva bytes. Sem laudo no solicitado, usam-se metadados do primeiro disponível. Compilação não herda assinatura criptográfica. groupedContent só existe em legacy, deprecated.",
        "x-mobilemed": {
          "name": "findByStudyUID",
          "url": "/v1/exam/studyUID/:studyUID",
          "group": "Exame",
          "description": "Retorna exame de acordo com o StudyUID fornecido, incluindo comentário, médico solicitante, contraste, subespecialidade, anexos e os exames duplicados associados ao mesmo StudyUID. Os retornos de status e prioridade poderão ser:\n\n - Status: Novo (0), Assinado (1), Laudando (2), Pendente (3), Revisar (4), Reassinado (5), Digitado (6), Reconvocar (7),\nDigitadoia (8), A Preparar (9), Pré Laudado (10) e Digitando (11);\n\n- Prioridades: Rotina (1), Ambulatório (2), Urgência (3), Emergência (4), Plantão (5) e Internado (6)."
        },
        "parameters": [
          {
            "name": "studyUID",
            "in": "path",
            "required": true,
            "description": "StudyUID (Study Instance UID) do exame",
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          },
          {
            "name": "format",
            "in": "header",
            "required": false,
            "description": "Formato do laudo a ser retornado. Opções disponíveis: pdf, html, rtf e text. Sem este header, `report.content` é a URL assinada (1 h) do PDF gravado, ou `null` se não há PDF.",
            "schema": {
              "type": "string",
              "enum": [
                "pdf",
                "html",
                "rtf",
                "text"
              ]
            }
          },
          {
            "name": "base64",
            "in": "header",
            "required": false,
            "description": "Retorno do laudo em base64. Opções disponíveis: true e false. Padrão: true quando `format` é informado.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "group",
            "in": "header",
            "required": false,
            "description": "Agrupa laudos disponíveis de itens relacionados (pai e cópias, exame principal e associados, ou mesmo StudyUID), em ordem determinística e sem duplicatas. Opções: true e false. Com format=pdf, mobilemed retorna um único PDF base64 em report.content. Em legacy, report.groupedContent é uma extensão deprecated; report.content já contém o PDF completo e não deve ser concatenado outra vez.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "marcacaoClinica",
            "in": "header",
            "required": false,
            "description": "Retorno de marcações clínicas do exame (`clinicalMarkings`). Opções disponíveis: true e false.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FindByStudyUidResult"
                },
                "examples": {
                  "mobilemed": {
                    "summary": "Perfil mobilemed (IDs numéricos)",
                    "value": {
                      "study": {
                        "id": 101,
                        "accessionNumber": "12345678",
                        "studyUID": "1.2.99.1.96.99.192.168.0.218",
                        "studyDate": "2026-09-18",
                        "company": {
                          "name": "CLINICA EXEMPLO"
                        },
                        "auxiliaryField01": "CAMPO AUXILIAR 01",
                        "description": "TOMOGRAFIA DE CRANIO",
                        "modality": "CT",
                        "status": {
                          "id": 1,
                          "description": "Assinado"
                        },
                        "priority": {
                          "id": 1,
                          "description": "Rotina"
                        },
                        "patient": {
                          "codigo_paciente": "123456",
                          "name": "NOME DO PACIENTE",
                          "birthday": "2000-12-01",
                          "sex": "M"
                        },
                        "publicViewerUrl": "https://laudos.exemplo.com.br/compartilhar/abc123",
                        "report": {
                          "id": 102,
                          "publishedAt": "2026-09-18T15:04:00.000Z",
                          "performingPhysician": {
                            "name": "NOME DO MÉDICO EXECUTANTE",
                            "crm": {
                              "code": 123456,
                              "uf": "SP"
                            },
                            "email": "medico@exemplo.com.br"
                          },
                          "content": "https://storage.exemplo.com.br/laudos/0b7e2a44.pdf?X-Amz-Signature=…"
                        },
                        "comment": "COMENTÁRIO DO EXAME",
                        "applicantPhysician": "NOME DO MÉDICO SOLICITANTE",
                        "contrast": {
                          "description": "campo auxiliar 02"
                        },
                        "subspecialty": {
                          "description": "TOMOGRAFIA DE CRANIO",
                          "subspecialtyCode": "123"
                        },
                        "attachments": [
                          {
                            "anexoID": 104,
                            "mimeType": "application/pdf",
                            "arquivo": "https://storage.exemplo.com.br/anexos/9f1c2d3e.pdf?X-Amz-Signature=…"
                          }
                        ]
                      },
                      "associatedExams": [
                        {
                          "study": {
                            "id": 103,
                            "accessionNumber": "12345679",
                            "studyUID": "1.2.99.1.96.99.192.168.0.218",
                            "studyDate": "2026-09-18",
                            "company": {
                              "name": "CLINICA EXEMPLO"
                            },
                            "auxiliaryField01": "CAMPO AUXILIAR 01",
                            "description": "TOMOGRAFIA DE CRANIO",
                            "modality": "CT",
                            "status": {
                              "id": 0,
                              "description": "Novo"
                            },
                            "priority": {
                              "id": 1,
                              "description": "Rotina"
                            },
                            "patient": {
                              "codigo_paciente": "123456",
                              "name": "NOME DO PACIENTE",
                              "birthday": "2000-12-01",
                              "sex": "M"
                            },
                            "publicViewerUrl": "https://laudos.exemplo.com.br/compartilhar/abc123",
                            "report": null,
                            "contrast": {
                              "description": ""
                            },
                            "subspecialty": {
                              "description": "TOMOGRAFIA DE CRANIO",
                              "subspecialtyCode": "123"
                            }
                          }
                        }
                      ]
                    }
                  },
                  "legacy": {
                    "summary": "Perfil legacy (UUIDs)",
                    "value": {
                      "study": {
                        "id": "6d2c1e0a-7f6b-4c1e-9a1a-3f2b5c8d9e01",
                        "accessionNumber": "12345678",
                        "studyUID": "1.2.99.1.96.99.192.168.0.218",
                        "studyDate": "2026-09-18",
                        "company": {
                          "name": "CLINICA EXEMPLO"
                        },
                        "auxiliaryField01": "CAMPO AUXILIAR 01",
                        "description": "TOMOGRAFIA DE CRANIO",
                        "modality": "CT",
                        "status": {
                          "id": 1,
                          "description": "Assinado"
                        },
                        "priority": {
                          "id": 1,
                          "description": "Rotina"
                        },
                        "patient": {
                          "codigo_paciente": "123456",
                          "name": "NOME DO PACIENTE",
                          "birthday": "2000-12-01",
                          "sex": "M"
                        },
                        "publicViewerUrl": "https://laudos.exemplo.com.br/compartilhar/abc123",
                        "report": {
                          "id": "0b7e2a44-1d6f-4a3e-8c2f-5e1d2c3b4a55",
                          "publishedAt": "2026-09-18T15:04:00.000Z",
                          "performingPhysician": {
                            "name": "NOME DO MÉDICO EXECUTANTE",
                            "crm": {
                              "code": "123456",
                              "uf": "SP"
                            },
                            "email": "medico@exemplo.com.br"
                          },
                          "content": "https://storage.exemplo.com.br/laudos/0b7e2a44.pdf?X-Amz-Signature=…"
                        },
                        "comment": "COMENTÁRIO DO EXAME",
                        "applicantPhysician": "NOME DO MÉDICO SOLICITANTE",
                        "contrast": {
                          "description": "campo auxiliar 02"
                        },
                        "subspecialty": {
                          "description": "TOMOGRAFIA DE CRANIO",
                          "subspecialtyCode": "123"
                        },
                        "attachments": [
                          {
                            "anexoID": "9f1c2d3e-4b5a-4c6d-8e7f-0a1b2c3d4e5f",
                            "mimeType": "application/pdf",
                            "arquivo": "https://storage.exemplo.com.br/anexos/9f1c2d3e.pdf?X-Amz-Signature=…"
                          }
                        ]
                      },
                      "associatedExams": [
                        {
                          "study": {
                            "id": "7e3d2f1b-8a7c-4d2f-9b2b-4a3c6d9e0f12",
                            "accessionNumber": "12345679",
                            "studyUID": "1.2.99.1.96.99.192.168.0.218",
                            "studyDate": "2026-09-18",
                            "company": {
                              "name": "CLINICA EXEMPLO"
                            },
                            "auxiliaryField01": "CAMPO AUXILIAR 01",
                            "description": "TOMOGRAFIA DE CRANIO",
                            "modality": "CT",
                            "status": {
                              "id": 0,
                              "description": "Novo"
                            },
                            "priority": {
                              "id": 1,
                              "description": "Rotina"
                            },
                            "patient": {
                              "codigo_paciente": "123456",
                              "name": "NOME DO PACIENTE",
                              "birthday": "2000-12-01",
                              "sex": "M"
                            },
                            "publicViewerUrl": "https://laudos.exemplo.com.br/compartilhar/abc123",
                            "report": null,
                            "contrast": {
                              "description": ""
                            },
                            "subspecialty": {
                              "description": "TOMOGRAFIA DE CRANIO",
                              "subspecialtyCode": "123"
                            }
                          }
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/{accessionNumber}/comments": {
      "get": {
        "tags": [
          "Exame"
        ],
        "operationId": "getComments",
        "summary": "Lista os comentários do exame",
        "description": "Retorna uma array de comentários feitos no exame, de acordo com o Accession Number fornecido, do mais antigo para o mais novo. Datas no formato `YYYY-MM-DD HH:mm`, no fuso da credencial.",
        "x-mobilemed": {
          "name": "getComments",
          "url": "/v1/exam/:accessionNumber/comments",
          "group": "Exame",
          "description": "Retorna uma array de comentários feitos no exame, de acordo com o Accession Number fornecido."
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number do exame",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Comment"
                  }
                },
                "examples": {
                  "mobilemed": {
                    "summary": "Success-Response (doc MobileMed)",
                    "value": [
                      {
                        "comentario": "Comentário exemplo 1",
                        "data_criacao": "2023-03-03 02:01",
                        "data_alteracao": "2023-03-03 02:01"
                      },
                      {
                        "comentario": "Comentário exemplo 2",
                        "data_criacao": "2023-03-03 02:01",
                        "data_alteracao": "2023-03-03 02:01"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/logs/integration": {
      "get": {
        "tags": [
          "Exame"
        ],
        "operationId": "integrationLogs",
        "summary": "Relatório de logs de integração",
        "description": "Retorna uma array de logs de integração, com no máximo 20 por página, ou retorna um link para download dos logs em Excel (`xlsx=true` → `{ \"url\": \"...\" }`, URL assinada, sem paginação).\n\nO relatório mistura os dois sentidos: chamadas recebidas por esta credencial e entregas do webhook de retorno do laudo ao sistema terceiro (`descricaoErro` traz a causa da falha, p. ex. `connect ECONNREFUSED`). `statusRetorno` é o HTTP da chamada/entrega; `codigoPedido` é o código do pedido do exame (`order_code` da worklist), quando há.",
        "x-mobilemed": {
          "name": "integrationLogs",
          "url": "/v1/exam/logs/integration",
          "group": "Exame",
          "description": "Retorna uma array de logs de integração, com no máximo 20 por página, ou retorna um link para download dos logs em Excel."
        },
        "parameters": [
          {
            "name": "success",
            "in": "query",
            "required": false,
            "description": "Retorno de logs que obtiveram ou não sucesso na integração. Opções disponíveis: true e false. Sem o filtro, vêm os dois.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "description": "Data do começo do relatório. Formato YYYY-MM-DD.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "finalDate",
            "in": "query",
            "required": false,
            "description": "Data do fim do relatório. Formato YYYY-MM-DD.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Número da página do relatório (padrão 1).",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "xlsx",
            "in": "query",
            "required": false,
            "description": "Retorno do relatório em um link para download em formato xlsx. Opções disponíveis: true e false.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/IntegrationLogsResult"
                    },
                    {
                      "$ref": "#/components/schemas/UrlBody"
                    }
                  ]
                },
                "examples": {
                  "themis": {
                    "summary": "Exemplo (Themis)",
                    "value": {
                      "totalLogs": {
                        "total": 417,
                        "pages": 21
                      },
                      "logs": [
                        {
                          "accessionNumber": "12313123",
                          "studyIUID": "1.2.99.1.96.99.192.168.0.218",
                          "codigoPedido": "3656753",
                          "statusRetorno": 0,
                          "descricaoErro": "fetch failed: connect ECONNREFUSED 127.0.0.1:8082"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corpo/parâmetros inválidos (validação). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/{accessionNumber}/keyimages": {
      "get": {
        "tags": [
          "Exame"
        ],
        "operationId": "keyImagesJPEG",
        "summary": "Imagens-chave do laudo em JPEG",
        "description": "Busca as imagens chaves em JPEG: URLs assinadas das imagens-chave anexadas ao laudo do exame. Exame sem laudo ou sem imagens-chave responde `{ \"images\": [] }`.",
        "x-mobilemed": {
          "name": "keyImagesJPEG",
          "url": "/v1/exam/:accessionNumber/keyimages",
          "group": "Exame",
          "description": "Busca as imagens chaves em JPEG"
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number do exame",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "images"
                  ],
                  "properties": {
                    "images": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "format": "uri"
                      }
                    }
                  }
                },
                "examples": {
                  "mobilemed": {
                    "summary": "Success-Response (doc MobileMed)",
                    "value": {
                      "images": [
                        "http://link.com/images"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/{accessionNumber}/report": {
      "post": {
        "tags": [
          "Exame"
        ],
        "operationId": "receiveReport",
        "summary": "Recebe o laudo externo (HTML, RTF ou PDF) e assina",
        "description": "Recebe laudo do exame pelo seu respectivo Accession Number. São suportados os formatos HTML, RTF e PDF, que deverão ser especificados no atributo `reportFormat` do body; o documento vai em `report`, em base64 (aceita também data URL `data:...;base64,`). Caso `reportFormat` seja PDF, o laudo não poderá ser alterado, somente refeito do zero. Caso a opção `useIntegrationUser` seja false (ou ausente), deverá ser enviado o campo `physicianCrmUf` (`\"12345-SP\"`) com o CRM e UF do médico executante, cadastrado na plataforma com esse CRM/UF.\n\nNo lugar do Accession Number, o path aceita a palavra `study` para localizar o exame pelo `studyIUID` do body (`POST /v1/exam/study/report`).\n\nO laudo recebido vira um laudo **assinado** na plataforma e dispara o webhook `report.signed` (quando a credencial tem webhook configurado). Um exame já assinado responde 400 `Exam already signed, no changes allowed`.\n\n**Desvios:** a doc da MobileMed escreve o path com o erro de digitação `:acessionNumber`; aqui é `{accessionNumber}`. Laudo externo em exame que ainda não recebeu imagens é assinado mesmo assim e o status do item da worklist é mantido. Sucesso é `{ \"message\": \"Exam report set successfully\" }`.",
        "x-mobilemed": {
          "name": "receiveReport",
          "url": "/v1/exam/:acessionNumber/report",
          "group": "Exame",
          "description": "Recebe laudo do exame pelo seu respectivo Accession Number. São suportados os formatos HTML, RTF e PDF, que deverão ser específicados no atributo 'reportFormat' do body.\n Caso \"reportFormat\" seja PDF, o laudo não poderá ser alterado, somente refeito do zero.\n Caso a opção \"useIntegrationUser\" seja false, deverá ser enviado o campo \"physicianCrmUf\" com o CRM e UF do médico executante, que estejam cadastrados no Portal Mobilemed."
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number do exame, ou a palavra `study` para usar o `studyIUID` do body",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReceiveReportBody"
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "reportFormat": "html",
                    "physicianCrmUf": "12345-SP",
                    "report": "PHA+PHN0cm9uZz5UT01PR1JBRklBIENPTVBVVEFET1JJWkFEQSBERSBBQkRPTUUgRSBQRUxWRTwvc3Ryb25nPjwvcD4KPHA"
                  }
                },
                "mobilemed2": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "reportFormat": "pdf",
                    "useIntegrationUser": true,
                    "report": "base64",
                    "studyIUID": "1.2.4352.434313124"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageBody"
                },
                "examples": {
                  "themis": {
                    "summary": "Exam report set successfully (Themis)",
                    "value": {
                      "message": "Exam report set successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue); Exame já assinado, sem alterações permitidas; Corpo/parâmetros inválidos (validação); report não é base64; reportFormat pdf com conteúdo que não é PDF; sem physicianCrmUf; physicianCrmUf mal formado; path `study` sem studyIUID. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  },
                  "assinado": {
                    "summary": "exame já assinado",
                    "value": {
                      "message": "Exam already signed, no changes allowed"
                    }
                  },
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  },
                  "base64": {
                    "summary": "report não é base64",
                    "value": {
                      "message": "Invalid base64 report"
                    }
                  },
                  "pdf": {
                    "summary": "reportFormat pdf com conteúdo que não é PDF",
                    "value": {
                      "message": "Report is not a valid PDF"
                    }
                  },
                  "crm": {
                    "summary": "sem physicianCrmUf",
                    "value": {
                      "message": "physicianCrmUf is required when useIntegrationUser is false"
                    }
                  },
                  "crmFormato": {
                    "summary": "physicianCrmUf mal formado",
                    "value": {
                      "message": "Invalid physicianCrmUf: expected \"<crm>-<uf>\""
                    }
                  },
                  "study": {
                    "summary": "path `study` sem studyIUID",
                    "value": {
                      "message": "studyIUID is required when accessionNumber is \"study\""
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo); CRM/UF sem médico cadastrado. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorMessage"
                    }
                  ]
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  },
                  "medico": {
                    "summary": "CRM/UF sem médico cadastrado",
                    "value": {
                      "message": "Physician not found"
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/reintegrateReports": {
      "post": {
        "tags": [
          "Exame"
        ],
        "operationId": "reintegrateReports",
        "summary": "Reenfileira o webhook de retorno de laudos",
        "description": "Reenfileira report.signed para até 20 accessions, com contador zerado, nas credenciais da organização inscritas nesse evento e com destino efetivo. Não reintegra study.received. Accessions ausentes são ignorados. Responde {message: \"Exams sended to reintegration queue.\"}.",
        "x-mobilemed": {
          "name": "reintegrateReports",
          "url": "/v1/exam/reintegrateReports",
          "group": "Exame",
          "description": "Recebe uma array de Accession Numbers para a reintegração manual de exames, com número máximo de 20 por requisição."
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "accessionNumbers"
                ],
                "properties": {
                  "accessionNumbers": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 20,
                    "items": {
                      "type": "object",
                      "required": [
                        "accessionNumber"
                      ],
                      "properties": {
                        "accessionNumber": {
                          "type": "string",
                          "maxLength": 64
                        }
                      }
                    }
                  }
                }
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "accessionNumbers": [
                      {
                        "accessionNumber": "12345"
                      },
                      {
                        "accessionNumber": "23456"
                      },
                      {
                        "accessionNumber": "34567"
                      }
                    ]
                  },
                  "description": "O exemplo original da MobileMed não é JSON válido; `value` é a versão corrigida e `x-mobilemed-raw` o texto original."
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageBody"
                },
                "examples": {
                  "themis": {
                    "summary": "Exams sended to reintegration queue. (Themis)",
                    "value": {
                      "message": "Exams sended to reintegration queue."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corpo/parâmetros inválidos (validação). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ]
      }
    },
    "/v1/exam/{accessionNumber}/replicate": {
      "post": {
        "tags": [
          "Exame"
        ],
        "operationId": "replicate",
        "summary": "Replica o exame em novos Accession Numbers",
        "description": "Replica entradas de um exame de acordo com o Accession Number da entrada principal já existente no portal: cria cópias do item (mesmo paciente, mesmo StudyUID) com os accessions informados, até 50 por chamada. `studyDescription` é opcional — sem ele a cópia herda a descrição do original. Accession que já existe na organização responde 409.",
        "x-mobilemed": {
          "name": "replicate",
          "url": "/v1/exam/:accessionNumber/replicate",
          "group": "Exame",
          "description": "Replica entradas de um exame de acordo com o Accession Number da entrada principal já existente no portal"
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number da entrada principal do exame",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "exams"
                ],
                "properties": {
                  "exams": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 50,
                    "items": {
                      "type": "object",
                      "required": [
                        "accessionNumber"
                      ],
                      "properties": {
                        "accessionNumber": {
                          "type": "string",
                          "maxLength": 64
                        },
                        "studyDescription": {
                          "type": "string",
                          "maxLength": 255
                        }
                      }
                    }
                  }
                }
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "exams": [
                      {
                        "accessionNumber": "1111",
                        "studyDescription": "DESCRICAO DO ESTUDO"
                      },
                      {
                        "accessionNumber": "2222",
                        "studyDescription": "DESCRICAO DO ESTUDO"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageBody"
                },
                "examples": {
                  "themis": {
                    "summary": "Exams replicated successfully (Themis)",
                    "value": {
                      "message": "Exams replicated successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue); corpo/parâmetros inválidos (validação); ou exame sem paciente vinculado. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  },
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  },
                  "semPaciente": {
                    "summary": "exame sem paciente vinculado",
                    "value": {
                      "message": "Exam has no linked patient"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Accession Number já existe na organização. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "conflito": {
                    "summary": "accession já existe",
                    "value": {
                      "message": "Accession 987654 already exists for organization … with different fields: patientName. Either retry with the same payload or PATCH explicitly.",
                      "error": "Conflict"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/{accessionNumber}/mammography": {
      "post": {
        "tags": [
          "Exame"
        ],
        "operationId": "saveMammography",
        "summary": "Grava a ficha de mamografia do exame",
        "description": "Recebe a ficha de mamografia vinculada ao exame pelo Accession Number. Grava o JSON `mammography` inteiro no exame (reenvio **sobrescreve** o JSON inteiro) e, no que dá para mapear com segurança, alimenta a anamnese estruturada da tela de laudo (esta com merge sobre o que o radiologista já preencheu). Exame assinado (status 1 ou 5) não pode ser alterado. O campo `is_mammography` no body é ignorado.\n\n Exame ausente: 404 no perfil mobilemed, 400 no legacy. Não altera outros erros de payload/assinatura.",
        "x-mobilemed": {
          "name": "saveMammography",
          "url": "/v1/exam/:accessionNumber/mammography",
          "group": "Exame",
          "description": "Recebe a ficha de mamografia vinculada ao exame pelo Accession Number. Grava o JSON mammography no laudo (tb_exame_laudo) e marca is_mammography como true no servidor. Reenvio sobrescreve o JSON inteiro. Exame assinado (status 1 ou 5) não pode ser alterado. O campo is_mammography no body é ignorado."
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number do exame",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "mammography"
                ],
                "properties": {
                  "mammography": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Ficha de mamografia — o JSON é gravado como veio."
                  }
                }
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "mammography": {
                      "cnes": "",
                      "service_name": "",
                      "exam_date": "2026-08-18",
                      "exam_number": "",
                      "never_menstruated": false,
                      "last_menstruation": null,
                      "forgot_last_menstruation": false,
                      "menopause_age": null,
                      "forgot_menopause_age": false,
                      "use_hormone": "no",
                      "is_pregnant": "no",
                      "film_quantity": 0,
                      "exibir_dados_preparo_exame": false,
                      "data_modal": {
                        "info_pessoais": {
                          "nome_mae": "",
                          "data_nascimento": null,
                          "escolaridade": ""
                        },
                        "info_residenciais": {
                          "lougradouro": "",
                          "numero": "",
                          "complemento": "",
                          "bairro": "",
                          "uf": "",
                          "cep": "",
                          "referencia": ""
                        },
                        "anamnese": {
                          "risk_of_cancer": "no",
                          "had_mammography": "no",
                          "mammography_year": "",
                          "breast_examined": "yes",
                          "nodule": "no"
                        },
                        "right": {
                          "surgery": []
                        },
                        "left": {
                          "surgery": []
                        },
                        "no_surgery": false
                      },
                      "right": {
                        "breast_was_not_radiographed": false,
                        "skin": "not_filled",
                        "breast_type": "not_filled",
                        "took_ultrasound": []
                      },
                      "left": {
                        "breast_was_not_radiographed": false,
                        "skin": "not_filled",
                        "breast_type": "not_filled",
                        "took_ultrasound": []
                      },
                      "radiological_classification": {},
                      "recommendations": {},
                      "comments": ""
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageBody"
                },
                "examples": {
                  "themis": {
                    "summary": "Mammography report saved successfully (Themis)",
                    "value": {
                      "message": "Mammography report saved successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue); Exame já assinado, sem alterações permitidas; Corpo/parâmetros inválidos (validação); sem mammography. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  },
                  "assinado": {
                    "summary": "exame já assinado",
                    "value": {
                      "message": "Exam already signed, no changes allowed"
                    }
                  },
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  },
                  "semFicha": {
                    "summary": "sem mammography",
                    "value": {
                      "message": "No mammography payload was sent"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/{accessionNumber}/attachment": {
      "post": {
        "tags": [
          "Exame"
        ],
        "operationId": "setAttachment",
        "summary": "Anexa arquivos ao exame",
        "description": "Aceita JPEG, PNG, GIF, BMP e PDF detectados pelos bytes, em base64; até 1 MB por arquivo e 20 por chamada. Preserva MIME e bytes originais. GIF/BMP promovidos e citados usam PNG derivada; GIF usa primeiro quadro composto, mantendo original animado para download. Arquivos inválidos são recusados.",
        "x-mobilemed": {
          "name": "setAttachment",
          "url": "/v1/exam/:accessionNumber/attachment",
          "group": "Exame",
          "description": "Atribui anexos comuns ao exame pelo seu respectivo Accession Number. Os tipos de anexos suportados são imagens (jpg, png, gif, bmp) ou PDF, até 1mb."
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number do exame",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "attachments"
                ],
                "properties": {
                  "attachments": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 20,
                    "items": {
                      "type": "string",
                      "contentEncoding": "base64"
                    }
                  }
                }
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "attachments": [
                      "PHA+PHN0cm9uZz5UT01PR1JBRklBIENPTVBVVEFET1JJWkFEQSBERSBBQkRPTUUgRSBQRUxWRTwvc3Ryb25nPjwvcD4KPH1",
                      "PHA+PHN0cm9uZz5UT01PR1JBRklBIENPTVBVVEFET1JJWkFEQSBERSBBQkRPTUUgRSBQRUxWRTwvc3Ryb25nPjwvcD4KPH2",
                      "PHA+PHN0cm9uZz5UT01PR1JBRklBIENPTVBVVEFET1JJWkFEQSBERSBBQkRPTUUgRSBQRUxWRTwvc3Ryb25nPjwvcD4KPH3"
                    ]
                  },
                  "description": "O exemplo original da MobileMed não é JSON válido; `value` é a versão corrigida e `x-mobilemed-raw` o texto original."
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageBody"
                },
                "examples": {
                  "themis": {
                    "summary": "Attachments successfully attached to exam (Themis)",
                    "value": {
                      "message": "Attachments successfully attached to exam"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue); Corpo/parâmetros inválidos (validação); item vazio ou não base64; acima de 1 MB; tipo não suportado. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  },
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  },
                  "vazio": {
                    "summary": "item vazio ou não base64",
                    "value": {
                      "message": "Attachment #1 is empty or not valid base64"
                    }
                  },
                  "tamanho": {
                    "summary": "acima de 1 MB",
                    "value": {
                      "message": "Attachment #1 exceeds the 1 MB limit"
                    }
                  },
                  "tipo": {
                    "summary": "tipo não suportado",
                    "value": {
                      "message": "Attachment #1 is not a supported file type (allowed: jpg, png, gif, bmp, pdf)"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/{accessionNumber}/resident-physician": {
      "post": {
        "tags": [
          "Exame"
        ],
        "operationId": "setPhysician",
        "summary": "Atribui o médico executante ao exame",
        "description": "Atribui o médico executante ao exame ainda não laudado pelo seu respectivo Accession Number. `crm_uf` no formato `\"<crm>-<uf>\"` (`\"12345-SP\"`); o médico precisa estar cadastrado na organização com esse CRM e UF (404 `Physician not found` se não estiver). Exame assinado responde 400.",
        "x-mobilemed": {
          "name": "setPhysician",
          "url": "/v1/exam/:accessionNumber/resident-physician",
          "group": "Exame",
          "description": "Atribui o médico executante ao exame ainda não laudado pelo seu respectivo Accesion Number"
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number do exame",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "crm_uf"
                ],
                "properties": {
                  "crm_uf": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 64,
                    "example": "12345-SP"
                  }
                }
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "crm_uf": "12345-SP"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageBody"
                },
                "examples": {
                  "themis": {
                    "summary": "Physician assigned to the exam (Themis)",
                    "value": {
                      "message": "Physician assigned to the exam"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue); Exame já assinado, sem alterações permitidas; Corpo/parâmetros inválidos (validação); crm_uf mal formado. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  },
                  "assinado": {
                    "summary": "exame já assinado",
                    "value": {
                      "message": "Exam already signed, no changes allowed"
                    }
                  },
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  },
                  "formato": {
                    "summary": "crm_uf mal formado",
                    "value": {
                      "message": "Invalid crm_uf: expected \"<crm>-<uf>\""
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo); CRM/UF sem médico cadastrado. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorMessage"
                    }
                  ]
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  },
                  "medico": {
                    "summary": "CRM/UF sem médico cadastrado",
                    "value": {
                      "message": "Physician not found"
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/{accessionNumber}/priority": {
      "post": {
        "tags": [
          "Exame"
        ],
        "operationId": "setPriority",
        "summary": "Altera a prioridade do exame",
        "description": "Atribui nova prioridade ao exame. As prioridades disponíveis são: Rotina (1), Ambulatório (2), Urgência (3), Emergência (4), Plantão (5) e — além da lista da doc — Internado (6). `priority_id` aceita número ou string. Exame assinado responde 400.",
        "x-mobilemed": {
          "name": "setPriority",
          "url": "/v1/exam/:accessionNumber/priority",
          "group": "Exame",
          "description": "Atribui nova prioridade ao exame. As prioridades disponíveis são: Rotina (1), Ambulatório (2), Urgência (3), Emergência (4), Plantão (5)"
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number do exame",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "priority_id"
                ],
                "properties": {
                  "priority_id": {
                    "oneOf": [
                      {
                        "type": "integer"
                      },
                      {
                        "type": "string"
                      }
                    ],
                    "description": "1 Rotina, 2 Ambulatório, 3 Urgência, 4 Emergência, 5 Plantão, 6 Internado"
                  }
                }
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "priority_id": "2"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageBody"
                },
                "examples": {
                  "themis": {
                    "summary": "Exam priority changed successfully (Themis)",
                    "value": {
                      "message": "Exam priority changed successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue); Exame já assinado, sem alterações permitidas; Corpo/parâmetros inválidos (validação); id fora de 1..6. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  },
                  "assinado": {
                    "summary": "exame já assinado",
                    "value": {
                      "message": "Exam already signed, no changes allowed"
                    }
                  },
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  },
                  "id": {
                    "summary": "id fora de 1..6",
                    "value": {
                      "message": "Invalid priority_id: expected one of 1, 2, 3, 4, 5, 6"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/{accessionNumber}/release": {
      "post": {
        "tags": [
          "Exame"
        ],
        "operationId": "setRelease",
        "summary": "Libera ou revoga a liberação do exame ao paciente",
        "description": "Exige laudo FINAL, SIGNED ou AMENDED e persiste worklist_items.patient_delivery_released com auditoria. release=false retém o exame nos canais de paciente (lista, detalhe, PDF, protocolo, e-mail, share e DICOM) e revoga seus links específicos; sessão do paciente e outros exames continuam. release=true permite novos links, sem reativar os revogados. Staff, integração e audiência physician continuam operacionais. O PACS revalida novas leituras de paciente, inclusive grants anteriores; qualquer item ativo retido bloqueia imagens comuns do mesmo StudyUID. Arquivos já entregues e URLs antigas de storage seguem sua validade original.",
        "x-mobilemed": {
          "name": "setRelease",
          "url": "/v1/exam/:accessionNumber/release",
          "group": "Exame",
          "description": "Libera ou revoga a liberação de um exame já assinado"
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number do exame",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "release"
                ],
                "properties": {
                  "release": {
                    "type": "boolean",
                    "description": "Aceita também \"true\"/\"false\"."
                  }
                }
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "release": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageBody"
                },
                "examples": {
                  "themis": {
                    "summary": "Exam released (Themis)",
                    "value": {
                      "message": "Exam released"
                    }
                  },
                  "revogado": {
                    "summary": "release: false",
                    "value": {
                      "message": "Exam release revoked"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue); Corpo/parâmetros inválidos (validação); exame sem laudo assinado. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  },
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  },
                  "naoAssinado": {
                    "summary": "exame sem laudo assinado",
                    "value": {
                      "message": "Exam not signed"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/exam/{accessionNumber}/description": {
      "post": {
        "tags": [
          "Exame"
        ],
        "operationId": "updateDescription",
        "summary": "Atualiza a descrição do exame",
        "description": "Atualiza a descrição do exame (até 255 caracteres). Exame assinado responde 400.",
        "x-mobilemed": {
          "name": "updateDescription",
          "url": "/v1/exam/:accessionNumber/description",
          "group": "Exame",
          "description": "Atualiza a descriçao do exame"
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number do exame",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "description"
                ],
                "properties": {
                  "description": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255
                  }
                }
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "description": "Example of a Description"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageBody"
                },
                "examples": {
                  "themis": {
                    "summary": "Description was changed successfully (Themis)",
                    "value": {
                      "message": "Description was changed successfully"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue); Exame já assinado, sem alterações permitidas; Corpo/parâmetros inválidos (validação). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  },
                  "assinado": {
                    "summary": "exame já assinado",
                    "value": {
                      "message": "Exam already signed, no changes allowed"
                    }
                  },
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/physician": {
      "get": {
        "tags": [
          "Physician"
        ],
        "operationId": "findByCrmUF",
        "summary": "Busca médico pelo CRM e UF",
        "description": "Busca por CRM e UF na organização da credencial, com assinatura visual em base64 ou null. Ambos são obrigatórios. mobilemed canonicaliza decimal + UF, produz CRM seguro positivo ou null e recusa ambiguidade; não remove pontuação nem arredonda. Legacy conserva representação anterior.",
        "x-mobilemed": {
          "name": "findByCrmUf",
          "url": "/v1/physician?crm=1234&uf=SP",
          "group": "Physician",
          "description": "Busca médico pelo CRM e UF"
        },
        "parameters": [
          {
            "name": "crm",
            "in": "query",
            "required": true,
            "description": "CRM do médico",
            "schema": {
              "type": "string",
              "maxLength": 32
            }
          },
          {
            "name": "uf",
            "in": "query",
            "required": true,
            "description": "UF do CRM do médico",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhysicianView"
                },
                "examples": {
                  "themis": {
                    "summary": "Exemplo (Themis)",
                    "value": {
                      "physician": {
                        "name": "Dr. Exemplo",
                        "crm": {
                          "code": 1234,
                          "uf": "SP"
                        },
                        "signature": "iVBORw0KGgoAAAANSUhEUgAA…"
                      }
                    }
                  },
                  "mobilemed": {
                    "summary": "Success-Response (doc MobileMed)",
                    "value": {
                      "physician": {
                        "name": "Dr. Mobilemed",
                        "crm": {
                          "code": 1234,
                          "uf": "SP"
                        },
                        "signature": "77+9UE5HDQoaCgAAAA1JSERSAAAD77+9AAAAeAgGAAAAYS3vv706AAAgAElEQVR4Xu+/vQd0XO+/vXXvv71/YO+/"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corpo/parâmetros inválidos (validação). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo); CRM/UF sem médico cadastrado. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorMessage"
                    }
                  ]
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  },
                  "medico": {
                    "summary": "CRM/UF sem médico cadastrado",
                    "value": {
                      "message": "Physician not found"
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/results/add-print-count": {
      "post": {
        "tags": [
          "Result"
        ],
        "operationId": "addPrintCount",
        "summary": "Incrementa o contador de impressão do exame",
        "description": "Incrementa atomicamente o contador do exame identificado pelo ID externo WORKLIST_ITEM numérico/decimal ou alias UUID. Sucesso 201 sem corpo. ID desconhecido ou fora do escopo retorna 400 Could not find any study.",
        "x-mobilemed": {
          "name": "addPrintCount",
          "url": "/v1/results/add-print-count",
          "group": "Result",
          "description": "Adiciona o valor do contador de impressão"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "exam_id"
                ],
                "properties": {
                  "exam_id": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      {
                        "type": "string",
                        "pattern": "^[1-9][0-9]*$"
                      },
                      {
                        "type": "string",
                        "format": "uuid"
                      }
                    ],
                    "description": "ID externo seguro como número ou texto decimal, ou alias UUID; resolução sempre na organização da credencial."
                  }
                }
              },
              "examples": {
                "themis": {
                  "summary": "Exemplo (Themis)",
                  "value": {
                    "exam_id": "6d2c1e0a-7f6b-4c1e-9a1a-3f2b5c8d9e01"
                  }
                },
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "exam_id": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Criado — sem corpo"
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue); Corpo/parâmetros inválidos (validação). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  },
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ]
      }
    },
    "/v1/results/signed/{code}": {
      "get": {
        "tags": [
          "Result"
        ],
        "operationId": "getDigitalSign",
        "summary": "Laudo e assinatura digital pelo código",
        "description": "Laudo pelo ID externo REPORT decimal ou alias UUID. mobilemed retorna HTTP 201 com os 13 campos e digital_sign completo quando há artefato SIGNED ativo da versão vigente. Validação desconhecida é null; SHA256 do PDF não prova assinatura. legacy retorna HTTP 200 com os seis campos históricos.",
        "x-mobilemed": {
          "name": "getDigitalSign",
          "url": "/v1/results/signed/:code",
          "group": "Result",
          "description": "Busca o Laudo e as informações assinadas digitalmente"
        },
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "description": "ID externo decimal REPORT ou alias UUID",
            "schema": {
              "type": "string",
              "description": "ID externo decimal REPORT ou alias UUID"
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso — perfil legacy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacySignedReport"
                },
                "examples": {
                  "themis": {
                    "summary": "Exemplo (Themis)",
                    "value": {
                      "id": "0b7e2a44-1d6f-4a3e-8c2f-5e1d2c3b4a55",
                      "exame_id": "6d2c1e0a-7f6b-4c1e-9a1a-3f2b5c8d9e01",
                      "usuario_id": "3a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
                      "html": "<p>Laudo…</p>",
                      "signed_at": "2026-09-18T15:04:00.000Z",
                      "signature": {
                        "status": "SIGNED",
                        "storage_key": "signed/0b7e2a44.pdf"
                      }
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Sucesso — perfil mobilemed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MobilemedSignedReport"
                },
                "example": {
                  "id": 102,
                  "exame_id": 101,
                  "usuario_id": null,
                  "html": "<p>Resultado sintético</p>",
                  "pdf_nome": "current.pdf",
                  "pdf_path": "https://storage.exemplo.com.br/current.pdf",
                  "data_criacao": "2026-09-20T12:00:00.000Z",
                  "data_alteracao": "2026-09-20T12:01:00.000Z",
                  "status_id": 1,
                  "data_conclusao": "2026-09-20T12:01:00.000Z",
                  "endereco_ip": null,
                  "birads": null,
                  "digital_sign": {
                    "signatureRSA": {
                      "signatureAlgorithm": null,
                      "algorithmHash": null,
                      "validation": {
                        "valid": null,
                        "description": "Verificação criptográfica não registrada."
                      }
                    },
                    "datetimeSignature": "20/09/2026 09:01:00",
                    "signatory": {
                      "holder": null,
                      "document": "12345678909",
                      "isICPBrasil": null,
                      "validation": {
                        "valid": null,
                        "description": "Validação da cadeia do certificado não registrada."
                      }
                    },
                    "timestamp": {
                      "issuer": null,
                      "dateTimeSignature": null,
                      "validation": {
                        "valid": null,
                        "description": "Carimbo do tempo não verificado."
                      }
                    },
                    "valid": null
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo); laudo inexistente. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorMessage"
                    }
                  ]
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  },
                  "laudo": {
                    "summary": "laudo inexistente",
                    "value": {
                      "message": "Report not found"
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/results/get-exams": {
      "post": {
        "tags": [
          "Result"
        ],
        "operationId": "getExams",
        "summary": "Lista os exames do paciente (CPF + nascimento)",
        "description": "Retorna os exames do paciente no portal de entregas. `cpf` e `dataNasc` (dd/mm/yyyy) são obrigatórios **juntos** — o paciente é identificado pelos dois; o CPF é comparado só por dígitos. `data` limita o período em meses a partir de hoje: 1, 3 ou 12; 0, ausente ou outro valor = sem filtro. `protocolo` (só em get-exams) filtra pelo número de protocolo exato.\n\n`status_id` usa a mesma tabela de status de `GET /v1/exam` (cancelados omitidos em mobilemed; -1 no legacy); `viewer_path` é o link público do viewer; `laudo[].pdf_path` é a URL assinada do PDF; `anexos[].file_path` a URL assinada do anexo. `id` e `empresa_id` são inteiros estáveis no perfil mobilemed; legacy mantém UUIDs.",
        "x-mobilemed": {
          "name": "getExams",
          "url": "/v1/results/get-exams",
          "group": "Result",
          "description": "Retorna os exames"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "cpf",
                  "dataNasc"
                ],
                "properties": {
                  "cpf": {
                    "type": "string",
                    "maxLength": 32,
                    "description": "CPF do paciente (só os dígitos contam)"
                  },
                  "dataNasc": {
                    "type": "string",
                    "maxLength": 10,
                    "description": "Nascimento, dd/mm/yyyy"
                  },
                  "protocolo": {
                    "type": "string",
                    "maxLength": 64,
                    "description": "Número de protocolo (opcional)"
                  },
                  "data": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Janela em meses: 1, 3 ou 12 (0/ausente = sem filtro)"
                  }
                }
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "cpf": "12345678910",
                    "dataNasc": "01/01/2000",
                    "protocolo": "ABCDE",
                    "data": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ResultExam"
                  }
                },
                "examples": {
                  "mobilemed": {
                    "summary": "Perfil mobilemed (IDs numéricos)",
                    "value": [
                      {
                        "id": 101,
                        "empresa_id": 105,
                        "status_id": 1,
                        "nome_paciente": "NOME DO PACIENTE",
                        "idade_paciente": 26,
                        "estudo_descricao": "TOMOGRAFIA DE CRANIO",
                        "data_realizacao": "2026-09-18T14:30:00.000Z",
                        "viewer_path": "https://laudos.exemplo.com.br/compartilhar/abc123",
                        "count_anexos_paciente": 1,
                        "laudo": [
                          {
                            "pdf_path": "https://storage.exemplo.com.br/laudos/0b7e2a44.pdf?X-Amz-Signature=…",
                            "status_id": 1
                          }
                        ],
                        "anexos": [
                          {
                            "file_path": "https://storage.exemplo.com.br/anexos/9f1c2d3e.pdf?X-Amz-Signature=…",
                            "is_excluido": false
                          }
                        ]
                      }
                    ]
                  },
                  "legacy": {
                    "summary": "Perfil legacy (UUIDs)",
                    "value": [
                      {
                        "id": "6d2c1e0a-7f6b-4c1e-9a1a-3f2b5c8d9e01",
                        "empresa_id": "c0ffee00-1111-4222-8333-444455556666",
                        "status_id": 1,
                        "nome_paciente": "NOME DO PACIENTE",
                        "idade_paciente": 26,
                        "estudo_descricao": "TOMOGRAFIA DE CRANIO",
                        "data_realizacao": "2026-09-18T14:30:00.000Z",
                        "viewer_path": "https://laudos.exemplo.com.br/compartilhar/abc123",
                        "count_anexos_paciente": 1,
                        "laudo": [
                          {
                            "pdf_path": "https://storage.exemplo.com.br/laudos/0b7e2a44.pdf?X-Amz-Signature=…",
                            "status_id": 1
                          }
                        ],
                        "anexos": [
                          {
                            "file_path": "https://storage.exemplo.com.br/anexos/9f1c2d3e.pdf?X-Amz-Signature=…",
                            "is_excluido": false
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corpo/parâmetros inválidos (validação); CPF sem dígitos; dataNasc fora de dd/mm/yyyy. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  },
                  "cpf": {
                    "summary": "CPF sem dígitos",
                    "value": {
                      "message": "Invalid \"cpf\": expected digits"
                    }
                  },
                  "nasc": {
                    "summary": "dataNasc fora de dd/mm/yyyy",
                    "value": {
                      "message": "Invalid \"dataNasc\": expected dd/mm/yyyy"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ]
      }
    },
    "/v1/results/get-all-exams": {
      "post": {
        "tags": [
          "Result"
        ],
        "operationId": "getAllExams",
        "summary": "Lista os exames do paciente em todo o grupo",
        "description": "Retorna os exames do paciente no portal de entregas. `cpf` e `dataNasc` (dd/mm/yyyy) são obrigatórios **juntos** — o paciente é identificado pelos dois; o CPF é comparado só por dígitos. `data` limita o período em meses a partir de hoje: 1, 3 ou 12; 0, ausente ou outro valor = sem filtro. `protocolo` (só em get-exams) filtra pelo número de protocolo exato.\n\n`status_id` usa a mesma tabela de status de `GET /v1/exam` (cancelados omitidos em mobilemed; -1 no legacy); `viewer_path` é o link público do viewer; `laudo[].pdf_path` é a URL assinada do PDF; `anexos[].file_path` a URL assinada do anexo. `id` e `empresa_id` são inteiros estáveis no perfil mobilemed; legacy mantém UUIDs.\n\n No perfil mobilemed, grupoId é o ID externo ORGANIZATION da credencial: grupo diferente ou não resolvido retorna []; omissão lista a organização atual. Legacy preserva a consulta sem filtro adicional.",
        "x-mobilemed": {
          "name": "getExams",
          "url": "/v1/results/get-all-exams",
          "group": "Result",
          "description": "Retorna os exames"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "cpf",
                  "dataNasc"
                ],
                "properties": {
                  "cpf": {
                    "type": "string",
                    "maxLength": 32,
                    "description": "CPF do paciente (só os dígitos contam)"
                  },
                  "dataNasc": {
                    "type": "string",
                    "maxLength": 10,
                    "description": "Nascimento, dd/mm/yyyy"
                  },
                  "data": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Janela em meses: 1, 3 ou 12 (0/ausente = sem filtro)"
                  },
                  "grupoId": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      {
                        "type": "string",
                        "pattern": "^[1-9][0-9]*$"
                      },
                      {
                        "type": "string",
                        "format": "uuid"
                      }
                    ],
                    "description": "ID externo seguro como número ou texto decimal, ou alias UUID; resolução sempre na organização da credencial."
                  }
                }
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "cpf": "12345678910",
                    "dataNasc": "01/01/2000",
                    "data": 1,
                    "grupoId": 1
                  },
                  "description": "O exemplo original da MobileMed não é JSON válido; `value` é a versão corrigida e `x-mobilemed-raw` o texto original."
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ResultExam"
                  }
                },
                "examples": {
                  "mobilemed": {
                    "summary": "Perfil mobilemed (IDs numéricos)",
                    "value": [
                      {
                        "id": 101,
                        "empresa_id": 105,
                        "status_id": 1,
                        "nome_paciente": "NOME DO PACIENTE",
                        "idade_paciente": 26,
                        "estudo_descricao": "TOMOGRAFIA DE CRANIO",
                        "data_realizacao": "2026-09-18T14:30:00.000Z",
                        "viewer_path": "https://laudos.exemplo.com.br/compartilhar/abc123",
                        "count_anexos_paciente": 1,
                        "laudo": [
                          {
                            "pdf_path": "https://storage.exemplo.com.br/laudos/0b7e2a44.pdf?X-Amz-Signature=…",
                            "status_id": 1
                          }
                        ],
                        "anexos": [
                          {
                            "file_path": "https://storage.exemplo.com.br/anexos/9f1c2d3e.pdf?X-Amz-Signature=…",
                            "is_excluido": false
                          }
                        ]
                      }
                    ]
                  },
                  "legacy": {
                    "summary": "Perfil legacy (UUIDs)",
                    "value": [
                      {
                        "id": "6d2c1e0a-7f6b-4c1e-9a1a-3f2b5c8d9e01",
                        "empresa_id": "c0ffee00-1111-4222-8333-444455556666",
                        "status_id": 1,
                        "nome_paciente": "NOME DO PACIENTE",
                        "idade_paciente": 26,
                        "estudo_descricao": "TOMOGRAFIA DE CRANIO",
                        "data_realizacao": "2026-09-18T14:30:00.000Z",
                        "viewer_path": "https://laudos.exemplo.com.br/compartilhar/abc123",
                        "count_anexos_paciente": 1,
                        "laudo": [
                          {
                            "pdf_path": "https://storage.exemplo.com.br/laudos/0b7e2a44.pdf?X-Amz-Signature=…",
                            "status_id": 1
                          }
                        ],
                        "anexos": [
                          {
                            "file_path": "https://storage.exemplo.com.br/anexos/9f1c2d3e.pdf?X-Amz-Signature=…",
                            "is_excluido": false
                          }
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corpo/parâmetros inválidos (validação); CPF sem dígitos; dataNasc fora de dd/mm/yyyy. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  },
                  "cpf": {
                    "summary": "CPF sem dígitos",
                    "value": {
                      "message": "Invalid \"cpf\": expected digits"
                    }
                  },
                  "nasc": {
                    "summary": "dataNasc fora de dd/mm/yyyy",
                    "value": {
                      "message": "Invalid \"dataNasc\": expected dd/mm/yyyy"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ]
      }
    },
    "/v1/results/getAllPais": {
      "get": {
        "tags": [
          "Result"
        ],
        "operationId": "getAllPais",
        "summary": "Lista a tabela de países",
        "description": "Lista de países com IDs numéricos estáveis (Brasil=1); novos países não renumeram os anteriores. HTTP 201 mobilemed e HTTP 200 legacy. O exemplo inválido da fonte é representado como array JSON.",
        "x-mobilemed": {
          "name": "getPais",
          "url": "/v1/results/getAllPais",
          "group": "Result",
          "description": "Busca o pais na tabela de pais"
        },
        "responses": {
          "200": {
            "description": "Sucesso — perfil legacy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Country"
                  }
                },
                "examples": {
                  "themis": {
                    "summary": "Exemplo (Themis)",
                    "value": [
                      {
                        "id": 1,
                        "nome": "Brasil",
                        "sigla": "BR"
                      },
                      {
                        "id": 2,
                        "nome": "Afeganistão",
                        "sigla": "AF"
                      }
                    ]
                  }
                }
              }
            }
          },
          "201": {
            "description": "Sucesso — perfil mobilemed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Country"
                  }
                },
                "examples": {
                  "themis": {
                    "summary": "Exemplo (Themis)",
                    "value": [
                      {
                        "id": 1,
                        "nome": "Brasil",
                        "sigla": "BR"
                      },
                      {
                        "id": 2,
                        "nome": "Afeganistão",
                        "sigla": "AF"
                      }
                    ]
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ]
      }
    },
    "/v1/results/report-pdf-link/{laudo_hash}": {
      "get": {
        "tags": [
          "Result"
        ],
        "operationId": "getReportPdfLink",
        "summary": "Link do PDF do laudo",
        "description": "URL assinada do PDF do laudo. laudo_hash aceita ID externo REPORT decimal ou UUID. HTTP 201 mobilemed e HTTP 200 legacy; corpo JSON válido {url}. Sem PDF: 404 Report PDF not available.",
        "x-mobilemed": {
          "name": "getReportPdfLink",
          "url": "/v1/results/report-pdf-link/:laudo_hash",
          "group": "Result",
          "description": "Busca link do laudo pelo hash"
        },
        "parameters": [
          {
            "name": "laudo_hash",
            "in": "path",
            "required": true,
            "description": "ID externo decimal REPORT ou alias UUID",
            "schema": {
              "type": "string",
              "description": "ID externo decimal REPORT ou alias UUID"
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso — perfil legacy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UrlBody"
                },
                "examples": {
                  "themis": {
                    "summary": "Exemplo (Themis)",
                    "value": {
                      "url": "https://www.exemplo.com.br/laudo/1602792111470-LQsMdB9EnUIvjvJE_jD_Tt3~VYyD70.pdf"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Sucesso — perfil mobilemed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UrlBody"
                },
                "examples": {
                  "themis": {
                    "summary": "Exemplo (Themis)",
                    "value": {
                      "url": "https://www.exemplo.com.br/laudo/1602792111470-LQsMdB9EnUIvjvJE_jD_Tt3~VYyD70.pdf"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo); laudo inexistente; laudo sem PDF gravado. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorMessage"
                    }
                  ]
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  },
                  "laudo": {
                    "summary": "laudo inexistente",
                    "value": {
                      "message": "Report not found"
                    }
                  },
                  "pdf": {
                    "summary": "laudo sem PDF gravado",
                    "value": {
                      "message": "Report PDF not available"
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/results/send-email": {
      "post": {
        "tags": [
          "Result"
        ],
        "operationId": "sendEmail",
        "summary": "Envia por e-mail o acesso do paciente ao exame",
        "description": "Envia um email sobre o exame: o mesmo e-mail de acesso ao portal de entregas que a recepção manda pela tela, para o endereço informado, sem gravar o e-mail no cadastro do paciente. Resposta 201 sem corpo.\n\n**Desvios:** `exame_id` é o ID numérico do exame ou alias UUID (o `id` de `get-exams`). Exame ainda sem paciente vinculado responde **400** com `{ \"message\": \"Exam has no linked patient\" }`.",
        "x-mobilemed": {
          "name": "sendEmail",
          "url": "/v1/results/send-email",
          "group": "Result",
          "description": "Envia um email sobre o exame"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "exame_id",
                  "email"
                ],
                "properties": {
                  "exame_id": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      {
                        "type": "string",
                        "pattern": "^[1-9][0-9]*$"
                      },
                      {
                        "type": "string",
                        "format": "uuid"
                      }
                    ],
                    "description": "ID externo seguro como número ou texto decimal, ou alias UUID; resolução sempre na organização da credencial."
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              },
              "examples": {
                "themis": {
                  "summary": "Exemplo (Themis)",
                  "value": {
                    "exame_id": "6d2c1e0a-7f6b-4c1e-9a1a-3f2b5c8d9e01",
                    "email": "paciente@exemplo.com.br"
                  }
                },
                "mobilemed": {
                  "summary": "Request-Example (doc MobileMed)",
                  "value": {
                    "exame_id": 1,
                    "email": "examplo@exemplo.com.br"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Criado — sem corpo"
          },
          "400": {
            "description": "Exame inexistente na organização da credencial (ou pertencente a outra organização — o cliente não distingue); Corpo/parâmetros inválidos (validação). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "semEstudo": {
                    "summary": "exame não encontrado",
                    "value": {
                      "message": "Could not find any study"
                    }
                  },
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ]
      }
    },
    "/v1/viewer/{accessionNumber}": {
      "get": {
        "tags": [
          "Viewer"
        ],
        "operationId": "getViewerUrl",
        "summary": "Link de acesso às imagens do exame",
        "description": "Retorna {url}. forMedic=true gera /medico/estudo/:token com audiência physician; false ou omitido gera /compartilhar/:token com audiência patient. Reuso compara audiência e includeFutureReports. Links de integração acompanham FINAL/SIGNED/AMENDED futuros exclusivamente do mesmo exame/organização, com contexto clínico mínimo e imagens antes do laudo. Shares internos restritos mantêm allowedReportIds e include_future_reports=false. Exame sem estudo, cancelado mobilemed, inexistente ou retido para audiência patient retorna 404. A página médica instala cookie DICOM antes do viewer real.",
        "x-mobilemed": {
          "name": "getViewerUrl",
          "url": "/v1/viewer/:accessionNumber",
          "group": "Viewer",
          "description": "Retorna link de acesso às imagens do exame de acordo com o Acession Number fornecido"
        },
        "parameters": [
          {
            "name": "accessionNumber",
            "in": "path",
            "required": true,
            "description": "Accession Number do exame",
            "schema": {
              "type": "string",
              "maxLength": 16
            }
          },
          {
            "name": "forMedic",
            "in": "query",
            "required": false,
            "description": "(Opcional) Link para o viewer principal dos médicos executantes. Opções disponíveis: true e false (padrão). true retorna /medico/estudo/:token, leitura médica com imagens antes do laudo e laudos finais HTML/texto/PDF; false retorna /compartilhar/:token, sujeito à liberação do paciente. O mesmo link acompanha laudos futuros exclusivamente do exame e organização autorizados.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UrlBody"
                },
                "examples": {
                  "mobilemed": {
                    "summary": "Success-Response (doc MobileMed)",
                    "value": {
                      "url": "https://link-do-viewer-publico"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corpo/parâmetros inválidos (validação). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo); exame sem imagens ou inexistente. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorEnvelope"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorMessage"
                    }
                  ]
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  },
                  "semEstudo": {
                    "summary": "exame sem imagens ou inexistente",
                    "value": {
                      "message": "Could not find any study"
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/viewer/list/bydate": {
      "get": {
        "tags": [
          "Viewer"
        ],
        "operationId": "getViewerUrlByDate",
        "summary": "Links do viewer dos exames de um período",
        "description": "Retorna o link de acesso às imagens de todos os exames realizados no período informado (janela de 1 minuto a 31 dias), paginado (20 por página, máximo 20). Só entram exames que já receberam imagens. Período fora da janela ou data mal formada responde 400 `Invalid period`.",
        "x-mobilemed": {
          "name": "getViewerUrlByDate",
          "url": "/v1/viewer/list/bydate",
          "group": "Viewer",
          "description": "Retorna o link de acesso às imagens de todos os exames realizados no período informado (janela de 1 minuto a 31 dias)"
        },
        "parameters": [
          {
            "name": "dataInicial",
            "in": "query",
            "required": true,
            "description": "Data/hora inicial do período, no formato YYYYMMDDTHHmm (ex: 20260514T0900)",
            "schema": {
              "type": "string",
              "pattern": "^\\d{8}T\\d{4}$"
            }
          },
          {
            "name": "dataFinal",
            "in": "query",
            "required": true,
            "description": "Data/hora final do período, no formato YYYYMMDDTHHmm (ex: 20260514T1000)",
            "schema": {
              "type": "string",
              "pattern": "^\\d{8}T\\d{4}$"
            }
          },
          {
            "name": "forMedic",
            "in": "query",
            "required": false,
            "description": "(Opcional) Link para o viewer principal dos médicos executantes. Opções disponíveis: true e false (padrão). true retorna /medico/estudo/:token, leitura médica com imagens antes do laudo e laudos finais HTML/texto/PDF; false retorna /compartilhar/:token, sujeito à liberação do paciente. O mesmo link acompanha laudos futuros exclusivamente do exame e organização autorizados.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "(Opcional) Página da listagem. Padrão: 1.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "description": "(Opcional) Quantidade de exames por página. Padrão: 20. Máximo: 20.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20
            }
          },
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ViewerListPage"
                },
                "examples": {
                  "mobilemed": {
                    "summary": "Success-Response (doc MobileMed)",
                    "value": {
                      "exams": [
                        {
                          "accessionNumber": "12313123",
                          "patient": {
                            "codigo_paciente": "PAC001",
                            "name": "Fulano de Tal"
                          },
                          "description": "Tomografia de crânio",
                          "studyDate": "2026-07-28",
                          "url": "https://link-do-viewer-publico"
                        }
                      ],
                      "pagination": {
                        "totalExams": 1,
                        "totalPages": 1,
                        "currentPage": 1,
                        "currentPageTotal": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corpo/parâmetros inválidos (validação); janela inválida. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "comment must be a string"
                      ],
                      "error": "Bad Request"
                    }
                  },
                  "periodo": {
                    "summary": "janela inválida",
                    "value": {
                      "message": "Invalid period"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ]
      }
    },
    "/v1/worklist": {
      "post": {
        "tags": [
          "Worklist"
        ],
        "operationId": "createWorklist",
        "summary": "Cria (ou reconfirma) um item de worklist",
        "description": "Cada chamada aceita conserva JSON completo (incluindo extras, false/0/null) ou XML original com sua estrutura parseada. Perfil mobilemed: sem adapter explícito/padrão tenta projetar os formatos MobileMed/KAI conhecidos; entrada genérica sem projeção fica RAW_ONLY, sem paciente/exame fabricado. Sucesso sempre 201 {} incluindo noop. Perfil legacy mantém validação obrigatória do DTO e corpos created 201/noop 200. Adapter selecionado pelo header adapter ou defaultWorklistAdapter da credencial deve existir e produzir projeção válida (400 caso contrário). Mapeamentos declarativos podem ser salvos e recebimentos reprocessados na administração. Conflito de identidade por accession permanece 409. Estado assinado nunca é importado por worklist.",
        "x-mobilemed": {
          "name": "createWorklist",
          "url": "/v1/worklist",
          "group": "Worklist",
          "description": "Cria um registro de worklist. O corpo pode ser enviado em JSON ou XML e aceita propriedades adicionais. Os campos abaixo representam os dados mínimos recomendados para identificar o paciente e o exame; a rota armazena o objeto recebido sem impor um schema global."
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "description": "Objeto JSON completo; campos conhecidos abaixo são recomendados. Somente legacy exige DTO global.",
                "properties": {
                  "patient_id": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "integer"
                      }
                    ],
                    "description": "Código do paciente no sistema de origem"
                  },
                  "patient_name": {
                    "type": "string",
                    "description": "Nome do paciente (obrigatório)"
                  },
                  "patient_birthdate": {
                    "type": "string",
                    "description": "yyyy-mm-dd (ou yyyymmdd)"
                  },
                  "patient_sex": {
                    "type": "string",
                    "enum": [
                      "M",
                      "F",
                      "O",
                      "U"
                    ]
                  },
                  "patient_cpf": {
                    "type": "string",
                    "description": "Só dígitos"
                  },
                  "accession_number": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "integer"
                      }
                    ],
                    "description": "Único na organização, até 16 caracteres (obrigatório)"
                  },
                  "referring_physician": {
                    "type": "string",
                    "description": "Médico solicitante"
                  },
                  "modality": {
                    "type": "string",
                    "description": "Sigla DICOM (CT, MR, MG, US, CR, DX…) (obrigatório)"
                  },
                  "study_description": {
                    "type": "string"
                  },
                  "date_exam": {
                    "type": "string",
                    "description": "yyyy-mm-dd (ou yyyymmdd) (obrigatório)"
                  },
                  "time_exam": {
                    "type": "string",
                    "description": "hh:mm:ss (ou hhmmss) (obrigatório)"
                  },
                  "insurence_plan": {
                    "type": "string",
                    "description": "Convênio (sic, grafia da MobileMed)"
                  },
                  "patient_comments": {
                    "description": "Preservado na fonte; não produz campo operacional."
                  },
                  "register_read": {
                    "description": "Preservado na fonte; não produz campo operacional."
                  }
                }
              },
              "examples": {
                "mobilemed": {
                  "summary": "Request-Example — snake_case (doc MobileMed)",
                  "value": {
                    "patient_id": 12345,
                    "patient_name": "Joao da Silva",
                    "patient_birthdate": "1985-04-12",
                    "patient_sex": "M",
                    "accession_number": 987654,
                    "referring_physician": "Dra. Maria Oliveira",
                    "modality": "CT",
                    "study_description": "Tomografia de cranio",
                    "date_exam": "2026-08-19",
                    "time_exam": "14:30:00",
                    "insurence_plan": "Particular",
                    "patient_comments": 1,
                    "patient_cpf": "12345678900",
                    "register_read": false
                  }
                },
                "pascalCase": {
                  "summary": "PascalCase (MobileWorklist / KAI / carretas)",
                  "value": {
                    "PatientId": "12345",
                    "PatientName": "JOAO DA SILVA",
                    "PatientBirthdate": "19850412",
                    "PatientSex": "M",
                    "PatientCpf": "12345678900",
                    "AccessionNumber": "ACC987654",
                    "ReferringPhysician": "Dra. Maria Oliveira",
                    "Modality": "CT",
                    "StudyDescription": "TOMOGRAFIA DE CRANIO",
                    "InsurencePlan": "Particular",
                    "Date": "20260819",
                    "Time": "143000"
                  }
                }
              }
            },
            "application/xml": {
              "schema": {
                "type": "string",
                "description": "`<worklist>` (tags snake_case) ou `<MWL_ITEM>` (tags PascalCase, Guardião Pixeon), valores em CDATA."
              },
              "examples": {
                "mobilemed": {
                  "summary": "XML-Request-Example — <worklist> (doc MobileMed)",
                  "value": "<worklist>\n  <patient_id>12345</patient_id>\n  <patient_name>Joao da Silva</patient_name>\n  <patient_birthdate>1985-04-12</patient_birthdate>\n  <patient_sex>M</patient_sex>\n  <accession_number>987654</accession_number>\n  <modality>CT</modality>\n  <study_description>Tomografia de cranio</study_description>\n  <date_exam>2026-08-19</date_exam>\n  <time_exam>14:30:00</time_exam>\n</worklist>"
                },
                "mwlItem": {
                  "summary": "<MWL_ITEM> (Guardião Pixeon)",
                  "value": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MWL_ITEM>\n   <PatientId>1</PatientId>\n   <PatientName><![CDATA[JOSÉ DA SILVA]]></PatientName>\n   <PatientBirthdate>19990131</PatientBirthdate>\n   <PatientSex>M</PatientSex>\n   <AccessionNumber>M00001</AccessionNumber>\n   <ReferringPhysician><![CDATA[Dr. MobileMed]]></ReferringPhysician>\n   <Modality>CT</Modality>\n   <StudyDescription><![CDATA[TOMOGRAFIA DE CRÂNIO]]></StudyDescription>\n   <Date>20201021</Date>\n   <Time>103155</Time>\n   <InsurencePlan>CONVENIO</InsurencePlan>\n   <PatientComments></PatientComments>\n   <PatientCpf>19119119100</PatientCpf>\n</MWL_ITEM>"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Somente legacy: repetição idempotente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorklistCreated"
                },
                "example": {
                  "accession_number": "987654",
                  "status": "noop"
                }
              }
            }
          },
          "201": {
            "description": "Mobilemed: fonte aceita (RAW_ONLY ou PROJECTED), inclusive noop. Legacy: criação.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "maxProperties": 0
                    },
                    {
                      "$ref": "#/components/schemas/WorklistCreated"
                    }
                  ]
                },
                "examples": {
                  "themis": {
                    "summary": "Criado (Themis)",
                    "value": {
                      "accession_number": "987654",
                      "status": "created"
                    }
                  },
                  "mobilemed": {
                    "summary": "Perfil mobilemed",
                    "value": {}
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos para a worklist — `message` é um array de mensagens. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "validacao": {
                    "summary": "validação do corpo",
                    "value": {
                      "message": [
                        "PatientName should not be empty",
                        "AccessionNumber must be 1..16 chars (DICOM limit)",
                        "Date must be yyyymmdd"
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token desconhecido (ou ambíguo). Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "tokenInvalido": {
                    "summary": "token não encontrado",
                    "value": {
                      "error": {
                        "message": "No integration found for the given token"
                      }
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "Header `token` ausente, ou header `api` presente com valor diferente de `one`/`mob`. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "examples": {
                  "semToken": {
                    "summary": "sem header token",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"Integration token\" not provided"
                      }
                    }
                  },
                  "apiInvalido": {
                    "summary": "header api inválido",
                    "value": {
                      "error": {
                        "error_code": 406,
                        "error_msg": "\"api\" header invalid"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Accession Number já existe na organização. Somente legacy identificado recebe statusCode, timestamp e path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorMessage"
                },
                "examples": {
                  "conflito": {
                    "summary": "accession já existe",
                    "value": {
                      "message": "Accession 987654 already exists for organization … with different fields: patientName. Either retry with the same payload or PATCH explicitly.",
                      "error": "Conflict"
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "token": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OptionalApiHeader"
          },
          {
            "name": "adapter",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Nome salvo nesta credencial, ou preset mobilemed/kai."
          }
        ]
      }
    },
    "/v1/doc": {
      "get": {
        "tags": [
          "Documentação"
        ],
        "operationId": "docHtml",
        "summary": "Esta documentação (Redoc)",
        "description": "Página HTML com esta especificação renderizada pelo Redoc. Pública — não exige credencial.",
        "responses": {
          "200": {
            "description": "HTML",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/v1/doc/openapi.json": {
      "get": {
        "tags": [
          "Documentação"
        ],
        "operationId": "docOpenApi",
        "summary": "Esta especificação em OpenAPI 3.1 (JSON)",
        "description": "O documento OpenAPI desta API, para importar em Postman/Insomnia ou gerar clientes. Pública — não exige credencial.",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        },
        "security": []
      }
    }
  },
  "webhooks": {
    "report.signed": {
      "post": {
        "tags": [
          "Webhook"
        ],
        "operationId": "reportSignedWebhook",
        "summary": "Laudo assinado — entregue na URL de retorno da credencial",
        "description": "Evento de assinatura/retificação/recebimento externo para credenciais inscritas com destino efetivo. Sem template usa {event,sentAt,study}; templates permitem qualquer JSON nativo inclusive null/false/0/string. O snapshot do template é imutável desde a geração, e o corpo HTTP é congelado na primeira preparação. Retries conservam bytes, inclusive sentAt e URLs com validade original. eventId e occurredAt nascem no RIS, não são proveniência do broker. study usa perfil atual na preparação; source é o último ingresso PROJECTED ativo do mesmo cliente/item. URL e autenticação são consultadas a cada tentativa. Cancelamento, credencial revogada ou destino removido impedem entrega. Confirmação 2xx; timeout 10 s; retries 2,4,8,16,32,64 minutos. Reintegração manual exclusiva de laudos.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/ReportCallbackPayload"
                  },
                  {}
                ],
                "description": "Sem template usa o objeto padrão; template configurado pode produzir qualquer valor JSON nativo."
              },
              "example": {
                "event": "report.signed",
                "sentAt": "2026-09-18T15:04:05.000Z",
                "study": {
                  "id": 101,
                  "accessionNumber": "12345678",
                  "studyUID": "1.2.99.1.96.99.192.168.0.218",
                  "studyDate": "2026-09-18",
                  "company": {
                    "name": "CLINICA EXEMPLO"
                  },
                  "auxiliaryField01": null,
                  "description": "TOMOGRAFIA DE CRANIO",
                  "modality": "CT",
                  "status": {
                    "id": 1,
                    "description": "Assinado"
                  },
                  "priority": {
                    "id": 1,
                    "description": "Rotina"
                  },
                  "patient": {
                    "codigo_paciente": "123456",
                    "name": "NOME DO PACIENTE",
                    "birthday": "2000-12-01",
                    "sex": "M"
                  },
                  "publicViewerUrl": "https://laudos.exemplo.com.br/compartilhar/abc123",
                  "report": {
                    "id": 102,
                    "publishedAt": "2026-09-18T15:04:00.000Z",
                    "performingPhysician": {
                      "name": "NOME DO MÉDICO EXECUTANTE",
                      "crm": {
                        "code": 123456,
                        "uf": "SP"
                      },
                      "email": "medico@exemplo.com.br"
                    },
                    "content": "https://storage.exemplo.com.br/laudos/0b7e2a44.pdf?X-Amz-Signature=…"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Entrega confirmada — o sistema terceiro recebeu o laudo."
          },
          "default": {
            "description": "Qualquer outra resposta conta como falha e agenda retry."
          }
        }
      }
    },
    "study.received": {
      "post": {
        "tags": [
          "Webhook"
        ],
        "operationId": "studyReceivedWebhook",
        "summary": "Primeiro estudo estável recebido",
        "description": "Primeiro study-stable processado após a janela de 60 segundos sem imagens, independente de vínculo anterior em study-started. mobilemed_study_receipts registra o primeiro evento mesmo sem assinantes. Ativar depois não gera callback retrospectivo; rollout não inventa histórico anterior. Recibo e eventos são transacionais e rollback permite retry. Uma notificação por organização/credencial/StudyUID. Não exige laudo. webhookUrlStudy usa fallback webhookUrlReport. Compartilha snapshot, retries e templates de report.signed.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/StudyReceivedCallbackPayload"
                  },
                  {}
                ],
                "description": "Sem template usa o objeto padrão; template configurado pode produzir qualquer valor JSON nativo."
              },
              "example": {
                "event": "study.received",
                "sentAt": "2026-09-18T15:04:05.000Z",
                "study": {
                  "id": 101,
                  "accessionNumber": "12345678",
                  "studyUID": "1.2.99.1.96.99.192.168.0.218",
                  "studyDate": "2026-09-18",
                  "company": {
                    "name": "CLINICA EXEMPLO"
                  },
                  "auxiliaryField01": null,
                  "description": "TOMOGRAFIA DE CRANIO",
                  "modality": "CT",
                  "status": {
                    "id": 0,
                    "description": "Novo"
                  },
                  "priority": {
                    "id": 1,
                    "description": "Rotina"
                  },
                  "patient": {
                    "codigo_paciente": "123456",
                    "name": "NOME DO PACIENTE",
                    "birthday": "2000-12-01",
                    "sex": "M"
                  },
                  "publicViewerUrl": "https://laudos.exemplo.com.br/compartilhar/abc123",
                  "report": null
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Entrega confirmada — o sistema terceiro recebeu o evento de estudo e seu payload."
          },
          "default": {
            "description": "Qualquer outra resposta conta como falha e agenda retry."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "token": {
        "type": "apiKey",
        "in": "header",
        "name": "token",
        "description": "Token da credencial de API da unidade (Admin → Unidades → Tokens de API). Obrigatório."
      }
    },
    "schemas": {
      "IdDescription": {
        "type": "object",
        "required": [
          "id",
          "description"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "PerformingPhysician": {
        "type": "object",
        "required": [
          "name",
          "crm",
          "email"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Nome do signatário; sem signatário cadastrado, o nome livre do laudo ou o nome da credencial"
          },
          "crm": {
            "type": "object",
            "required": [
              "code",
              "uf"
            ],
            "properties": {
              "code": {
                "oneOf": [
                  {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 9007199254740991
                  },
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "mobilemed: número seguro positivo, ou null para CRM ausente/não numérico/inseguro. legacy: representação anterior. Busca canônica com UF recusa múltiplos médicos equivalentes."
              },
              "uf": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          }
        }
      },
      "StudyReportView": {
        "type": "object",
        "required": [
          "id",
          "publishedAt",
          "performingPhysician",
          "content"
        ],
        "properties": {
          "id": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 9007199254740991,
                "title": "mobilemed"
              },
              {
                "type": "string",
                "format": "uuid",
                "title": "legacy"
              }
            ],
            "description": "Perfil mobilemed (padrão de novas credenciais): inteiro positivo estável. Perfil legacy: UUID. O cabeçalho api não seleciona perfil."
          },
          "publishedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Data/hora da assinatura"
          },
          "performingPhysician": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PerformingPhysician"
              },
              {
                "type": "null"
              }
            ]
          },
          "content": {
            "type": [
              "string",
              "null"
            ],
            "description": "Sem header `format`: URL assinada (1 h) do PDF, ou null sem PDF gravado. Com `format`: o conteúdo no formato pedido, em base64 por padrão (`base64: false` devolve texto para html/rtf/text)."
          },
          "groupedContent": {
            "type": "array",
            "items": {
              "type": "string",
              "contentEncoding": "base64"
            },
            "description": "Extensão deprecated exclusiva de legacy em group=true/format=pdf. Não existe em mobilemed; content já é o PDF único e não deve ser concatenado novamente.",
            "deprecated": true
          }
        }
      },
      "StudyPatient": {
        "type": "object",
        "required": [
          "codigo_paciente",
          "name",
          "birthday",
          "sex"
        ],
        "properties": {
          "codigo_paciente": {
            "type": [
              "string",
              "null"
            ],
            "description": "Identificador do paciente como veio na worklist (patient_id/PatientId)"
          },
          "name": {
            "type": "string"
          },
          "birthday": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "sex": {
            "type": "string",
            "enum": [
              "M",
              "F",
              "O"
            ]
          }
        }
      },
      "StudyView": {
        "type": "object",
        "description": "O `study` de `GET /v1/exam/{accessionNumber}` — e o mesmo objeto que vai no webhook `report.signed`.",
        "required": [
          "id",
          "accessionNumber",
          "studyUID",
          "studyDate",
          "company",
          "auxiliaryField01",
          "description",
          "modality",
          "status",
          "priority",
          "patient",
          "publicViewerUrl",
          "report"
        ],
        "properties": {
          "id": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 9007199254740991,
                "title": "mobilemed"
              },
              {
                "type": "string",
                "format": "uuid",
                "title": "legacy"
              }
            ],
            "description": "Perfil mobilemed (padrão de novas credenciais): inteiro positivo estável. Perfil legacy: UUID. O cabeçalho api não seleciona perfil."
          },
          "accessionNumber": {
            "type": [
              "string",
              "null"
            ]
          },
          "studyUID": {
            "type": [
              "string",
              "null"
            ],
            "description": "Study Instance UID; null enquanto as imagens não chegam"
          },
          "studyDate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Data de realização (ou agendamento), no fuso da credencial"
          },
          "company": {
            "type": "object",
            "required": [
              "name"
            ],
            "properties": {
              "name": {
                "type": "string",
                "description": "Nome da organização"
              }
            }
          },
          "auxiliaryField01": {
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "modality": {
            "type": "string"
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/IdDescription"
              }
            ],
            "description": "0 a 11 conforme procedência clínica. Cancelados são omitidos em mobilemed; legacy pode retornar -1 Cancelado."
          },
          "priority": {
            "allOf": [
              {
                "$ref": "#/components/schemas/IdDescription"
              }
            ],
            "description": "1 Rotina, 2 Ambulatório, 3 Urgência, 4 Emergência, 5 Plantão, 6 Internado"
          },
          "clinicalMarkings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IdDescription"
            },
            "description": "Somente com marcacaoClinica=true. IDs 1 a 14 derivados de fatos explícitos; 11/12 exigem BENIGN/MALIGNANT e incluem 7."
          },
          "patient": {
            "$ref": "#/components/schemas/StudyPatient"
          },
          "publicViewerUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Link público do viewer; null enquanto não há imagens"
          },
          "report": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/StudyReportView"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "StudyDetails": {
        "type": "object",
        "required": [
          "contrast",
          "subspecialty"
        ],
        "properties": {
          "contrast": {
            "type": "object",
            "required": [
              "description"
            ],
            "properties": {
              "description": {
                "type": "string",
                "description": "Campo auxiliar 02"
              }
            }
          },
          "subspecialty": {
            "type": "object",
            "required": [
              "description",
              "subspecialtyCode"
            ],
            "properties": {
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "subspecialtyCode": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Código do procedimento"
              }
            }
          }
        }
      },
      "StudyAttachment": {
        "type": "object",
        "required": [
          "anexoID",
          "mimeType",
          "arquivo"
        ],
        "properties": {
          "anexoID": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 9007199254740991,
                "title": "mobilemed"
              },
              {
                "type": "string",
                "format": "uuid",
                "title": "legacy"
              }
            ],
            "description": "Perfil mobilemed (padrão de novas credenciais): inteiro positivo estável. Perfil legacy: UUID. O cabeçalho api não seleciona perfil."
          },
          "mimeType": {
            "type": "string"
          },
          "arquivo": {
            "type": "string",
            "description": "URL assinada do anexo, ou o conteúdo em base64 com `base64: true`"
          }
        }
      },
      "StudyFullView": {
        "allOf": [
          {
            "$ref": "#/components/schemas/StudyView"
          },
          {
            "$ref": "#/components/schemas/StudyDetails"
          },
          {
            "type": "object",
            "required": [
              "comment",
              "applicantPhysician",
              "attachments"
            ],
            "properties": {
              "comment": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Último comentário do exame"
              },
              "applicantPhysician": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Médico solicitante"
              },
              "attachments": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/StudyAttachment"
                }
              }
            }
          }
        ]
      },
      "FindByStudyUidResult": {
        "type": "object",
        "required": [
          "study",
          "associatedExams"
        ],
        "properties": {
          "study": {
            "$ref": "#/components/schemas/StudyFullView"
          },
          "associatedExams": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "study"
              ],
              "properties": {
                "study": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/StudyView"
                    },
                    {
                      "$ref": "#/components/schemas/StudyDetails"
                    }
                  ]
                }
              }
            }
          }
        }
      },
      "Comment": {
        "type": "object",
        "required": [
          "comentario",
          "data_criacao",
          "data_alteracao"
        ],
        "properties": {
          "comentario": {
            "type": "string"
          },
          "data_criacao": {
            "type": "string",
            "example": "2023-03-03 02:01"
          },
          "data_alteracao": {
            "type": "string",
            "example": "2023-03-03 02:01"
          }
        }
      },
      "IntegrationLogsResult": {
        "type": "object",
        "required": [
          "totalLogs",
          "logs"
        ],
        "properties": {
          "totalLogs": {
            "type": "object",
            "required": [
              "total",
              "pages"
            ],
            "properties": {
              "total": {
                "type": "integer"
              },
              "pages": {
                "type": "integer"
              }
            }
          },
          "logs": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "accessionNumber",
                "studyIUID",
                "codigoPedido",
                "statusRetorno",
                "descricaoErro"
              ],
              "properties": {
                "accessionNumber": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "studyIUID": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "codigoPedido": {
                  "type": [
                    "integer",
                    "string",
                    "null"
                  ],
                  "description": "mobilemed: código decimal seguro ou ID EXAM_ORDER de pedido ativo comprovado; null caso indisponível. legacy: texto original."
                },
                "statusRetorno": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "description": "HTTP da chamada recebida ou da entrega do webhook"
                },
                "descricaoErro": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "codigoPedidoOriginal": {
                  "type": "string",
                  "description": "Extensão mobilemed quando o código original não pode ser representado numericamente."
                }
              }
            }
          }
        }
      },
      "ReceiveReportBody": {
        "type": "object",
        "required": [
          "reportFormat",
          "report"
        ],
        "properties": {
          "reportFormat": {
            "type": "string",
            "enum": [
              "html",
              "rtf",
              "pdf"
            ],
            "description": "Sem distinção de caixa"
          },
          "report": {
            "type": "string",
            "contentEncoding": "base64",
            "description": "Documento em base64 (ou data URL)"
          },
          "physicianCrmUf": {
            "type": "string",
            "description": "\"<crm>-<uf>\" do médico executante; obrigatório quando useIntegrationUser não é true",
            "example": "12345-SP"
          },
          "useIntegrationUser": {
            "type": "boolean",
            "description": "true: assina em nome da credencial (sem médico)"
          },
          "studyIUID": {
            "type": "string",
            "description": "Localizador quando o path traz `study` no lugar do accession"
          }
        }
      },
      "PhysicianView": {
        "type": "object",
        "required": [
          "physician"
        ],
        "properties": {
          "physician": {
            "type": "object",
            "required": [
              "name",
              "crm",
              "signature"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "crm": {
                "type": "object",
                "required": [
                  "code",
                  "uf"
                ],
                "properties": {
                  "code": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 9007199254740991
                      },
                      {
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "mobilemed: número seguro positivo, ou null para CRM ausente/não numérico/inseguro. legacy: representação anterior. Busca canônica com UF recusa múltiplos médicos equivalentes."
                  },
                  "uf": {
                    "type": "string"
                  }
                }
              },
              "signature": {
                "type": [
                  "string",
                  "null"
                ],
                "contentEncoding": "base64",
                "description": "Imagem da assinatura em base64; null sem imagem"
              }
            }
          }
        }
      },
      "ResultExam": {
        "type": "object",
        "required": [
          "id",
          "empresa_id",
          "status_id",
          "nome_paciente",
          "idade_paciente",
          "estudo_descricao",
          "data_realizacao",
          "viewer_path",
          "count_anexos_paciente",
          "laudo",
          "anexos"
        ],
        "properties": {
          "id": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 9007199254740991,
                "title": "mobilemed"
              },
              {
                "type": "string",
                "format": "uuid",
                "title": "legacy"
              }
            ],
            "description": "Perfil mobilemed (padrão de novas credenciais): inteiro positivo estável. Perfil legacy: UUID. O cabeçalho api não seleciona perfil."
          },
          "empresa_id": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 9007199254740991,
                "title": "mobilemed"
              },
              {
                "type": "string",
                "format": "uuid",
                "title": "legacy"
              }
            ],
            "description": "Perfil mobilemed (padrão de novas credenciais): inteiro positivo estável. Perfil legacy: UUID. O cabeçalho api não seleciona perfil."
          },
          "status_id": {
            "type": "integer",
            "description": "Mesma tabela de GET /v1/exam. Cancelados omitidos em mobilemed; -1 somente legacy."
          },
          "nome_paciente": {
            "type": "string"
          },
          "idade_paciente": {
            "type": [
              "integer",
              "null"
            ]
          },
          "estudo_descricao": {
            "type": "string"
          },
          "data_realizacao": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "viewer_path": {
            "type": "string",
            "description": "Link público do viewer (\"\" sem imagens)"
          },
          "count_anexos_paciente": {
            "type": "integer"
          },
          "laudo": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "pdf_path",
                "status_id"
              ],
              "properties": {
                "pdf_path": {
                  "type": "string",
                  "description": "URL assinada do PDF (\"\" sem PDF)"
                },
                "status_id": {
                  "type": "integer"
                }
              }
            }
          },
          "anexos": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "file_path",
                "is_excluido"
              ],
              "properties": {
                "file_path": {
                  "type": "string",
                  "description": "URL assinada do anexo"
                },
                "is_excluido": {
                  "type": "boolean"
                }
              }
            }
          }
        }
      },
      "SignedReport": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/MobilemedSignedReport"
          },
          {
            "$ref": "#/components/schemas/LegacySignedReport"
          }
        ],
        "description": "mobilemed é o padrão para credenciais novas; legacy é preservado para credenciais existentes."
      },
      "Country": {
        "type": "object",
        "required": [
          "id",
          "nome",
          "sigla"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "nome": {
            "type": "string",
            "example": "Brasil"
          },
          "sigla": {
            "type": "string",
            "example": "BR"
          }
        }
      },
      "ViewerListPage": {
        "type": "object",
        "required": [
          "exams",
          "pagination"
        ],
        "properties": {
          "exams": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "accessionNumber",
                "patient",
                "description",
                "studyDate",
                "url"
              ],
              "properties": {
                "accessionNumber": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "patient": {
                  "type": "object",
                  "required": [
                    "codigo_paciente",
                    "name"
                  ],
                  "properties": {
                    "codigo_paciente": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "name": {
                      "type": "string"
                    }
                  }
                },
                "description": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "studyDate": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date"
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "pagination": {
            "type": "object",
            "required": [
              "totalExams",
              "totalPages",
              "currentPage",
              "currentPageTotal"
            ],
            "properties": {
              "totalExams": {
                "type": "integer"
              },
              "totalPages": {
                "type": "integer"
              },
              "currentPage": {
                "type": "integer"
              },
              "currentPageTotal": {
                "type": "integer"
              }
            }
          }
        }
      },
      "WorklistCreated": {
        "type": "object",
        "required": [
          "accession_number",
          "status"
        ],
        "properties": {
          "accession_number": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "created",
              "noop",
              "updated"
            ]
          }
        }
      },
      "UrlBody": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "MessageBody": {
        "type": "object",
        "required": [
          "message"
        ],
        "description": "Corpo de sucesso das mutações. A doc da MobileMed mostra `{ \"frase\" }` (JSON inválido); o Themis devolve a mesma frase em `message`.",
        "properties": {
          "message": {
            "type": "string"
          }
        }
      },
      "ErrorMessage": {
        "type": "object",
        "required": [
          "message"
        ],
        "description": "Erro de negócio/validação. Mobilemed conserva o JSON específico sem statusCode, timestamp ou path. Somente legacy identificado recebe esses campos adicionais. A API interna mantém seu envelope próprio.",
        "properties": {
          "message": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "description": "Texto nas regras de negócio; array de mensagens nos erros de validação do corpo"
          },
          "error": {
            "type": "string",
            "description": "Só nos erros de validação (\"Bad Request\")"
          },
          "statusCode": {
            "type": "integer"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "path": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "ErrorEnvelope": {
        "type": "object",
        "required": [
          "error"
        ],
        "description": "Erros de autenticação MobileMed em JSON. Apenas credencial resolvida legacy recebe também statusCode,timestamp,path. Credencial ausente/desconhecida usa formato mobilemed. O envelope da API interna permanece inalterado.",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "error_code": {
                "type": "integer"
              },
              "error_msg": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "statusCode": {
            "type": "integer"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "path": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "ReportCallbackPayload": {
        "type": "object",
        "required": [
          "event",
          "sentAt",
          "study"
        ],
        "properties": {
          "event": {
            "type": "string",
            "const": "report.signed"
          },
          "sentAt": {
            "type": "string",
            "format": "date-time",
            "description": "Instante da primeira preparação; permanece idêntico no corpo congelado dos retries de eventos novos."
          },
          "study": {
            "$ref": "#/components/schemas/StudyView"
          }
        }
      },
      "LegacySignedReport": {
        "type": "object",
        "required": [
          "id",
          "exame_id",
          "usuario_id",
          "html",
          "signed_at",
          "signature"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "UUID do laudo"
          },
          "exame_id": {
            "type": "string",
            "format": "uuid"
          },
          "usuario_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Quem assinou (null para laudo externo assinado pela credencial)"
          },
          "html": {
            "type": "string"
          },
          "signed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "signature": {
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "status",
                  "storage_key"
                ],
                "properties": {
                  "status": {
                    "type": "string"
                  },
                  "storage_key": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Documento assinado ICP-Brasil mais recente; null quando só há assinatura eletrônica simples"
          }
        },
        "description": "Perfil legacy: seis campos históricos. signature identifica apenas um artefato SIGNED da versão vigente; não afirma verificação criptográfica."
      },
      "MobilemedSignedReport": {
        "type": "object",
        "required": [
          "id",
          "exame_id",
          "usuario_id",
          "html",
          "pdf_nome",
          "pdf_path",
          "data_criacao",
          "data_alteracao",
          "status_id",
          "data_conclusao",
          "endereco_ip",
          "birads",
          "digital_sign"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991
          },
          "exame_id": {
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991
          },
          "usuario_id": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "html": {
            "type": "string"
          },
          "pdf_nome": {
            "type": [
              "string",
              "null"
            ]
          },
          "pdf_path": {
            "type": [
              "string",
              "null"
            ],
            "description": "URL assinada do PDF selecionado, ou null."
          },
          "data_criacao": {
            "type": "string",
            "format": "date-time"
          },
          "data_alteracao": {
            "type": "string",
            "format": "date-time"
          },
          "status_id": {
            "type": "integer"
          },
          "data_conclusao": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "endereco_ip": {
            "type": "null",
            "description": "Não há IP de assinatura persistido; nunca usa o IP desta consulta."
          },
          "birads": {
            "type": [
              "string",
              "null"
            ]
          },
          "digital_sign": {
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "signatureRSA",
                  "datetimeSignature",
                  "signatory",
                  "timestamp",
                  "valid"
                ],
                "properties": {
                  "signatureRSA": {
                    "type": "object",
                    "required": [
                      "signatureAlgorithm",
                      "algorithmHash",
                      "validation"
                    ],
                    "properties": {
                      "signatureAlgorithm": {
                        "type": "null"
                      },
                      "algorithmHash": {
                        "type": "null"
                      },
                      "validation": {
                        "type": "object",
                        "required": [
                          "valid",
                          "description"
                        ],
                        "properties": {
                          "valid": {
                            "type": "null",
                            "description": "null: verificação não registrada; nenhum booleano é inferido de status ou hash do arquivo."
                          },
                          "description": {
                            "type": "string",
                            "example": "Verificação criptográfica não registrada."
                          }
                        }
                      }
                    }
                  },
                  "datetimeSignature": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Horário de conclusão registrado pelo serviço, no fuso da credencial (dd/MM/yyyy HH:mm:ss). Não é timestamp extraído do certificado ou de TSA."
                  },
                  "signatory": {
                    "type": "object",
                    "required": [
                      "holder",
                      "document",
                      "isICPBrasil",
                      "validation"
                    ],
                    "properties": {
                      "holder": {
                        "type": "null"
                      },
                      "document": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "description": "signerIdentification persistido da sessão SafeID; não vem do nome mutável do usuário."
                      },
                      "isICPBrasil": {
                        "type": "null"
                      },
                      "validation": {
                        "type": "object",
                        "required": [
                          "valid",
                          "description"
                        ],
                        "properties": {
                          "valid": {
                            "type": "null",
                            "description": "null: verificação não registrada; nenhum booleano é inferido de status ou hash do arquivo."
                          },
                          "description": {
                            "type": "string",
                            "example": "Validação da cadeia do certificado não registrada."
                          }
                        }
                      }
                    }
                  },
                  "timestamp": {
                    "type": "object",
                    "required": [
                      "issuer",
                      "dateTimeSignature",
                      "validation"
                    ],
                    "properties": {
                      "issuer": {
                        "type": "null"
                      },
                      "dateTimeSignature": {
                        "type": "null"
                      },
                      "validation": {
                        "type": "object",
                        "required": [
                          "valid",
                          "description"
                        ],
                        "properties": {
                          "valid": {
                            "type": "null",
                            "description": "null: verificação não registrada; nenhum booleano é inferido de status ou hash do arquivo."
                          },
                          "description": {
                            "type": "string",
                            "example": "Carimbo do tempo não verificado."
                          }
                        }
                      }
                    }
                  },
                  "valid": {
                    "type": "null"
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "description": "Perfil mobilemed: 13 campos. Somente documento SIGNED ativo, da mesma organização/laudo/versão, com storage e signedAt, em laudo finalizado. Validações sem evidência criptográfica persistida permanecem null. Falha posterior não apaga sucesso vigente; versão antiga não valida HTML novo."
      },
      "StudyReceivedCallbackPayload": {
        "type": "object",
        "required": [
          "event",
          "sentAt",
          "study"
        ],
        "properties": {
          "event": {
            "type": "string",
            "const": "study.received"
          },
          "sentAt": {
            "type": "string",
            "format": "date-time",
            "description": "Instante da primeira preparação; permanece idêntico no corpo congelado dos retries de eventos novos."
          },
          "study": {
            "$ref": "#/components/schemas/StudyView"
          }
        }
      }
    },
    "parameters": {
      "OptionalApiHeader": {
        "name": "api",
        "in": "header",
        "required": false,
        "description": "Opcional; quando presente, aceita one ou mob.",
        "schema": {
          "type": "string",
          "enum": [
            "one",
            "mob"
          ]
        }
      }
    }
  },
  "x-administrative-contract": "docs/integrations/mobilemed-compat/worklist-admin.openapi.json",
  "x-shared-reading-contract": "docs/integrations/mobilemed-compat/shared-study-reading.openapi.json"
}
