> ## 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.

# Sessões ao Vivo

> Transmita o áudio da consulta em tempo real e receba o registro gerado

Uma sessão ao vivo permite transmitir uma consulta enquanto ela acontece. Você cria a sessão com uma chamada REST, recebe uma URL de WebSocket, envia o áudio enquanto o médico fala e recebe o registro médico gerado quando a consulta termina.

Use isto quando capturar áudio em tempo real. Quando você já tiver uma gravação finalizada, use o fluxo de [Consultas](/pt-BR/scribe-api/consultations).

## Como funciona

1. `POST /v1/scribe-sessions/live` devolve uma URL de WebSocket.
2. Conecte-se a essa URL e transmita o áudio conforme ele é capturado.
3. Envie `stop_recording` quando a consulta terminar.
4. O webhook `scribe_session.completed` ([webhooks](/pt-BR/scribe-api/webhooks)) avisa que o registro está pronto.
5. Busque o registro em [Documentos de Registro Médico](/pt-BR/scribe-api/medical-record-documents).

## O que a chave de API precisa ter

A chave usada aqui precisa das três condições abaixo, ou a chamada falha com `403`:

* A permissão `scribe:write`, concedida de forma explícita. Uma chave antiga sem o claim de permissões funciona em outros endpoints, mas é recusada aqui; gere a chave de novo para obter uma válida.
* O papel `doctor`.
* Um vínculo com uma instituição.

## Criar uma sessão

O corpo da requisição carrega o contexto da consulta: qual é a consulta, qual modelo será preenchido, a qual paciente ela pertence e o contexto escrito que você já tiver.

```bash theme={null}
curl -X POST https://scribe-api.telepatia.ai/v1/scribe-sessions/live \
  -H "Authorization: Bearer SUA_CHAVE_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."
    }
  }'
```

**Resposta:**

```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 e trate-a como um segredo. Conecte-se exatamente à URL devolvida e não a construa por conta própria: o host, o caminho e a credencial mudam sem aviso.

A credencial é verificada apenas quando o socket abre. Uma conexão estabelecida antes de `expiresAt` continua transmitindo depois desse instante, e uma conexão tentada depois é recusada, então peça uma sessão nova em vez de reutilizar uma URL vencida.

### Campos da requisição

| Campo                        | Obrigatório | Observações                                                                                       |
| ---------------------------- | ----------- | ------------------------------------------------------------------------------------------------- |
| `consultation.id`            | sim         | Seu próprio id de consulta. É a chave de idempotência e o id com que você busca o registro depois |
| `consultation.modality`      | não         | `IN_PERSON` ou `TELEMEDICINE`. `DICTATION` é recusado aqui: um laudo ditado tem o próprio fluxo   |
| `template`                   | sim         | Um id ou o JSON do modelo. Veja abaixo                                                            |
| `patient`                    | sim         | Um paciente existente por id, ou a identidade do paciente em linha. Veja abaixo                   |
| `context.notes`              | não         | Texto livre, até 10000 caracteres, usado na geração do registro                                   |
| `context.pastMedicalHistory` | não         | Texto livre, até 10000 caracteres, usado na geração do registro                                   |

### Escolher o modelo

`template` aceita **um id ou o próprio JSON do modelo**. Envie exatamente um dos dois.

| Campo               | Envie isto quando                                                                                                                                                                                    |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `template.id`       | O modelo já existe na Telepatia. Use o id público de um [Smart Template](/pt-BR/scribe-api/smart-templates) (`mrc_...`) ou de um [Modelo de Sessão](/pt-BR/scribe-api/session-templates) (`ssc_...`) |
| `template.sections` | Seu sistema é dono do modelo. Envie a estrutura em linha, sem etapa de registro                                                                                                                      |

Enviar os dois, ou nenhum, devolve `400` com `param` igual a `template`.

A forma em linha:

```json theme={null}
{
  "consultation": { "id": "CONSULT-12345", "modality": "IN_PERSON" },
  "template": {
    "sections": {
      "chiefComplaint": {
        "schema": { "type": "string", "instructions": "A queixa principal do paciente." },
        "systemPrompt": "Resuma a queixa principal."
      },
      "assessment": {
        "schema": { "type": "string", "instructions": "Avaliação clínica e conduta." },
        "systemPrompt": "Escreva a avaliação e a conduta."
      }
    }
  },
  "patient": { "id": "sp_a1b2c3d4e5f6g7h8" }
}
```

O modelo em linha é armazenado na primeira vez que você o envia e reutilizado depois: seções idênticas resolvem para o mesmo modelo por hash de conteúdo, então enviá-lo em toda consulta não cria duplicatas. O formato das seções é o mesmo documentado em [Smart Templates](/pt-BR/scribe-api/smart-templates), incluindo objetos aninhados, arrays e enums.

### Identificar o paciente

`patient` também aceita **um id ou a identidade em linha**. Envie exatamente um.

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

A forma em linha cria o paciente quando ele ainda não existe, então você não precisa chamar antes a API de [Pacientes](/pt-BR/scribe-api/patients).

### Repetir a mesma consulta

Chamar o endpoint de novo com o mesmo `consultation.id` enquanto a sessão ainda está gravando devolve a mesma sessão com uma URL **nova**. Essa é a forma suportada de se recuperar de uma conexão perdida. Não compare as duas URLs entre si e não armazene a primeira. Depois que a gravação para, o mesmo id devolve `409`.

## Enviar áudio

Conecte-se a `live.url`. O servidor envia uma mensagem `ready` quando está pronto para receber áudio.

Envie o áudio como **frames binários de WebSocket**. Dois formatos são aceitos:

| Formato   | Requisito                                     |
| --------- | --------------------------------------------- |
| PCM bruto | 16 kHz, mono, 16 bits com sinal little-endian |
| Opus      | Dentro de um contêiner Ogg ou WebM            |

<Warning>
  O PCM bruto não é inspecionado. Se você enviar outra taxa de amostragem ou número de canais, o áudio é aceito e transcrito de forma incorreta, sem erro. Um arquivo WAV é aceito do mesmo jeito: o cabeçalho dele não é lido, então os primeiros bytes viram um ruído curto e o restante é transcrito normalmente. Envie apenas as amostras, sem o cabeçalho.
</Warning>

Envie cerca de 100 ms de áudio por frame, no ritmo em que ele é capturado. Uma carga PCM menor que 1024 bytes (cerca de 32 ms) é mantida na gravação, mas não é encaminhada ao reconhecedor ao vivo, então frames muito pequenos atrasam o texto que você vê em vez de perder áudio.

### Manter a conexão viva

Envie `{"type": "ping", "data": {}}` quando quiser confirmar que o socket está saudável; o servidor responde com `{"type": "pong", "data": {}}`. Qualquer frame recebido, inclusive áudio, conta como atividade. Uma sessão que não recebe nada por **15 minutos** é fechada pelo servidor, então envie áudio continuamente, ou faça ping durante pausas longas.

<Warning>
  Um socket por sessão. Abrir uma segunda conexão para a mesma sessão expulsa a primeira: o socket anterior para de receber transcrições. Reconecte depois de uma queda, mas nunca transmita a mesma consulta de dois lugares ao mesmo tempo.
</Warning>

## Mensagens que você recebe

Toda mensagem é JSON com um campo `type` e um campo `data`.

| Tipo               | Significado                                                                         |
| ------------------ | ----------------------------------------------------------------------------------- |
| `ready`            | O servidor está pronto para receber áudio                                           |
| `transcript`       | Texto reconhecido até agora. `data.is_final` marca um segmento estável              |
| `correction`       | Um segmento de transcrição refinado que substitui o texto anterior daquele segmento |
| `scribe_completed` | O áudio foi aceito e o registro está sendo gerado. `data.status` é `processing`     |
| `scribe_error`     | A geração falhou para esta sessão                                                   |
| `reconnect`        | O servidor pede que você reconecte. `data.reason` diz o motivo                      |
| `error`            | Algo falhou. Repita apenas quando `data.retriable` for verdadeiro                   |
| `pong`             | Resposta ao seu `ping`                                                              |

Uma `correction` substitui o que um `transcript` informou para o mesmo segmento. Quando exibir texto para um médico, aplique as correções conforme elas chegam.

`reconnect` carrega dois motivos. `server_draining` significa que o servidor está reiniciando: reconecte e continue transmitindo. `resume_upload` significa que a parada chegou antes de todo o áudio: reconecte e envie o áudio que falta.

## Encerrar a sessão

Envie esta mensagem quando a consulta terminar:

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

O servidor termina de processar o áudio que possui, envia `scribe_completed` com `data.status` igual a `processing` e fecha a conexão.

<Warning>
  `stop_recording` é a única coisa que produz um registro. Se o socket simplesmente fechar sem ele, o áudio é preservado mas nada é gerado, nenhum webhook dispara e a consulta fica inacabada. Envie sempre, inclusive quando o médico cancela.
</Warning>

<Tip>
  O socket não entrega o registro médico. `scribe_completed` significa que a geração começou, não que terminou. Aguarde o webhook `scribe_session.completed` e então busque o registro.
</Tip>

## Receber o registro

O webhook `scribe_session.completed` carrega `consultationInternalId`, o mesmo `consultation.id` que você enviou. Busque o registro com ele:

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

A conclusão costuma chegar dentro do minuto seguinte ao `stop_recording`. A geração acontece em parte enquanto o áudio é transmitido, então uma consulta mais longa não demora proporcionalmente mais para terminar.

<Warning>
  O webhook dispara alguns segundos antes de o documento ficar disponível para consulta. Se a primeira leitura devolver uma lista vazia, aguarde 5 segundos e leia novamente.
</Warning>

## Perda de conexão

Reconectar é esperado e seguro.

* **O socket cai durante a gravação.** Chame `POST /v1/scribe-sessions/live` de novo com o mesmo `consultation.id` e conecte-se à URL devolvida. O áudio já recebido é preservado.
* **`live.url` chega ao `expiresAt`.** Peça uma sessão nova com o mesmo `consultation.id`. Um socket já aberto não é afetado.
* **Fechamento 1013.** Repetível: o servidor está ocupado ou reiniciando. Aguarde um momento e reconecte.
* **Fechamento 1003.** O áudio não pôde ser decodificado. A sessão vai para estado de erro, então reconectar não a recupera. Corrija o codificador e comece uma consulta nova.
* **Fechamento 1008.** Terminal: a credencial ou a sessão não é válida. Não reconecte; repetir devolve o mesmo resultado.

## Erros

| Status | Significado                                                                                                                                                    |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | O corpo é inválido. `param` indica o campo                                                                                                                     |
| `401`  | A chave de API está ausente ou é inválida                                                                                                                      |
| `403`  | A chave de API não tem `scribe:write`, o papel `doctor`, ou o vínculo com uma instituição                                                                      |
| `404`  | `param` `template.id`: o modelo não existe. `param` `patient.id`: o paciente não existe. `param` `consultation.id`: esse id não está disponível para sua chave |
| `409`  | `param` `consultation.id`: o id pertence a outra consulta, ou esta já parou de gravar. `param` `template.id`: o modelo existe mas não está ativo               |
| `413`  | O corpo JSON passa de 1 MiB. Um `template.sections` em linha muito grande pode alcançar isso. `param` é `body`                                                 |
| `503`  | As sessões ao vivo estão indisponíveis. Repita com backoff                                                                                                     |

Veja [Erros](/pt-BR/scribe-api/errors) para o envelope completo de resposta.
