> ## Documentation Index
> Fetch the complete documentation index at: https://docs.telepatia.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Sesiones en Vivo

> Transmita el audio de la consulta en tiempo real y reciba el registro generado

Una sesión en vivo le permite transmitir una consulta mientras ocurre. Usted crea la sesión con una llamada REST, recibe una URL de WebSocket, envía el audio mientras el médico habla y recibe el registro médico generado cuando termina la consulta.

Use esto cuando capture audio en tiempo real. Cuando ya tenga una grabación finalizada, use el flujo de [Consultas](/es/scribe-api/consultations).

## Cómo funciona

1. `POST /v1/scribe-sessions/live` devuelve una URL de WebSocket.
2. Conéctese a esa URL y transmita el audio a medida que se captura.
3. Envíe `stop_recording` cuando termine la consulta.
4. El webhook `scribe_session.completed` ([webhooks](/es/scribe-api/webhooks)) le indica que el registro está listo.
5. Obtenga el registro desde [Documentos de Registro Médico](/es/scribe-api/medical-record-documents).

## Qué debe tener la clave API

La clave que use aquí necesita las tres condiciones siguientes, o la llamada falla con `403`:

* El permiso `scribe:write`, otorgado de forma explícita. Una clave antigua sin el claim de permisos funciona en otros endpoints, pero aquí se rechaza; regenere la clave para obtener una válida.
* El rol `doctor`.
* Un vínculo con una institución.

## Crear una sesión

El cuerpo de la solicitud lleva el contexto de la consulta: cuál es la consulta, qué plantilla se completa, a qué paciente pertenece y el contexto escrito que usted ya tenga.

```bash theme={null}
curl -X POST https://scribe-api.telepatia.ai/v1/scribe-sessions/live \
  -H "Authorization: Bearer SU_CLAVE_API" \
  -H "Content-Type: application/json" \
  -d '{
    "consultation": { "id": "CONSULT-12345", "modality": "IN_PERSON" },
    "template": { "id": "mrc_a1b2c3d4e5f6g7h8" },
    "patient": { "id": "sp_a1b2c3d4e5f6g7h8" },
    "context": {
      "notes": "Patient reports headache since Monday.",
      "pastMedicalHistory": "Hypertension diagnosed 2020."
    }
  }'
```

**Respuesta:**

```json theme={null}
{
  "consultation": { "id": "CONSULT-12345" },
  "status": "created",
  "live": {
    "url": "wss://audio.telepatia.ai/v1/ws/audio/b0cf283f-ab53-51ea-8313-f9c90b38fd1f?token=eyJhbGciOi...",
    "expiresAt": "2026-08-13T22:14:49+00:00"
  }
}
```

Trate `live.url` como opaca y manéjela como un secreto. Conéctese exactamente a la URL devuelta y no la construya usted mismo: el host, la ruta y la credencial cambian sin aviso.

La credencial se verifica solo cuando el socket se abre. Una conexión establecida antes de `expiresAt` sigue transmitiendo después de ese instante, y una conexión intentada después se rechaza, así que solicite una sesión nueva en lugar de reutilizar una URL vencida.

### Campos de la solicitud

| Campo                        | Obligatorio | Notas                                                                                                |
| ---------------------------- | ----------- | ---------------------------------------------------------------------------------------------------- |
| `consultation.id`            | sí          | Su propio id de consulta. Es la clave de idempotencia y el id con el que obtiene el registro después |
| `consultation.modality`      | no          | `IN_PERSON` o `TELEMEDICINE`. `DICTATION` se rechaza aquí: un informe dictado tiene su propio flujo  |
| `template`                   | sí          | Un id o el JSON de la plantilla. Vea abajo                                                           |
| `patient`                    | sí          | Un paciente existente por id, o la identidad del paciente en línea. Vea abajo                        |
| `context.notes`              | no          | Texto libre, hasta 10000 caracteres, usado en la generación del registro                             |
| `context.pastMedicalHistory` | no          | Texto libre, hasta 10000 caracteres, usado en la generación del registro                             |

### Elegir la plantilla

`template` acepta **un id o el propio JSON de la plantilla**. Envíe exactamente uno de los dos.

| Campo               | Envíe esto cuando                                                                                                                                                                                       |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `template.id`       | La plantilla ya existe en Telepatia. Use el id público de una [Smart Template](/es/scribe-api/smart-templates) (`mrc_...`) o de una [Plantilla de Sesión](/es/scribe-api/session-templates) (`ssc_...`) |
| `template.sections` | Su sistema es dueño de la plantilla. Envíe la estructura en línea, sin paso de registro                                                                                                                 |

Enviar ambos, o ninguno, devuelve `400` con `param` igual a `template`.

La forma en línea:

```json theme={null}
{
  "consultation": { "id": "CONSULT-12345", "modality": "IN_PERSON" },
  "template": {
    "sections": {
      "chiefComplaint": {
        "schema": { "type": "string", "instructions": "El motivo principal de consulta del paciente." },
        "systemPrompt": "Resuma el motivo de consulta."
      },
      "assessment": {
        "schema": { "type": "string", "instructions": "Evaluación clínica y plan." },
        "systemPrompt": "Escriba la evaluación y el plan."
      }
    }
  },
  "patient": { "id": "sp_a1b2c3d4e5f6g7h8" }
}
```

La plantilla en línea se almacena la primera vez que la envía y se reutiliza después: secciones idénticas resuelven a la misma plantilla por hash de contenido, así que enviarla en cada consulta no crea duplicados. El formato de las secciones es el mismo documentado en [Smart Templates](/es/scribe-api/smart-templates), incluidos objetos anidados, arreglos y enums.

### Identificar al paciente

`patient` también acepta **un id o la identidad en línea**. Envíe exactamente uno.

```json theme={null}
{
  "patient": {
    "name": "John Doe",
    "document": { "country": "BR", "type": "CPF", "value": "123.456.789-00" }
  }
}
```

La forma en línea crea al paciente cuando aún no existe, así que no necesita llamar antes a la API de [Pacientes](/es/scribe-api/patients).

### Reintentar la misma consulta

Llamar al endpoint de nuevo con el mismo `consultation.id` mientras la sesión sigue grabando devuelve la misma sesión con una URL **nueva**. Esa es la forma admitida de recuperarse de una conexión caída. No compare las dos URL entre sí y no almacene la primera. Una vez detenida la grabación, el mismo id devuelve `409`.

## Enviar audio

Conéctese a `live.url`. El servidor envía un mensaje `ready` cuando está preparado para recibir audio.

Envíe el audio como **frames binarios de WebSocket**. Se aceptan dos formatos:

| Formato      | Requisito                                     |
| ------------ | --------------------------------------------- |
| PCM en bruto | 16 kHz, mono, 16 bits con signo little-endian |
| Opus         | Dentro de un contenedor Ogg o WebM            |

<Warning>
  El PCM en bruto no se inspecciona. Si envía otra frecuencia de muestreo o número de canales, el audio se acepta y se transcribe de forma incorrecta, sin error. Un archivo WAV se acepta de la misma manera: su encabezado no se analiza, así que los primeros bytes se convierten en un breve ruido y el resto se transcribe con normalidad. Envíe solo las muestras, sin el encabezado.
</Warning>

Envíe aproximadamente 100 ms de audio por frame, al ritmo en que se captura. Una carga PCM menor a 1024 bytes (cerca de 32 ms) se conserva en la grabación, pero no se reenvía al reconocedor en vivo, así que los frames muy pequeños retrasan el texto que usted ve en lugar de perder audio.

### Mantener la conexión viva

Envíe `{"type": "ping", "data": {}}` cuando quiera confirmar que el socket está sano; el servidor responde con `{"type": "pong", "data": {}}`. Cualquier frame entrante, incluido el audio, cuenta como actividad. Una sesión que no recibe nada durante **15 minutos** es cerrada por el servidor, así que envíe audio de forma continua, o haga ping durante las pausas largas.

<Warning>
  Un socket por sesión. Abrir una segunda conexión para la misma sesión expulsa a la primera: el socket anterior deja de recibir transcripciones. Reconéctese después de una caída, pero nunca transmita la misma consulta desde dos lugares a la vez.
</Warning>

## Mensajes que usted recibe

Cada mensaje es JSON con un campo `type` y un campo `data`.

| Tipo               | Significado                                                                           |
| ------------------ | ------------------------------------------------------------------------------------- |
| `ready`            | El servidor está preparado para recibir audio                                         |
| `transcript`       | Texto reconocido hasta ahora. `data.is_final` marca un segmento estable               |
| `correction`       | Un segmento de transcripción refinado que reemplaza el texto anterior de ese segmento |
| `scribe_completed` | El audio fue aceptado y el registro se está generando. `data.status` es `processing`  |
| `scribe_error`     | La generación falló para esta sesión                                                  |
| `reconnect`        | El servidor le pide reconectarse. `data.reason` indica por qué                        |
| `error`            | Algo falló. Reintente solo cuando `data.retriable` sea verdadero                      |
| `pong`             | Respuesta a su `ping`                                                                 |

Una `correction` reemplaza lo que un `transcript` informó para el mismo segmento. Cuando muestre texto a un médico, aplique las correcciones a medida que llegan.

`reconnect` lleva dos motivos. `server_draining` significa que el servidor se está reiniciando: reconéctese y siga transmitiendo. `resume_upload` significa que la detención llegó antes que todo el audio: reconéctese y envíe el audio que falta.

## Finalizar la sesión

Envíe este mensaje cuando termine la consulta:

```json theme={null}
{ "type": "stop_recording", "data": {} }
```

El servidor termina de procesar el audio que tiene, envía `scribe_completed` con `data.status` igual a `processing` y cierra la conexión.

<Warning>
  `stop_recording` es lo único que produce un registro. Si el socket simplemente se cierra sin él, el audio se conserva pero no se genera nada, ningún webhook se dispara y la consulta queda sin terminar. Envíelo siempre, incluso cuando el médico cancela.
</Warning>

<Tip>
  El socket no entrega el registro médico. `scribe_completed` significa que la generación comenzó, no que terminó. Espere el webhook `scribe_session.completed` y luego obtenga el registro.
</Tip>

## Recibir el registro

El webhook `scribe_session.completed` incluye `consultationInternalId`, el mismo `consultation.id` que usted envió. Obtenga el registro con él:

```bash theme={null}
curl https://scribe-api.telepatia.ai/v1/scribe-sessions/CONSULT-12345/medical-record-documents \
  -H "Authorization: Bearer SU_CLAVE_API"
```

La finalización suele llegar dentro del minuto siguiente a `stop_recording`. La generación ocurre en parte mientras el audio se transmite, así que una consulta más larga no tarda proporcionalmente más en terminar.

<Warning>
  El webhook se dispara unos segundos antes de que el documento se pueda consultar. Si su primera lectura devuelve una lista vacía, espere 5 segundos y vuelva a leer.
</Warning>

## Pérdida de conexión

Reconectarse es esperado y seguro.

* **El socket se cae durante la grabación.** Llame de nuevo a `POST /v1/scribe-sessions/live` con el mismo `consultation.id` y conéctese a la URL devuelta. El audio ya recibido se conserva.
* **`live.url` llega a `expiresAt`.** Solicite una sesión nueva con el mismo `consultation.id`. Un socket ya abierto no se ve afectado.
* **Cierre 1013.** Reintentable: el servidor está ocupado o reiniciando. Espere un momento y reconéctese.
* **Cierre 1003.** El audio no se pudo decodificar. La sesión pasa a estado de error, así que reconectarse no la recupera. Corrija el codificador y comience una consulta nueva.
* **Cierre 1008.** Terminal: la credencial o la sesión no son válidas. No se reconecte; reintentar devuelve el mismo resultado.

## Errores

| Estado | Significado                                                                                                                                                    |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | El cuerpo es inválido. `param` indica el campo                                                                                                                 |
| `401`  | La clave API falta o es inválida                                                                                                                               |
| `403`  | La clave API no tiene `scribe:write`, el rol `doctor`, o el vínculo con una institución                                                                        |
| `404`  | `param` `template.id`: la plantilla no existe. `param` `patient.id`: el paciente no existe. `param` `consultation.id`: ese id no está disponible para su clave |
| `409`  | `param` `consultation.id`: el id pertenece a otra consulta, o esta ya detuvo la grabación. `param` `template.id`: la plantilla existe pero no está activa      |
| `413`  | El cuerpo JSON supera 1 MiB. Una `template.sections` en línea muy grande puede alcanzarlo. `param` es `body`                                                   |
| `503`  | Las sesiones en vivo no están disponibles. Reintente con backoff                                                                                               |

Consulte [Errores](/es/scribe-api/errors) para el envelope completo de respuesta.
