{
  "openapi": "3.1.0",
  "info": {
    "title": "OmniMed Consulta API",
    "version": "1.0.0",
    "summary": "De la grabación de una consulta a la nota clínica, los pedidos y las sugerencias, en un solo resultado.",
    "description": "OmniMed Consulta procesa la grabación completa de una consulta médica (médico, paciente y acompañantes)\ny devuelve, en un único JSON:\n\n- la **nota de la consulta** en el formato elegido (SOAP por defecto), donde cada oración cita el\n  momento de la conversación del que sale;\n- los **pedidos** que hizo el médico (laboratorio, imágenes, otros estudios, derivaciones, terapias,\n  procedimientos), cada uno con un **borrador de orden** listo para completar en su plataforma;\n- las **sugerencias** para el médico (diagnósticos para considerar con razones a favor y en contra,\n  controles de seguridad de los pedidos, chequeos de guías clínicas), que nunca cambian la nota por sí solas;\n- los **códigos CIE-10** propuestos para la evaluación;\n- la **transcripción** con el rol de cada hablante y sus tiempos.\n\nSi se envía la historia clínica del paciente, el resultado la usa como contexto: trae los antecedentes\nrelevantes citados y marca las **discrepancias** entre lo dicho hoy y lo registrado (por ejemplo,\n\"no toma medicación\" frente a un tratamiento activo). La nota clínica sale solo de lo dicho en la\nconsulta de hoy: la historia nunca entra en sus secciones como si se hubiera dicho.\n\n## Cómo se usa\n\n1. Tu servidor envía el audio con `POST /api/consulta/v1/consultations` y recibe `202` con el `id`.\n2. Consultás `GET /api/consulta/v1/consultations/{id}` hasta que `status` sea `done` (o `failed`).\n3. Mostrás el resultado en tu sistema. Las decisiones del médico (aceptar una sugerencia, editar la\n   nota, firmar las órdenes) ocurren en tu sistema, no en el nuestro.\n\nEl procesamiento es asíncrono porque una consulta larga tarda más de lo que una conexión HTTP espera.\nRecomendamos consultar cada 5 segundos durante el primer minuto y después cada 15 segundos.\n\n## Autenticación\n\nCada llamada lleva la **Partner Credential** (`omp_...`) como `Authorization: Bearer`. Es un secreto\nde servidor a servidor: nunca debe llegar al navegador ni a una app instalada. Está habilitada para\nuna lista de centros y, en cada centro, para los productos contratados; una credencial de Dictado no\nsirve para Consulta salvo que el centro tenga Consulta habilitada. Si se filtra, pedinos rotarla: la\ncredencial vieja deja de funcionar en menos de 60 segundos.\n\n## El médico (usuario declarado)\n\nTu sistema ya autenticó al médico; nos decís en cada llamada quién es con `doctor_id` (tu propio\nidentificador) y, si querés, nombre, matrícula y especialidad. No creamos usuarios. Sin matrícula, el\nborrador de orden la marca como faltante.\n\n## Datos del paciente\n\nNo hace falta identificar al paciente. Podés enviar datos opcionales que mejoran el resultado\n(edad, sexo, cobertura) y una referencia opaca tuya para correlacionar. Los campos que no conocemos\nse ignoran. Los datos de identidad del paciente (nombre, documento) los completa tu sistema sobre el\nborrador de orden.\n\n## Historia clínica\n\nOpcional, en el campo `history`, organizada por secciones (problemas, alergias, medicación,\nlaboratorio, informes de imágenes, consultas previas). Cada registro lleva tu propio `id`: las citas\ndel resultado (`source_ids`) usan esos mismos ids, así podés enlazar cada antecedente o discrepancia\nal registro de tu sistema. La historia que enviás se usa solo para esa consulta: nunca se mezcla con\notra consulta ni con otro paciente.\n\n## Consentimiento\n\nGrabar una consulta requiere el consentimiento del paciente. Al enviar `consent=true` tu sistema\ndeclara que el paciente aceptó ser grabado; sin eso la consulta se rechaza.\n\n## Datos y seguridad\n\n- Todo el tráfico va cifrado (TLS). Nuestros servidores y bases de datos están alojados en la Unión Europea.\n- El audio se procesa y no se conserva salvo que el contrato del centro lo pida.\n- Qué más se conserva (transcripción, nota, resultado) y por cuánto tiempo se define en el contrato con cada centro.\n- La lista de subprocesadores y sus condiciones se entrega bajo acuerdo de confidencialidad.\n\n## Límites\n\n- Audio: hasta 100 MB por archivo; formatos m4a, mp3, wav, webm y ogg. Una consulta de 15 minutos en\n  m4a pesa alrededor de 15 MB.\n- Historia clínica: hasta 1 MB de JSON; textos de más de 8.000 caracteres se recortan.\n- Datos del paciente: hasta 1 MB de JSON.\n- El tiempo de procesamiento depende de la duración del audio; no hay un tiempo garantizado.\n\n## Facturación\n\nCada consulta procesada con éxito cuenta como una consulta. Reenviar con la misma `Idempotency-Key`,\nun fallo de nuestro lado y generar indicaciones para el paciente no cuentan.\n\n## Errores\n\nTodo error responde `{\"detail\": {\"code\": \"...\", \"message\": \"...\"}}`. El `code` es estable y es lo que\ntu código debe comparar; el `message` es para personas y puede cambiar.\n",
    "contact": {
      "name": "Soporte Omnimed AI",
      "url": "https://omniai.com.ar"
    }
  },
  "servers": [
    {
      "url": "https://api.omniai.com.ar"
    }
  ],
  "security": [
    {
      "partnerCredential": []
    }
  ],
  "tags": [
    {
      "name": "Consultas",
      "description": "Enviar una consulta y obtener su resultado."
    },
    {
      "name": "Catálogo",
      "description": "Formatos de nota disponibles."
    }
  ],
  "paths": {
    "/api/consulta/v1/consultations": {
      "post": {
        "tags": [
          "Consultas"
        ],
        "operationId": "createConsultation",
        "summary": "Enviar una consulta para procesar",
        "description": "Recibe la grabación completa y responde de inmediato con el `id`; el procesamiento sigue en segundo\nplano. Con la misma `Idempotency-Key` podés reenviar sin crear otra consulta: si la primera sigue en\nproceso o terminó, vuelve esa misma (200); si falló, o lleva más de 10 minutos sin avanzar, se\nprocesa de nuevo con el audio de este envío y responde 202 con el mismo `id`. Sin\n`Idempotency-Key`, cada envío crea una consulta nueva.\n",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Identificador único de este envío, generado por tu sistema (recomendado un UUID). Hasta 255 caracteres. Sin ella, cada envío crea una consulta nueva.",
            "schema": {
              "type": "string",
              "maxLength": 255
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CreateConsultationRequest"
              },
              "encoding": {
                "audio": {
                  "contentType": "audio/*"
                },
                "dictation": {
                  "contentType": "audio/*"
                },
                "patient": {
                  "contentType": "application/json"
                },
                "history": {
                  "contentType": "application/json"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reenvío con una `Idempotency-Key` ya usada; devuelve la consulta existente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Consultation"
                }
              }
            }
          },
          "202": {
            "description": "Consulta aceptada; se está procesando. También es la respuesta a un reenvío que reprocesa una consulta fallida o trabada (mismo `id`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Consultation"
                },
                "example": {
                  "id": "3f6c1d2e-8a4b-4c7e-9f10-2b5d6e7a8c90",
                  "status": "processing",
                  "stage": "transcribing",
                  "medical_center_id": "9b2f4c1a-6d3e-4f5a-8b7c-1d2e3f4a5b6c",
                  "doctor": {
                    "id": "med-1042",
                    "name": "Dra. Ana Pérez",
                    "license": "MP 12345",
                    "specialty": "Clínica médica"
                  },
                  "patient_ref": "hc-998877",
                  "note_format": "soap",
                  "created_at": "2026-11-03T13:05:12Z",
                  "completed_at": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidAudio"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "La `Idempotency-Key` ya se usó para otro centro (cada credencial tiene sus propias keys).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": {
                    "code": "idempotency_key_conflict",
                    "message": "Esa Idempotency-Key ya se usó en otro envío."
                  }
                }
              }
            }
          },
          "413": {
            "description": "El archivo supera los 100 MB. Esta respuesta puede llegar sin cuerpo JSON."
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/consulta/v1/consultations/{consultation_id}": {
      "get": {
        "tags": [
          "Consultas"
        ],
        "operationId": "getConsultation",
        "summary": "Obtener el estado y el resultado de una consulta",
        "description": "Mientras `status` es `processing`, `stage` indica en qué paso va y los campos del resultado vienen\nvacíos. Con `done`, trae todo el resultado. Con `failed`, `error` dice por qué; reenviá con la misma\n`Idempotency-Key` para reintentar.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/ConsultationId"
          }
        ],
        "responses": {
          "200": {
            "description": "La consulta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Consultation"
                },
                "examples": {
                  "done": {
                    "$ref": "#/components/examples/DoneConsultation"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/consulta/v1/consultations/{consultation_id}/instructions": {
      "post": {
        "tags": [
          "Consultas"
        ],
        "operationId": "createPatientInstructions",
        "summary": "Generar indicaciones para el paciente",
        "description": "Reescribe el Plan de la nota en lenguaje simple para que el paciente se lo lleve (por ejemplo, por\nWhatsApp o impreso). No agrega nada que no esté en la nota. Llamarlo de nuevo genera una versión\nnueva, que reemplaza a la anterior en `patient_instructions`. No cuenta como consulta.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/ConsultationId"
          }
        ],
        "responses": {
          "200": {
            "description": "Indicaciones generadas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "patient_instructions"
                  ],
                  "properties": {
                    "patient_instructions": {
                      "type": "string",
                      "description": "Texto plano, en segunda persona, para el paciente."
                    }
                  }
                },
                "example": {
                  "patient_instructions": "Vas a hacerte un análisis de sangre y una ecografía de abdomen. Cuando tengas los resultados, volvé a la consulta.\nConsultá a la guardia si tenés fiebre alta, dolor fuerte en la panza o si la panza se pone dura de golpe.\n"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "La consulta todavía no terminó de procesarse o falló.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": {
                    "code": "consultation_not_done",
                    "message": "La consulta todavía no está lista."
                  }
                }
              }
            }
          },
          "422": {
            "description": "La nota no tiene Plan del que partir.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": {
                    "code": "plan_empty",
                    "message": "La nota no tiene indicaciones en el Plan."
                  }
                }
              }
            }
          },
          "502": {
            "description": "No se pudieron generar; reintentar.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "detail": {
                    "code": "generation_failed",
                    "message": "No se pudieron generar las indicaciones; reintentá."
                  }
                }
              }
            }
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/consulta/v1/note-formats": {
      "get": {
        "tags": [
          "Catálogo"
        ],
        "operationId": "listNoteFormats",
        "summary": "Listar los formatos de nota",
        "description": "Los formatos en los que se puede escribir la nota, con sus secciones en orden.",
        "responses": {
          "200": {
            "description": "Formatos disponibles.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "formats"
                  ],
                  "properties": {
                    "formats": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NoteFormat"
                      }
                    }
                  }
                },
                "example": {
                  "formats": [
                    {
                      "id": "soap",
                      "name": "SOAP",
                      "sections": [
                        {
                          "key": "subjective",
                          "title": "Subjetivo"
                        },
                        {
                          "key": "objective",
                          "title": "Objetivo"
                        },
                        {
                          "key": "assessment",
                          "title": "Evaluación"
                        },
                        {
                          "key": "plan",
                          "title": "Plan"
                        }
                      ]
                    },
                    {
                      "id": "pediatric_checkup",
                      "name": "Control pediátrico",
                      "sections": [
                        {
                          "key": "reason",
                          "title": "Motivo de consulta"
                        },
                        {
                          "key": "growth",
                          "title": "Crecimiento y desarrollo"
                        },
                        {
                          "key": "feeding",
                          "title": "Alimentación y hábitos"
                        },
                        {
                          "key": "vaccines",
                          "title": "Vacunas"
                        },
                        {
                          "key": "exam",
                          "title": "Examen físico"
                        },
                        {
                          "key": "plan",
                          "title": "Indicaciones"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "partnerCredential": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "omp_...",
        "description": "Partner Credential emitida por Omnimed AI, habilitada por centro y producto. Solo de servidor a servidor."
      }
    },
    "parameters": {
      "ConsultationId": {
        "name": "consultation_id",
        "in": "path",
        "required": true,
        "description": "El `id` devuelto al crear la consulta.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "schemas": {
      "CreateConsultationRequest": {
        "type": "object",
        "required": [
          "audio",
          "medical_center_id",
          "doctor_id",
          "consent"
        ],
        "properties": {
          "audio": {
            "type": "string",
            "format": "binary",
            "description": "La grabación completa de la consulta (médico, paciente y acompañantes)."
          },
          "dictation": {
            "type": "string",
            "format": "binary",
            "description": "Opcional. Lo que el médico dicta solo, después de que el paciente se fue. Se suma a la misma\nconsulta; si contradice a la conversación, prevalece el dictado.\n"
          },
          "medical_center_id": {
            "type": "string",
            "description": "El centro por el que actuás (su id o su slug en Omnimed AI). Tiene que estar habilitado para Consulta en tu credencial."
          },
          "doctor_id": {
            "type": "string",
            "maxLength": 255,
            "description": "Tu identificador del médico que grabó la consulta."
          },
          "doctor_name": {
            "type": "string",
            "maxLength": 255,
            "description": "Nombre del médico, como debe figurar en el borrador de orden."
          },
          "doctor_license": {
            "type": "string",
            "maxLength": 100,
            "description": "Matrícula del médico. Sin ella, el borrador de orden la marca como faltante."
          },
          "doctor_specialty": {
            "type": "string",
            "maxLength": 255
          },
          "consent": {
            "type": "boolean",
            "description": "Tiene que ser `true`. Declara que el paciente aceptó ser grabado."
          },
          "note_format": {
            "type": "string",
            "default": "soap",
            "description": "Uno de los `id` de `GET /api/consulta/v1/note-formats`."
          },
          "num_speakers": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10,
            "description": "Cantidad esperada de personas que hablan. Si no se envía, se detecta sola."
          },
          "patient": {
            "$ref": "#/components/schemas/PatientContext"
          },
          "history": {
            "$ref": "#/components/schemas/ProvidedHistory"
          }
        }
      },
      "PatientContext": {
        "type": "object",
        "description": "Opcional, como JSON. Sin datos de identidad. Los campos que no conocemos se ignoran, y también un\ncampo conocido cuyo valor no respeta el schema (por ejemplo `sex: \"F\"`, `age: 200` o una fecha mal\nescrita): se descarta ese campo y se usa el resto. Guardamos solo los campos de este schema. Hasta 1 MB.\n",
        "additionalProperties": true,
        "properties": {
          "ref": {
            "type": "string",
            "maxLength": 255,
            "description": "Referencia opaca de tu sistema (por ejemplo, el número de historia clínica). Se devuelve como `patient_ref`; no la usamos para unir consultas."
          },
          "birth_date": {
            "type": "string",
            "format": "date"
          },
          "age": {
            "type": "integer",
            "minimum": 0,
            "maximum": 130,
            "description": "Si se envía `birth_date`, se usa esa."
          },
          "sex": {
            "type": "string",
            "enum": [
              "female",
              "male",
              "other",
              "unknown"
            ]
          },
          "coverage": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "description": "Obra social o prepaga."
              },
              "plan": {
                "type": "string"
              },
              "affiliate_number": {
                "type": "string"
              }
            }
          }
        }
      },
      "ProvidedHistory": {
        "type": "object",
        "description": "Opcional, como JSON. La historia clínica del paciente para esta consulta. Todas las secciones son\nopcionales. Cada registro lleva tu `id`, que vuelve en las citas (`source_ids`). Hasta 1 MB.\n",
        "properties": {
          "problems": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "text"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "text": {
                  "type": "string",
                  "description": "El problema, como lo lista tu sistema (ej. \"Hipertensión arterial\")."
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "resolved"
                  ],
                  "default": "active"
                },
                "code": {
                  "type": "string",
                  "description": "Código con su sistema, si lo tiene (ej. \"CIE-10 I10\")."
                },
                "onset": {
                  "type": "string",
                  "format": "date"
                }
              }
            }
          },
          "allergies": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "substance"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "substance": {
                  "type": "string"
                },
                "reaction": {
                  "type": "string"
                }
              }
            }
          },
          "medications": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "name"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "dose": {
                  "type": "string",
                  "description": "Dosis y frecuencia en texto (ej. \"10 mg cada 12 h\")."
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "suspended"
                  ],
                  "default": "active"
                },
                "since": {
                  "type": "string",
                  "format": "date"
                }
              }
            }
          },
          "labs": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "name",
                "value",
                "date"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                },
                "unit": {
                  "type": "string"
                },
                "ref_range": {
                  "type": "string",
                  "description": "Rango de referencia en texto (ej. \"70-110\")."
                },
                "date": {
                  "type": "string",
                  "format": "date"
                }
              }
            }
          },
          "imaging_reports": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "study",
                "date",
                "text"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "study": {
                  "type": "string"
                },
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "text": {
                  "type": "string",
                  "description": "Texto del informe."
                },
                "conclusion": {
                  "type": "string"
                }
              }
            }
          },
          "visits": {
            "type": "array",
            "description": "Consultas previas.",
            "items": {
              "type": "object",
              "required": [
                "id",
                "date"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "reason": {
                  "type": "string"
                },
                "summary": {
                  "type": "string",
                  "description": "Resumen o evolución de esa consulta."
                }
              }
            }
          }
        }
      },
      "Consultation": {
        "type": "object",
        "required": [
          "id",
          "status",
          "stage",
          "medical_center_id",
          "doctor",
          "note_format",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "done",
              "failed"
            ]
          },
          "stage": {
            "type": "string",
            "enum": [
              "transcribing",
              "identifying_speakers",
              "writing_note",
              "done",
              "failed"
            ],
            "description": "Paso actual mientras `status` es `processing`. Puede crecer con pasos nuevos; tratá un valor desconocido como \"procesando\"."
          },
          "error": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ErrorBody"
              },
              {
                "type": "null"
              }
            ],
            "description": "Solo con `status` = `failed`. Códigos y mensajes:\n- `audio_empty`: \"La grabación no tiene voz. Revisá que el micrófono no haya estado silenciado.\"\n- `processing_failed`: \"No se pudo procesar la consulta; reenviala con la misma Idempotency-Key.\"\n- `processing_timeout` (más de 10 minutos sin avanzar): \"El procesamiento se interrumpió; reenviala con la misma Idempotency-Key.\"\nEn los tres casos podés reenviar con la misma `Idempotency-Key`. Un código que no conozcas\ntrae el mensaje \"No se pudo procesar la consulta.\".\n"
          },
          "medical_center_id": {
            "type": "string",
            "description": "El id del centro, aunque lo hayas enviado por su slug."
          },
          "doctor": {
            "$ref": "#/components/schemas/DeclaredDoctor"
          },
          "patient_ref": {
            "type": [
              "string",
              "null"
            ]
          },
          "note_format": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "audio_seconds": {
            "type": [
              "number",
              "null"
            ],
            "description": "Duración del audio procesado."
          },
          "note": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Note"
              },
              {
                "type": "null"
              }
            ]
          },
          "orders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Order"
            }
          },
          "suggestions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Suggestion"
            }
          },
          "diagnosis_codes": {
            "type": "array",
            "description": "Códigos CIE-10 propuestos para la evaluación (hasta 4).",
            "items": {
              "$ref": "#/components/schemas/DiagnosisCode"
            }
          },
          "transcript": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Transcript"
              },
              {
                "type": "null"
              }
            ]
          },
          "patient_instructions": {
            "type": [
              "string",
              "null"
            ],
            "description": "Las últimas indicaciones generadas con `POST .../instructions`, si las hay."
          }
        }
      },
      "DeclaredDoctor": {
        "type": "object",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "license": {
            "type": [
              "string",
              "null"
            ]
          },
          "specialty": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Note": {
        "type": "object",
        "required": [
          "format",
          "sections",
          "history_context",
          "discrepancies"
        ],
        "properties": {
          "format": {
            "type": "string"
          },
          "sections": {
            "type": "array",
            "description": "Las secciones del formato, en orden. Cada oración sale de lo dicho hoy y cita los turnos de la transcripción.",
            "items": {
              "type": "object",
              "required": [
                "key",
                "title",
                "sentences"
              ],
              "properties": {
                "key": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "sentences": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "text",
                      "turn_ids"
                    ],
                    "properties": {
                      "text": {
                        "type": "string"
                      },
                      "turn_ids": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Turnos de `transcript.turns` de los que sale la oración."
                      }
                    }
                  }
                }
              }
            }
          },
          "history_context": {
            "type": "array",
            "description": "Antecedentes de la historia enviada que son relevantes hoy, cada uno citando tus registros. Vacío sin historia.",
            "items": {
              "type": "object",
              "required": [
                "text",
                "source_ids"
              ],
              "properties": {
                "text": {
                  "type": "string"
                },
                "source_ids": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Los `id` de tus registros en `history`."
                }
              }
            }
          },
          "discrepancies": {
            "type": "array",
            "description": "Lo dicho hoy que contradice la historia enviada; cita el turno y el registro. Nunca se resuelve sola.",
            "items": {
              "type": "object",
              "required": [
                "text",
                "turn_ids",
                "source_ids"
              ],
              "properties": {
                "text": {
                  "type": "string"
                },
                "turn_ids": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "source_ids": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      },
      "Order": {
        "type": "object",
        "description": "Un pedido que hizo el médico, citado a sus propias palabras. Lo que pide el paciente sin que el médico lo indique no es un pedido.",
        "required": [
          "id",
          "kind",
          "name",
          "said_as",
          "status",
          "needs_detail",
          "turn_ids",
          "missing"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "lab",
              "imaging",
              "other_study",
              "referral",
              "therapy",
              "procedure"
            ]
          },
          "name": {
            "type": "string",
            "description": "Nombre clínico, como en una orden (ej. \"Ecografía abdominal\")."
          },
          "said_as": {
            "type": "string",
            "description": "Las palabras textuales del médico."
          },
          "details": {
            "type": "string",
            "description": "Lateralidad, región, contraste, determinaciones, sesiones; solo si se dijeron."
          },
          "indication": {
            "type": "string",
            "description": "El motivo del pedido, solo si el médico lo dijo."
          },
          "status": {
            "type": "string",
            "enum": [
              "firm",
              "conditional",
              "in_visit"
            ],
            "description": "`firm`: lo pide ahora. `conditional`: depende de algo futuro (\"si sale positivo...\"). `in_visit`: se hace durante la consulta."
          },
          "needs_detail": {
            "type": "boolean",
            "description": "Falta algo imprescindible para emitir la orden."
          },
          "detail_question": {
            "type": "string",
            "description": "Qué falta, como pregunta corta para el médico."
          },
          "detail_options": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Entre 2 y 4 respuestas posibles a `detail_question`."
          },
          "turn_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "missing": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "detail",
                "diagnosis",
                "clinical_data",
                "doctor_license"
              ]
            },
            "description": "Lo que falta para que el borrador de orden esté completo."
          },
          "draft": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/OrderDraft"
              },
              {
                "type": "null"
              }
            ],
            "description": "Solo para pedidos `firm`."
          }
        }
      },
      "OrderDraft": {
        "type": "object",
        "description": "Lo que una plataforma de órdenes necesita, armado a partir del pedido y la nota. Nunca es una orden\nválida por sí misma: el médico la completa y la firma en tu sistema. Los datos del paciente\n(nombre, documento, cobertura) los agrega tu sistema.\n",
        "required": [
          "study",
          "presumptive_diagnosis",
          "clinical_data",
          "cie10_codes"
        ],
        "properties": {
          "study": {
            "type": "string",
            "description": "Estudio con sus detalles."
          },
          "presumptive_diagnosis": {
            "type": [
              "string",
              "null"
            ],
            "description": "De la evaluación de la nota; `null` si falta."
          },
          "clinical_data": {
            "type": [
              "string",
              "null"
            ],
            "description": "Datos clínicos que justifican el pedido; `null` si faltan."
          },
          "cie10_codes": {
            "type": "array",
            "maxItems": 2,
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Suggestion": {
        "type": "object",
        "description": "Una propuesta para el médico sobre la consulta de hoy. No cambia nada por sí sola: el médico decide\nen tu sistema. Cada una explica por qué y cita sus fuentes.\n",
        "required": [
          "id",
          "kind",
          "severity",
          "title",
          "sources",
          "ai_generated"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "diagnosis_to_consider",
              "safety",
              "duplicate",
              "low_value",
              "missing_check",
              "unrecorded_problem",
              "pending_follow_up"
            ],
            "description": "- `diagnosis_to_consider`: un diagnóstico que el médico podría considerar, con razones a favor y en contra.\n- `safety`: un pedido contraindicado para este paciente (ej. contraste tras una reacción previa).\n- `duplicate`: el mismo estudio ya figura en la historia enviada.\n- `low_value`: una guía desaconseja ese pedido en esta situación.\n- `missing_check`: un chequeo de una guía clínica que no aparece en la consulta.\n- `unrecorded_problem`: algo dicho hoy que no figura como problema en la historia.\n- `pending_follow_up`: un control que la historia deja pendiente.\nPuede crecer con tipos nuevos; ignorá los que no conozcas.\n"
          },
          "severity": {
            "type": "string",
            "enum": [
              "red",
              "amber",
              "info"
            ],
            "description": "`red`: revisar antes de cerrar la consulta. `amber`: conviene revisar. `info`: informativa."
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "question": {
            "type": "string",
            "description": "Pregunta para el médico, si la sugerencia la tiene."
          },
          "order_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "El pedido al que se refiere, si se refiere a uno."
          },
          "proposed_actions": {
            "type": "array",
            "description": "Acciones que la sugerencia propone, para que las muestres; aplicarlas es decisión del médico en tu sistema.",
            "items": {
              "type": "object",
              "required": [
                "key",
                "label"
              ],
              "properties": {
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                }
              }
            }
          },
          "reasons_for": {
            "type": "array",
            "description": "Solo en `diagnosis_to_consider`.",
            "items": {
              "$ref": "#/components/schemas/CitedReason"
            }
          },
          "reasons_against": {
            "type": "array",
            "description": "Solo en `diagnosis_to_consider`.",
            "items": {
              "$ref": "#/components/schemas/CitedReason"
            }
          },
          "sources": {
            "type": "object",
            "required": [
              "turn_ids",
              "source_ids"
            ],
            "properties": {
              "turn_ids": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "source_ids": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Los `id` de tus registros en `history`."
              },
              "guideline": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "title": {
                    "type": "string"
                  },
                  "url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "version": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "ai_generated": {
            "type": "boolean",
            "description": "`true` cuando la sugerencia la redacta un modelo de IA (hoy, los diagnósticos para considerar); `false` cuando sale de una regla clínica explícita."
          }
        }
      },
      "CitedReason": {
        "type": "object",
        "required": [
          "text",
          "turn_ids"
        ],
        "properties": {
          "text": {
            "type": "string"
          },
          "turn_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "DiagnosisCode": {
        "type": "object",
        "required": [
          "code",
          "description"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Código CIE-10 normalizado (ej. \"K52.9\")."
          },
          "description": {
            "type": "string"
          }
        }
      },
      "Transcript": {
        "type": "object",
        "required": [
          "turns"
        ],
        "properties": {
          "turns": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "speaker_id",
                "role",
                "segment",
                "text"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Lo que citan `turn_ids`."
                },
                "speaker_id": {
                  "type": "string"
                },
                "role": {
                  "type": "string",
                  "enum": [
                    "doctor",
                    "patient",
                    "companion",
                    "unknown"
                  ],
                  "description": "`companion`: quien acompaña al paciente; lo que dice entra en la nota como referido por un familiar. `unknown`: no se pudo asignar."
                },
                "segment": {
                  "type": "string",
                  "enum": [
                    "conversation",
                    "dictation"
                  ],
                  "description": "`dictation`: el dictado posterior del médico."
                },
                "text": {
                  "type": "string"
                },
                "start": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "description": "Segundos desde el inicio de su audio."
                },
                "end": {
                  "type": [
                    "number",
                    "null"
                  ]
                }
              }
            }
          }
        }
      },
      "NoteFormat": {
        "type": "object",
        "required": [
          "id",
          "name",
          "sections"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "sections": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "key",
                "title"
              ],
              "properties": {
                "key": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ErrorBody": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Estable; compará contra este valor."
          },
          "message": {
            "type": "string",
            "description": "Para personas; puede cambiar."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "detail"
        ],
        "properties": {
          "detail": {
            "$ref": "#/components/schemas/ErrorBody"
          }
        }
      }
    },
    "responses": {
      "InvalidAudio": {
        "description": "El audio falta, pesa menos de 1 KB, su formato no está soportado o su extensión no coincide con el contenido.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "detail": {
                "code": "invalid_audio",
                "message": "Formato de audio no soportado."
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Credencial ausente (`unauthenticated`), desconocida (`invalid_partner_credential`) o revocada\n(`partner_credential_revoked`).\n",
        "headers": {
          "WWW-Authenticate": {
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "detail": {
                "code": "invalid_partner_credential",
                "message": "Partner Credential desconocida."
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "La credencial no está habilitada para ese centro (`center_not_enabled`) o el centro no tiene\nConsulta habilitada para tu credencial (`product_not_enabled`).\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "detail": {
                "code": "product_not_enabled",
                "message": "La Partner Credential no está habilitada para Consulta en el centro 'centro-ejemplo'."
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "La consulta no existe, no es de tu credencial o su centro ya no tiene Consulta habilitada para tu credencial (`consultation_not_found`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "detail": {
                "code": "consultation_not_found",
                "message": "No existe esa consulta."
              }
            }
          }
        }
      },
      "ValidationFailed": {
        "description": "Algún campo no es válido. Códigos: `medical_center_id_required`, `consent_required`,\n`doctor_id_required`, `invalid_doctor` (un campo del médico supera su largo máximo),\n`unknown_note_format`, `invalid_patient` (no es JSON, no es un objeto o supera 1 MB; un campo con\nun valor inválido no da error, se descarta),\n`invalid_history` (no es JSON, supera 1 MB o un registro no respeta el schema: campos obligatorios,\nfechas, valores permitidos o ids repetidos en una sección), `invalid_num_speakers`,\n`invalid_idempotency_key` (supera 255 caracteres).\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "detail": {
                "code": "consent_required",
                "message": "Falta el consentimiento del paciente (consent=true)."
              }
            }
          }
        }
      },
      "Unavailable": {
        "description": "No pudimos verificar la credencial (`partner_lookup_unavailable`) o el modelo de IA no está disponible\npor un momento (`llm_unavailable`); reintentá con espera creciente.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "detail": {
                "code": "partner_lookup_unavailable",
                "message": "No se pudo verificar la Partner Credential; reintentar."
              }
            }
          }
        }
      }
    },
    "examples": {
      "DoneConsultation": {
        "summary": "Consulta procesada",
        "value": {
          "id": "3f6c1d2e-8a4b-4c7e-9f10-2b5d6e7a8c90",
          "status": "done",
          "stage": "done",
          "error": null,
          "medical_center_id": "9b2f4c1a-6d3e-4f5a-8b7c-1d2e3f4a5b6c",
          "doctor": {
            "id": "med-1042",
            "name": "Dra. Ana Pérez",
            "license": "MP 12345",
            "specialty": "Clínica médica"
          },
          "patient_ref": "hc-998877",
          "note_format": "soap",
          "created_at": "2026-11-03T13:05:12Z",
          "completed_at": "2026-11-03T13:06:40Z",
          "audio_seconds": 312.4,
          "note": {
            "format": "soap",
            "sections": [
              {
                "key": "subjective",
                "title": "Subjetivo",
                "sentences": [
                  {
                    "text": "Dolor abdominal de 2 días de evolución, con diarrea, sin vómitos.",
                    "turn_ids": [
                      "t2",
                      "t4"
                    ]
                  },
                  {
                    "text": "Refiere cefalea leve.",
                    "turn_ids": [
                      "t4"
                    ]
                  }
                ]
              },
              {
                "key": "objective",
                "title": "Objetivo",
                "sentences": [
                  {
                    "text": "Dolor que se irradia a fosa ilíaca derecha.",
                    "turn_ids": [
                      "t8"
                    ]
                  }
                ]
              },
              {
                "key": "assessment",
                "title": "Evaluación",
                "sentences": [
                  {
                    "text": "Se sospecha cuadro quirúrgico a descartar.",
                    "turn_ids": [
                      "t9"
                    ]
                  }
                ]
              },
              {
                "key": "plan",
                "title": "Plan",
                "sentences": [
                  {
                    "text": "Laboratorio con enzimas y ecografía abdominal; control con resultados.",
                    "turn_ids": [
                      "t9"
                    ]
                  },
                  {
                    "text": "Pautas de alarma: fiebre alta, dolor abdominal intenso o abdomen duro.",
                    "turn_ids": [
                      "t11"
                    ]
                  }
                ]
              }
            ],
            "history_context": [
              {
                "text": "Alergia a penicilina registrada.",
                "source_ids": [
                  "alg-17"
                ]
              }
            ],
            "discrepancies": []
          },
          "orders": [
            {
              "id": "o1",
              "kind": "lab",
              "name": "Laboratorio",
              "said_as": "te vamos a sacar sangre, quiero ver si tenés elevadas algunas enzimas",
              "details": "Enzimas",
              "indication": "Descartar cuadro quirúrgico",
              "status": "firm",
              "needs_detail": true,
              "detail_question": "¿Qué determinaciones?",
              "detail_options": [
                "Hemograma",
                "Hepatograma",
                "Amilasa",
                "Lipasa"
              ],
              "turn_ids": [
                "t9"
              ],
              "missing": [
                "detail"
              ],
              "draft": {
                "study": "Laboratorio, Enzimas",
                "presumptive_diagnosis": "Dolor abdominal, se sospecha cuadro quirúrgico",
                "clinical_data": "Dolor abdominal de 2 días con irradiación a fosa ilíaca derecha.",
                "cie10_codes": [
                  "R10.3"
                ]
              }
            },
            {
              "id": "o2",
              "kind": "imaging",
              "name": "Ecografía abdominal",
              "said_as": "vamos a hacer un eco rápido como para descartar que no sea el apéndice",
              "details": "",
              "indication": "Descartar apendicitis",
              "status": "firm",
              "needs_detail": false,
              "detail_question": "",
              "detail_options": [],
              "turn_ids": [
                "t9"
              ],
              "missing": [],
              "draft": {
                "study": "Ecografía abdominal",
                "presumptive_diagnosis": "Dolor abdominal, se sospecha cuadro quirúrgico",
                "clinical_data": "Dolor abdominal de 2 días con irradiación a fosa ilíaca derecha.",
                "cie10_codes": [
                  "R10.3"
                ]
              }
            }
          ],
          "suggestions": [
            {
              "id": "s1",
              "kind": "diagnosis_to_consider",
              "severity": "info",
              "title": "Gastroenteritis aguda",
              "body": "",
              "question": "",
              "order_id": null,
              "proposed_actions": [
                {
                  "key": "add_to_assessment",
                  "label": "Agregar a la evaluación"
                },
                {
                  "key": "dismiss",
                  "label": "Descartar"
                }
              ],
              "reasons_for": [
                {
                  "text": "Diarrea de 2 días",
                  "turn_ids": [
                    "t4"
                  ]
                }
              ],
              "reasons_against": [
                {
                  "text": "Dolor que se irradia a fosa ilíaca derecha",
                  "turn_ids": [
                    "t8"
                  ]
                }
              ],
              "sources": {
                "turn_ids": [
                  "t4",
                  "t8"
                ],
                "source_ids": [],
                "guideline": null
              },
              "ai_generated": true
            }
          ],
          "diagnosis_codes": [
            {
              "code": "R10.3",
              "description": "Dolor localizado en otras partes inferiores del abdomen"
            }
          ],
          "transcript": {
            "turns": [
              {
                "id": "t1",
                "speaker_id": "speaker_0",
                "role": "doctor",
                "segment": "conversation",
                "text": "Hola, ¿cómo andás?",
                "start": 0.4,
                "end": 1.6
              },
              {
                "id": "t2",
                "speaker_id": "speaker_1",
                "role": "patient",
                "segment": "conversation",
                "text": "Vengo porque tengo dolor de panza hace dos días.",
                "start": 1.8,
                "end": 5.2
              }
            ]
          },
          "patient_instructions": null
        }
      }
    }
  }
}
