Pular para o conteúdo principal

Integração com Chave de Integração

Este guia é para empresas que integram o TranscriMed ao próprio sistema, com uma conta corporativa. Seu backend envia o áudio de uma consulta ou evolução e recebe o documento médico pronto. Depois, pode pedir correções desse documento por texto ou por voz.

Todos os documentos e todo o consumo de créditos ficam na conta da sua empresa. A API não precisa de dados de identificação do médico nem do paciente.

Uma requisição é o atendimento de um paciente (por exemplo, uma evolução de um leito em um plantão). Para ligar cada documento ao registro correspondente no seu sistema, envie o seu identificador em external_reference_id: ele volta em todas as respostas e consultas do job, e você pode buscar jobs por ele. Veja Correlacionar jobs com o seu sistema.

Visão geral​

  1. Crie uma chave de integração no TranscriMed, com a conta da sua empresa.
  2. Troque a chave por um token de acesso (válido por 4 horas).
  3. Envie o áudio para gerar um documento e receba um jobId.
  4. Consulte o job até que o documento esteja pronto.
  5. Opcional: peça uma correção. Ela é gravada no documento quando o job termina.

Em vez de consultar o job, você pode enviar "mode": "sync": a requisição espera o job e responde com o documento. Veja Síncrono ou assíncrono.

Tablet ──► Seu backend ──► API TranscriMed
│ 1. troca a chave por um token
│ 2. envia o áudio → jobId
│ 3. consulta o job → documento
A chave fica apenas no seu backend

A chave de integração dá acesso a todos os documentos da sua conta. Nunca a instale em tablets, celulares, navegadores ou qualquer aplicativo distribuído. O dispositivo envia o áudio ao seu backend, e só o seu backend chama o TranscriMed. Guarde a chave em um cofre de segredos ou em variável de ambiente, nunca no código-fonte.

Ambientes​

AmbienteAplicativo webURL base da APIUso
Sandboxhttps://sandbox.transcrimed.com.brhttps://api.sandbox.transcrimed.com.br/api/v1Desenvolvimento e testes de integração
Produçãohttps://transcrimed.com.brhttps://api.transcrimed.com.br/api/v1Uso real

Como obter acesso ao sandbox​

O sandbox é uma instalação separada do TranscriMed, não um "modo de teste" da produção. O acesso é provisionado pela TranscriMed:

  1. A TranscriMed cria a conta da sua empresa no sandbox e envia um convite por e-mail. O endereço do aplicativo web e a URL base da API do sandbox estão na tabela acima.
  2. Você aceita o convite, define a senha e configura a autenticação em dois fatores.
  3. No aplicativo web do sandbox, você cria seus modelos e suas chaves de integração exatamente como no passo 1.
  4. Seu backend usa a chave e a URL base do sandbox. Todo o restante deste guia funciona igual.

A conta, as chaves, os créditos, os modelos e os documentos do sandbox são independentes de produção. Uma chave de sandbox não funciona em produção, nem o contrário. Para ir para produção, a TranscriMed cria a conta de produção da mesma forma, e você cria novas chaves nela.

Use apenas dados fictícios no sandbox

O sandbox é o nosso ambiente de pré-lançamento: cada nova versão passa por ele antes de chegar à produção. Use áudios sintéticos ou gravados sem dados de pacientes reais. Dados de pacientes reais pertencem somente à produção.

O sandbox dorme quando está ocioso

Para economizar recursos, o processamento do sandbox para depois de um período sem uso e volta na próxima requisição. O primeiro job depois de um período sem uso pode ficar em queued mais tempo que o normal enquanto o sandbox acorda; continue consultando dentro do tempo-limite do passo 5. A produção não dorme.

Os exemplos abaixo usam a variável BASE_URL.

1. Criar a chave de integração​

  1. Entre no TranscriMed com a conta da sua empresa.
  2. Abra Configurações da organização → Integrações → Chaves de Integração.
  3. Crie uma chave e dê a ela um nome que identifique o sistema que vai usá-la (por exemplo, backend-producao).
  4. Copie a chave imediatamente. Ela começa com ik_ e é exibida uma única vez.

Você pode manter várias chaves ativas. Para trocar uma chave sem interromper o serviço: crie uma nova, publique-a no seu backend e só então revogue a antiga. Uma chave revogada deixa de funcionar na hora, inclusive os tokens já emitidos a partir dela.

2. Trocar a chave por um token de acesso​

POST {BASE_URL}/auth/exchange-integration-key
Content-Type: application/json

{ "integration_key": "ik_..." }

Resposta 200

{
"success": true,
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 14400,
"refresh_token": "...",
"scope": "medical_records:read medical_records:write ..."
},
"meta": { "requestId": "...", "timestamp": "..." }
}

Envie o access_token em todas as chamadas seguintes:

Authorization: Bearer <access_token>

Renovar o token​

O token vale por 4 horas (expires_in, em segundos). Antes de expirar, renove-o com o refresh_token:

POST {BASE_URL}/auth/refresh
Content-Type: application/json

{ "refresh_token": "..." }

A resposta tem o mesmo formato da troca e traz um novo refresh_token: guarde sempre o mais recente. Se a renovação falhar, faça uma nova troca com a chave.

3. Obter o ID do modelo de documento​

Cada documento é gerado a partir de um modelo da sua conta (por exemplo, "Evolução diária UTI"). Os modelos são criados e editados no TranscriMed. Liste os modelos da conta para obter seus IDs:

GET {BASE_URL}/templates
Authorization: Bearer <access_token>
{ "success": true, "data": { "templates": [ { "id": "6f1c...", "name": "Evolução diária UTI", "...": "..." } ] } }
Como o modelo é escolhido

Toda geração define um modelo, nesta ordem. Nenhuma etapa espera por uma pessoa.

  1. O template_id que você envia. Ele precisa ser um modelo da sua conta; caso contrário, a requisição responde 400 TEMPLATE_NOT_FOUND, sem criar job e sem cobrar crédito.
  2. Seleção automática pelo conteúdo do áudio, entre os modelos da sua conta. Uma conta com um único modelo usa sempre esse modelo.
  3. O modelo padrão da conta, usado somente quando a seleção automática não encontra modelo. Você escolhe esse modelo no aplicativo web, na página Modelos, em Modelo padrão, e pode trocá-lo ou removê-lo ali a qualquer momento. Excluir esse modelo remove a escolha.
  4. Caso contrário, o job falha com TEMPLATE_UNRESOLVED, e nenhum crédito é cobrado. Envie o template_id, ou escolha um modelo padrão na página Modelos do aplicativo web, e envie novamente.

Para obter sempre o mesmo modelo, envie o template_id.

4. Gerar um documento a partir de áudio​

POST {BASE_URL}/medical-records/generate
Authorization: Bearer <access_token>
Content-Type: application/json
Idempotency-Key: 5d2f8c4a-7b1e-4f3a-9c6d-2e8b0a4f1c37
X-Request-Id: 0b8f6a1e-3c2d-4e7a-9b1f-5d6c7e8f9a01

{
"audio": "<áudio em base64>",
"template_id": "6f1c...",
"mode": "async",
"language": "pt-BR",
"external_reference_id": "leito-12-noturno-2026-10-21"
}
CampoObrigatórioDescrição
audiosim*Áudio codificado em base64. Use ou audio ou text.
textsim*Texto já transcrito, no lugar do áudio.
template_idveja o passo 3ID do modelo.
modenãoasync (padrão) ou sync. Veja Síncrono ou assíncrono.
languagenãoIdioma do áudio. Padrão: pt-BR.
external_reference_idnãoSeu próprio identificador deste documento, com até 255 caracteres, nunca identificando o paciente. Volta em todas as respostas e consultas do job, e pode ser buscado. Veja Correlacionar jobs com o seu sistema.
metadatanãoObjeto livre, guardado com o documento. Não envie dados de identificação do paciente.
clinical_intelligencenãotrue (padrão) ou false. Com false, só o documento é produzido: veja Somente o documento.

Cabeçalho Idempotency-Key (obrigatório): um valor gerado por você, único por envio (recomendamos um UUID; até 255 caracteres ASCII visíveis). Se a requisição falhar ou a conexão cair, reenvie a mesma requisição com a mesma chave. Veja Repetições e Idempotency-Key.

Cabeçalho X-Request-Id (recomendado): um UUID gerado por você, único por envio. Ele identifica a requisição nos registros de suporte e permite consultar o job (veja Erros).

Áudio: formatos WebM (Opus), M4A/MP4 (AAC), WAV, OGG, FLAC e MP3. Recomendamos WebM (Opus) ou M4A, mono. O corpo da requisição tem limite de 50 MB, o que equivale a cerca de 37 MB de áudio antes da codificação base64.

Resposta 202

{
"success": true,
"data": {
"jobId": "6f1c2a9e-3b7d-4c51-9a2e-8d4b7f0c1e23",
"status": "queued",
"statusUrl": "https://api.transcrimed.com.br/api/v1/pipeline/jobs/6f1c2a9e-3b7d-4c51-9a2e-8d4b7f0c1e23",
"eventsUrl": "https://api.transcrimed.com.br/api/v1/pipeline/jobs/6f1c2a9e-3b7d-4c51-9a2e-8d4b7f0c1e23/events",
"estimatedCompletionAt": "2026-10-21T15:02:00.000Z",
"external_reference_id": "leito-12-noturno-2026-10-21"
},
"meta": { "request_id": "...", "timestamp": "..." }
}
patient_id é ignorado

A API não recebe identificador de paciente: o documento pertence à sua conta, não a um cadastro de paciente no TranscriMed. Uma requisição que envia patient_id é processada normalmente, o valor não é guardado em lugar nenhum, e a resposta traz um aviso em meta.warnings:

"meta": {
"request_id": "...",
"timestamp": "...",
"warnings": [{ "code": "PATIENT_ID_IGNORED", "message": "patient_id is not supported and was ignored; ..." }]
}

Remova patient_id das suas requisições e use external_reference_id (sem identificar o paciente) para correlacionar.

Síncrono ou assíncrono​

A geração e as duas correções aceitam mode. Os dois modos criam o mesmo job; só a resposta muda.

  • async (padrão): 202 com o jobId na hora, como acima. Você consulta o job (passo 5).
  • sync: a requisição espera o job por até 90 segundos:
    • Terminou a tempo: 200 com o resultado (abaixo).
    • Falhou: o código de erro do job, com o status HTTP da tabela de Erros. Não há o que consultar.
    • Ainda em andamento após 90 segundos: exatamente o 202 do async (jobId, statusUrl, eventsUrl). Consulte o job como no passo 5.

Configure o tempo-limite do seu cliente HTTP acima de 90 segundos (por exemplo, 120 segundos), para que ele não desista antes do 202.

Recomendamos async para áudios longos. O processamento deles costuma passar de 90 segundos, e uma requisição sync então espera 90 segundos só para receber o 202.

Resposta 200 (geração, sync)

{
"success": true,
"data": {
"jobId": "6f1c2a9e-3b7d-4c51-9a2e-8d4b7f0c1e23",
"status": "completed",
"record_id": "b3f0c2de-...",
"document": {
"id": "b3f0c2de-...",
"title": "Evolução diária UTI",
"content": "<div>...documento em HTML...</div>"
},
"clinical_intelligence": { "specialty": "MEDICINA_INTENSIVA", "...": "..." },
"external_reference_id": "leito-12-noturno-2026-10-21"
},
"meta": { "request_id": "...", "timestamp": "..." }
}
  • document.content é o documento, em HTML. Guarde o record_id: é o ID do documento.
  • clinical_intelligence é o mesmo objeto do resultado do job (passo 5), e não vem quando você enviou clinical_intelligence: false.

Se a conexão cair durante a espera, reenvie a mesma requisição com a mesma Idempotency-Key. Ela se liga ao mesmo job: nenhum segundo job é criado e nenhum segundo crédito é cobrado. Se o job já terminou, você recebe o resultado na hora; se ainda está em andamento, a requisição espera de novo, por até 90 segundos. O mode não entra na comparação das requisições, então você também pode reenviar um envio async como sync, com a mesma chave, para esperar o resultado dele. Veja Repetições e Idempotency-Key.

Somente o documento (clinical_intelligence: false)​

Por padrão, o TranscriMed também analisa a consulta: identifica a especialidade, o tipo de atendimento e a urgência, e extrai medicamentos, procedimentos e códigos CID-10, que informam o documento e são devolvidos no resultado do job (veja o passo 5).

Se você só precisa do documento, envie "clinical_intelligence": false. As etapas de análise são puladas e o documento é gerado apenas a partir da transcrição:

  • Nenhuma especialidade, tipo de atendimento, urgência, medicamento, procedimento ou código CID-10 é extraído, guardado ou devolvido. O resultado não traz o objeto clinical_intelligence.
  • A escolha do modelo não muda: se você omitir template_id, ela funciona como descrito no passo 3.
  • O documento consome o mesmo crédito.

5. Consultar o job até o documento ficar pronto​

GET {BASE_URL}/pipeline/jobs/{jobId}
Authorization: Bearer <access_token>

status evolui de queued para in_progress e termina em completed ou failed. Consulte a cada 3 a 5 segundos. Um áudio costuma ficar pronto em 1 a 2 minutos; considere um tempo-limite de 10 minutos antes de tratar o caso como erro.

Concluído

{
"jobId": "6f1c2a9e-3b7d-4c51-9a2e-8d4b7f0c1e23",
"requestId": "...",
"type": "medical_record_generation",
"external_reference_id": "leito-12-noturno-2026-10-21",
"state": "completed",
"status": "completed",
"progress": { "...": "..." },
"result": {
"requestId": "...",
"result": {
"record_id": "b3f0c2de-...",
"text": {
"title": "Evolução diária UTI",
"content": "<div>...documento em HTML...</div>",
"templateId": "6f1c...",
"succeeded": true
},
"transcript": "...",
"clinical_intelligence": {
"specialty": "MEDICINA_INTENSIVA",
"encounter_type": "follow_up",
"urgency": "urgent",
"medications": [
{ "name": "Noradrenalina", "dosage": "0,1 mcg/kg/min", "route": "IV", "frequency": null, "duration": null }
],
"procedures": [{ "name": "Intubação orotraqueal", "tuss_code": null }],
"cid10": [{ "code": "J96.0", "description": "Insuficiência respiratória aguda", "is_primary": true, "status": "confirmed" }]
}
},
"transcript": "..."
},
"error": null,
"document": {
"id": "b3f0c2de-...",
"title": "Evolução diária UTI",
"content": "<div>...documento em HTML...</div>"
}
}
  • O documento está em result.result.text.content, em HTML. Um job de geração concluído também o traz como document (id, title, content), o mesmo objeto da resposta sync.
  • Guarde o result.result.record_id. É o ID do documento, usado para lê-lo e corrigi-lo depois.
  • Se status for failed, o código de erro estável vem em errorCode (por exemplo, TEMPLATE_UNRESOLVED) e a descrição em error.
  • external_reference_id é o que você enviou, em todos os estados (queued, in_progress, completed, failed), ou null se você não enviou. type é medical_record_generation, document_correction ou voice_correction.

result.result.clinical_intelligence vem sempre, exceto quando você enviou clinical_intelligence: false. Qualquer campo pode vir null ou como lista vazia quando nada foi identificado.

CampoDescrição
specialtyEspecialidade médica identificada, como código (por exemplo CLINICA_MEDICA).
encounter_typenew_patient, follow_up, procedure, emergency, pre_operative, post_operative ou report.
urgencyroutine, priority, urgent ou emergency.
medicationsMedicamentos mencionados: name, e dosage, route, frequency e duration quando ditos.
proceduresProcedimentos mencionados: name, e tuss_code quando houve correspondência com a tabela TUSS.
cid10Códigos CID-10: code, description, is_primary e status (confirmed: corresponde à tabela oficial do CID-10; ai_selected: escolhido de uma lista curta da tabela oficial). Códigos que são apenas sugestões não são devolvidos.

São extrações automáticas para revisão do médico, não um diagnóstico confirmado.

O job continua respondendo depois de terminar: o mesmo GET devolve o status, o result, o document e o errorCode também mais tarde. Para ler o documento como ele está agora (inclusive com as correções gravadas), use o record_id:

GET {BASE_URL}/medical-records/{record_id}
Authorization: Bearer <access_token>
{ "success": true, "data": { "record": { "id": "b3f0c2de-...", "title": "...", "content": "<div>...</div>", "...": "..." } } }
Acompanhar em tempo real

Em vez de consultar periodicamente, você pode assinar eventsUrl, um stream Server-Sent Events com o progresso do job, usando o mesmo cabeçalho Authorization.

6. Corrigir um documento​

Corrija um documento informando o record_id e a correção, por texto ou por voz. As duas formas aceitam mode, como a geração (Síncrono ou assíncrono): com async (padrão) devolvem um jobId, consultado como no passo 5; com sync respondem com o documento corrigido.

Por texto​

POST {BASE_URL}/medical-records/{record_id}/correct-text
Authorization: Bearer <access_token>
Content-Type: application/json
Idempotency-Key: 9a3c1e7f-2b4d-4c8e-a6f0-1d5b7e9c3a20

{ "instructions": "Trocar a dose de noradrenalina para 0,3 mcg/kg/min.", "external_reference_id": "leito-12-noturno-2026-10-21" }

Por voz​

POST {BASE_URL}/medical-records/{record_id}/correct
Authorization: Bearer <access_token>
Content-Type: application/json
Idempotency-Key: 4e6b2d8f-1a3c-4b5e-8d7f-0c2a4e6b8d91

{ "audio": "<áudio em base64>", "language": "pt-BR" }

Limite do corpo: 10 MB.

As duas correções exigem o cabeçalho Idempotency-Key, exatamente como a geração. As duas aceitam external_reference_id, como a geração: ele volta no 202, no 200 do sync e em toda consulta do job da correção.

Resultado da correção​

Quando o job da correção termina (status: "completed"), a correção já está gravada no documento:

{
"status": "completed",
"result": {
"success": true,
"recordId": "b3f0c2de-...",
"correctedDocument": "<div>...documento corrigido em HTML...</div>",
"saved": true
}
}
  • result.saved é true: o documento passa a ser a versão corrigida. Não há etapa de confirmação.
  • result.correctedDocument é o documento gravado, em HTML. GET /medical-records/{record_id} devolve o mesmo conteúdo.
  • A próxima correção parte desta versão.

Com "mode": "sync", a resposta 200 traz os mesmos campos:

{
"success": true,
"data": {
"jobId": "b2e94d17-5a60-4f8c-a1d3-7c9e2f4b6a08",
"status": "completed",
"recordId": "b3f0c2de-...",
"correctedDocument": "<div>...documento corrigido em HTML...</div>",
"saved": true,
"external_reference_id": "leito-12-noturno-2026-10-21"
},
"meta": { "request_id": "...", "timestamp": "..." }
}

Uma correção sync com falha responde o código diretamente, por exemplo 409 CORRECTION_CONFLICT (veja Erros).

Uma correção por vez em cada documento

A correção é calculada a partir do documento como ele estava quando você a pediu. Se o documento mudou antes de a correção ser gravada, por exemplo porque outra correção do mesmo documento foi gravada antes, o job falha com CORRECTION_CONFLICT e nada é gravado. Leia o documento de novo e peça a correção outra vez, se ainda for necessária. Para evitar isso, espere o job de uma correção terminar antes de pedir a próxima correção do mesmo documento.

Correlacionar jobs com o seu sistema​

Envie o seu próprio identificador em external_reference_id, na geração e nas correções. Recomendamos o identificador do registro do seu sistema que o documento preenche, por exemplo o id da sua evolução por leito e por plantão.

  • Uma requisição é o atendimento de um paciente. Envie uma geração por documento; não junte vários pacientes no mesmo áudio.
  • Ele não pode identificar o paciente. Nada de nome, CPF, número de prontuário ou outro dado do paciente: use um id opaco seu (até 255 caracteres). Ele é guardado com o job, como foi enviado.
  • Ele não é único do nosso lado. A mesma referência pode ser enviada de novo (por exemplo, uma geração e depois as correções dela, ou um reenvio). Cada requisição continua sendo um job separado; só a Idempotency-Key evita duplicatas.

Onde ele volta:

RespostaCampo
202 da geração e das correçõesdata.external_reference_id
200 sync da geração e das correçõesdata.external_reference_id
GET /pipeline/jobs/{jobId}, em todos os estadosexternal_reference_id (null se não foi enviado)
GET /pipeline/jobs?external_reference_id=...external_reference_id de cada job

Buscar jobs pela sua referência​

Se você perdeu um jobId (por exemplo, o 202 não chegou e você não tinha enviado Idempotency-Key), liste os jobs da sua conta com essa referência:

GET {BASE_URL}/pipeline/jobs?external_reference_id=leito-12-noturno-2026-10-21&limit=10
Authorization: Bearer <access_token>
{
"external_reference_id": "leito-12-noturno-2026-10-21",
"limit": 10,
"jobs": [
{ "jobId": "b2e94d17-5a60-4f8c-a1d3-7c9e2f4b6a08", "type": "document_correction", "external_reference_id": "leito-12-noturno-2026-10-21", "status": "completed", "...": "..." },
{ "jobId": "6f1c2a9e-3b7d-4c51-9a2e-8d4b7f0c1e23", "type": "medical_record_generation", "external_reference_id": "leito-12-noturno-2026-10-21", "status": "completed", "document": { "...": "..." } }
]
}
  • Só os jobs da sua conta são devolvidos, do mais recente para o mais antigo. Cada job tem os mesmos campos de GET /pipeline/jobs/{jobId}.
  • limit é opcional: 10 por padrão, no máximo 50.
  • Uma referência desconhecida devolve "jobs": [].

Repetições e Idempotency-Key​

A geração (/medical-records/generate) e as duas correções (/correct-text, /correct) exigem o cabeçalho Idempotency-Key. Ele torna a repetição segura: uma requisição reenviada nunca cria um segundo job, nem cobra um segundo crédito.

  • Gere uma chave nova para cada novo envio, e reutilize-a apenas para reenviar esse mesmo envio.
  • Mesma chave, mesma requisição, em até 24 horas: a resposta é o 202 original, com o mesmo jobId, statusUrl e eventsUrl. Nada é processado de novo. A resposta traz o cabeçalho Idempotent-Replayed: true. O corpo é o original (por exemplo, status: "queued"): consulte o statusUrl para saber o estado atual.
  • O mesmo, no modo sync: o reenvio espera esse mesmo job, por até 90 segundos, e responde como uma requisição sync: 200 com o resultado, o código de erro do job, ou o 202 original se ele ainda estiver em andamento. A resposta também traz Idempotent-Replayed: true.
  • "Mesma requisição" significa o mesmo endpoint, o mesmo documento (nas correções) e os mesmos campos no corpo, com os mesmos valores (a ordem dos campos não importa). No áudio, conta o conteúdo do áudio, não a sua codificação. O mode não conta: ele só diz como responder.
  • Mesma chave, requisição diferente: 409 IDEMPOTENCY_KEY_REUSED. Use uma chave nova para um novo envio.
  • Mesma chave enquanto a primeira requisição ainda está sendo aceita: 409 IDEMPOTENCY_KEY_IN_PROGRESS. Aguarde o cabeçalho Retry-After (em segundos) e reenvie com a mesma chave.
  • Uma requisição que falhou (por exemplo 402, 429, 503 ou 5xx): reenvie-a com a mesma chave. Se ela falhou antes de o job ser criado, o reenvio é processado como um novo envio. Se falhou depois de o job ser criado, o reenvio devolve esse job (202, mesmo jobId): uma chave nunca cria um segundo job.
  • Se o nosso servidor parou durante a primeira requisição, o reenvio pode responder 409 IDEMPOTENCY_KEY_IN_PROGRESS por até 5 minutos. Continue reenviando com a mesma chave depois do Retry-After: ele então devolve o job da primeira requisição ou, se nenhum foi criado, processa o envio.
  • Uma correção reenviada é a correção original: ela é calculada a partir do documento como estava na primeira requisição. Se o documento mudou nesse meio-tempo, o job falha com CORRECTION_CONFLICT e nada é gravado.
  • Depois de 24 horas a chave é esquecida. A mesma chave passa a iniciar um novo envio.
  • As chaves pertencem à sua conta, não a uma chave de integração: uma repetição enviada com o token de outra chave da mesma conta encontra o job original.

Erros​

Há três formatos de erro, conforme o endpoint.

Geração, correção, jobs, documentos e modelos:

{ "success": false, "error": { "code": "insufficient_credits", "message": "..." }, "requestId": "...", "timestamp": "..." }

Autenticação (/auth/exchange-integration-key e /auth/refresh):

{ "success": false, "error": { "error": "key_revoked", "error_description": "..." }, "meta": { "requestId": "...", "timestamp": "..." } }

Limite de requisições (HTTP 429):

{ "error": "rate_limited", "error_description": "Too many requests. Please retry after the indicated delay." }
HTTPCódigoO que fazer
400VALIDATION_ERROR, MISSING_AUDIO, INVALID_AUDIO, invalid_request, invalid_keyCorrija a requisição. Não repita sem alterar.
400TEMPLATE_NOT_FOUNDO template_id não é um modelo da sua conta. Liste os seus modelos (passo 3) e envie um ID válido. Nenhum job foi criado.
400IDEMPOTENCY_KEY_REQUIRED, IDEMPOTENCY_KEY_INVALIDEnvie o cabeçalho Idempotency-Key: de 1 a 255 caracteres ASCII visíveis, único por envio.
401 (autenticação)invalid_key, key_inactive, key_revoked, key_expiredA chave não é mais válida. Use uma chave ativa.
401 (autenticação)invalid_grantO refresh_token não vale mais. Faça uma nova troca com a chave.
401 (demais)TOKEN_EXPIRED, TOKEN_INVALID, INVALID_TOKEN, KEY_INVALID, UNAUTHORIZEDRenove o token. Se a chave foi revogada, faça a troca com uma chave ativa.
402insufficient_creditsA conta está sem créditos. Fale com a TranscriMed.
404NOT_FOUNDO documento ou o job não existe, ou não pertence à sua conta.
409IDEMPOTENCY_KEY_REUSEDEsta Idempotency-Key foi usada em outra requisição nas últimas 24 horas. Use uma chave nova.
409IDEMPOTENCY_KEY_IN_PROGRESSUma requisição com esta chave ainda está sendo aceita. Reenvie com a mesma chave depois do Retry-After.
409 (correção sync)CORRECTION_CONFLICT, CORRECTION_SUPERSEDEDO job de correção falhou como descrito abaixo. Nada foi gravado. error.details.jobId identifica o job.
422 (geração sync)TEMPLATE_UNRESOLVED, TEMPLATE_NOT_FOUNDO job de geração não conseguiu definir um modelo (veja o passo 3). Nenhum crédito foi cobrado. error.details.jobId identifica o job.
422 (correção sync)CORRECTION_NOT_SAVED, NON_MEDICAL_CONTENT, STRUCTURED_CORRECTION_NO_CHANGE, STRUCTURED_CORRECTION_MISSING_DOCUMENTA correção não pôde ser aplicada. Nada foi gravado.
500 (sync)processing_failed, CORRECTION_FAILED, outros códigos do jobO job falhou. Reenviar com a mesma Idempotency-Key devolve o mesmo job com falha: para tentar de novo, envie com uma chave nova.
503 (correção sync)CORRECTION_SAVE_FAILEDA gravação falhou depois das novas tentativas automáticas. Leia o documento: se ele não tiver a correção, peça-a de novo com uma chave nova.
— (job de correção com falha)CORRECTION_CONFLICTEm error de um job de correção failed: o documento mudou depois que a correção foi pedida. Nada foi gravado. Leia o documento e peça a correção de novo, se ainda for necessária.
— (job de correção com falha)CORRECTION_SUPERSEDEDEm error de um job de correção failed: uma correção mais recente do mesmo documento foi pedida antes de esta ser gravada. Este job não gravou nada.
— (job de correção com falha)CORRECTION_NOT_SAVEDEm error de um job de correção failed: sua conta não pode mais gravar o documento (por exemplo, ele foi excluído). Nada foi gravado.
— (job de correção com falha)CORRECTION_SAVE_FAILEDEm error de um job de correção failed: a gravação falhou depois das novas tentativas automáticas. Leia o documento: se ele não tiver a correção, peça-a de novo.
429rate_limited, user_generation_limit_reachedLimite atingido. Respeite o cabeçalho Retry-After, quando presente, ou tente novamente com espera exponencial.
503*_capacity_reached, IDEMPOTENCY_STORE_UNAVAILABLEIndisponibilidade momentânea. Tente novamente com espera exponencial e a mesma Idempotency-Key.
5xx—Erro do servidor. Tente novamente com espera exponencial e registre o requestId.
— (job com falha)TEMPLATE_UNRESOLVEDEm errorCode de um job failed: nenhum modelo pôde ser definido (veja o passo 3). Nenhum crédito foi cobrado. Envie o template_id, ou escolha um modelo padrão na página Modelos do aplicativo web, e envie novamente.
Se a conexão cair antes de você receber o jobId

Reenvie a mesma requisição com a mesma Idempotency-Key. Se a primeira foi aceita, você recebe o jobId dela (ou, no modo sync, o resultado), e nada é gerado nem cobrado de novo. Um reenvio com uma chave nova é um novo envio, e gera e cobra um segundo documento.

Você também pode consultar o job pelo X-Request-Id que enviou:

GET {BASE_URL}/pipeline/jobs/by-request/{X-Request-Id}
Authorization: Bearer <access_token>
  • 200: o envio foi aceito. A resposta traz jobId, requestId, external_reference_id, state, status, progress, result e error, mas não type, document nem errorCode. Pegue o jobId e continue consultando como no passo 5.
  • 404: o envio não chegou a ser aceito. Reenvie-o com a mesma Idempotency-Key.

Para correções, esta busca também encontra o job pelo external_reference_id que você enviou na correção. Para qualquer job, você também pode buscá-lo pela sua referência.

Limites e créditos​

  • Créditos: cada documento gerado consome 1 crédito da conta da empresa. Correções não consomem créditos.
  • Taxa de requisições: até 30 gerações e 60 correções por minuto por conta. Se precisar de mais, fale com a TranscriMed.
  • Chaves: o número de chaves ativas depende do plano da conta.

Exemplo completo (Node.js)​

const BASE_URL = process.env.TRANSCRIMED_BASE_URL; // sandbox ou produção
const INTEGRATION_KEY = process.env.TRANSCRIMED_INTEGRATION_KEY;

async function getToken() {
const res = await fetch(`${BASE_URL}/auth/exchange-integration-key`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ integration_key: INTEGRATION_KEY })
});
if (!res.ok) throw new Error(`Troca falhou: ${res.status}`);
return (await res.json()).data.access_token;
}

async function waitForJob(token, jobId, { intervalMs = 4000, timeoutMs = 10 * 60 * 1000 } = {}) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const res = await fetch(`${BASE_URL}/pipeline/jobs/${jobId}`, {
headers: { Authorization: `Bearer ${token}` }
});
const job = await res.json();
if (job.status === 'completed') return job.result;
if (job.status === 'failed') throw new Error(`Job falhou: ${job.errorCode ?? job.error}`);
await new Promise((r) => setTimeout(r, intervalMs));
}
throw new Error('Tempo-limite aguardando o job');
}

async function generateDocument(audioBuffer, templateId, externalId) {
const token = await getToken();
// Uma chave por envio. Guarde-a junto com o envio e reenvie com a mesma
// chave se a requisição falhar ou a conexão cair.
const idempotencyKey = crypto.randomUUID();

const submit = await fetch(`${BASE_URL}/medical-records/generate`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey,
'X-Request-Id': crypto.randomUUID()
},
body: JSON.stringify({
audio: audioBuffer.toString('base64'),
template_id: templateId,
mode: 'async',
external_reference_id: externalId
})
});
if (submit.status !== 202) throw new Error(`Envio falhou: ${submit.status} ${await submit.text()}`);
const { jobId } = (await submit.json()).data;

const result = await waitForJob(token, jobId);
return { recordId: result.result.record_id, html: result.result.text.content };
}

async function correctDocument(recordId, instructions) {
const token = await getToken();

const submit = await fetch(`${BASE_URL}/medical-records/${recordId}/correct-text`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID() // reutilize-a só para reenviar esta correção
},
body: JSON.stringify({ instructions })
});
if (submit.status !== 202) throw new Error(`Envio falhou: ${submit.status} ${await submit.text()}`);
const { jobId } = (await submit.json()).data;

// A correção é gravada quando o job termina. Um job com falha não gravou nada:
// `CORRECTION_CONFLICT` significa que o documento mudou; leia-o e peça de novo, se necessário.
const result = await waitForJob(token, jobId);
return result.correctedDocument;
}

Em produção, reutilize o token durante a sua validade e renove-o com /auth/refresh, em vez de fazer uma troca a cada chamada.

Checklist de segurança​

  • A chave de integração existe somente no backend, em um cofre de segredos.
  • Os tablets e demais dispositivos nunca recebem a chave nem o token.
  • Uma chave por sistema ou ambiente, com nomes claros, e revogação imediata de chave suspeita de vazamento.
  • Nenhum dado de identificação do paciente em metadata ou external_reference_id.
  • Uma Idempotency-Key nova por envio, reutilizada apenas para reenviar esse envio.
  • Registre o requestId das respostas de erro para facilitar o suporte.

Suporte​

Fale com a TranscriMed pelo seu canal de atendimento e informe o requestId ou o jobId da operação.