Skip to main content
POST
/
transcripts
/
retry
Reprocessar nota falhada
curl --request POST \
  --url https://api-sandbox.connectvets.com.br/notes/v1/transcripts/retry \
  --header 'Content-Type: application/json' \
  --header 'X-API-KEY: <api-key>' \
  --data '{}'
{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Rex",
    "transcription_status": "pending",
    "created_at": "2024-02-14T18:25:43Z",
    "updated_at": "2024-02-14T19:15:30Z"
  },
  "message": "Note reprocessing started successfully"
}

Documentation Index

Fetch the complete documentation index at: https://docs.connectvets.com.br/llms.txt

Use this file to discover all available pages before exploring further.

Descrição

Inicia uma nova tentativa de processamento para uma nota que falhou na transcrição ou que você deseja reprocessar. Útil para casos onde:
  • A transcrição falhou devido a problemas temporários
  • Você deseja reprocessar uma nota com melhorias na IA
  • Houve problemas na qualidade da primeira transcrição
Compatibilidade: Este endpoint permite retry para notas com status failed, completed ou pending. Não é possível fazer retry de uma nota que já está com status processing.

Parâmetros da Requisição

Headers

HeaderObrigatórioValor
X-API-KEY✅ SimSua chave de API
Content-Type✅ Simapplication/json

Body (JSON)

CampoTipoObrigatórioDescrição
note_idUUID✅ SimID da nota que será reprocessada

Exemplos de Requisição

cURL

curl -X POST https://api.connectvets.com/transcripts/retry \
  -H "X-API-KEY: cvn_live_abc123def456..." \
  -H "Content-Type: application/json" \
  -d '{
    "note_id": "6a4fe1de-52c4-4b2b-a30f-4b3fa9d7d8b3"
  }'

JavaScript/TypeScript

async function retryTranscription(noteId) {
  const response = await fetch('https://api.connectvets.com/transcripts/retry', {
    method: 'POST',
    headers: {
      'X-API-KEY': 'cvn_live_abc123def456...',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      note_id: noteId
    })
  });
  
  if (!response.ok) {
    throw new Error(`Erro no retry: ${response.status}`);
  }
  
  const result = await response.json();
  return result;
}

// Uso
try {
  const result = await retryTranscription('6a4fe1de-52c4-4b2b-a30f-4b3fa9d7d8b3');
  console.log('Retry iniciado:', result.status);
  console.log('URL da transcrição:', result.transcription);
} catch (error) {
  console.error('Erro:', error.message);
}

Python

import requests
import json

def retry_transcription(api_key, note_id):
    url = "https://api.connectvets.com/transcripts/retry"
    headers = {
        "X-API-KEY": api_key,
        "Content-Type": "application/json"
    }
    
    data = {
        "note_id": note_id
    }
    
    response = requests.post(url, headers=headers, json=data)
    
    if response.status_code == 200:
        result = response.json()
        print(f"Retry iniciado para nota {note_id}")
        print(f"Status: {result['status']}")
        print(f"Transcrição: {result['transcription']}")
        return result
    else:
        print(f"Erro: {response.status_code}")
        print(response.text)
        return None

# Uso
api_key = "cvn_live_abc123def456..."
note_id = "6a4fe1de-52c4-4b2b-a30f-4b3fa9d7d8b3"

result = retry_transcription(api_key, note_id)

Go

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

type RetryRequest struct {
    NoteID string `json:"note_id"`
}

type RetryResponse struct {
    NoteID        string `json:"note_id"`
    Status        string `json:"status"`
    Message       string `json:"message"`
    Transcription string `json:"transcription"`
}

func retryTranscription(apiKey, noteID string) (*RetryResponse, error) {
    url := "https://api.connectvets.com/transcripts/retry"
    
    requestBody := RetryRequest{
        NoteID: noteID,
    }
    
    jsonData, err := json.Marshal(requestBody)
    if err != nil {
        return nil, err
    }
    
    req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
    if err != nil {
        return nil, err
    }
    
    req.Header.Set("X-API-KEY", apiKey)
    req.Header.Set("Content-Type", "application/json")
    
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    
    if resp.StatusCode != 200 {
        return nil, fmt.Errorf("erro %d: %s", resp.StatusCode, resp.Status)
    }
    
    var result RetryResponse
    err = json.NewDecoder(resp.Body).Decode(&result)
    return &result, err
}

// Uso
result, err := retryTranscription("cvn_live_abc123def456...", "6a4fe1de-52c4-4b2b-a30f-4b3fa9d7d8b3")
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Status: %s\n", result.Status)
fmt.Printf("Mensagem: %s\n", result.Message)

Resposta de Sucesso (200 OK)

{
  "note_id": "6a4fe1de-52c4-4b2b-a30f-4b3fa9d7d8b3",
  "status": "processing",
  "message": "Transcription retry initiated successfully",
  "transcription": "https://cdn.connectvets.com/notes/6a4fe1de.txt"
}
CampoTipoDescrição
note_idUUIDID da nota que está sendo reprocessada
statusStringNovo status da nota (sempre “processing”)
messageStringMensagem de confirmação
transcriptionStringURL onde a nova transcrição ficará disponível

Tratamento de Erros

400 Bad Request

{
  "error": "bad_request",
  "message": "Invalid note_id format",
  "code": "INVALID_NOTE_ID"
}
Causas:
  • note_id ausente no corpo da requisição
  • note_id com formato inválido (não é UUID)
  • Corpo da requisição malformado

400 Bad Request - Já em Processamento

{
  "error": "bad_request", 
  "message": "transcription is already being processed",
  "code": "TRANSCRIPTION_IN_PROGRESS"
}
Causa: A nota já está com status processing e não pode ser reprocessada novamente até a conclusão.

403 Forbidden

{
  "error": "forbidden",
  "message": "Note does not belong to current tenant",
  "code": "NOTE_ACCESS_DENIED"
}
Causa: A nota não pertence ao tenant/clínica associado à API Key utilizada.

404 Not Found

{
  "error": "not_found",
  "message": "Note not found",
  "code": "NOTE_NOT_FOUND"
}
Causa: Nota com o ID fornecido não existe.

Casos de Uso

Retry Automático para Notas Falhadas

async function retryFailedNotes() {
  // Buscar notas com status failed
  const failedNotes = await listNotes({
    transcription_status: 'failed'
  });
  
  console.log(`Encontradas ${failedNotes.notes.length} notas falhadas`);
  
  const retryResults = [];
  
  for (const note of failedNotes.notes) {
    try {
      const result = await retryTranscription(note.id);
      retryResults.push({
        noteId: note.id,
        status: 'success',
        newStatus: result.status
      });
      
      console.log(`✅ Retry iniciado para nota ${note.id}`);
      
      // Aguardar um pouco entre retries
      await new Promise(resolve => setTimeout(resolve, 1000));
      
    } catch (error) {
      retryResults.push({
        noteId: note.id,
        status: 'error',
        error: error.message
      });
      
      console.error(`❌ Erro no retry da nota ${note.id}:`, error.message);
    }
  }
  
  return retryResults;
}

Retry com Monitoramento

async function retryAndMonitor(noteId) {
  try {
    // Iniciar retry
    const retryResult = await retryTranscription(noteId);
    console.log(`🔄 Retry iniciado para nota ${noteId}`);
    
    // Monitorar progresso
    let status = 'processing';
    let attempts = 0;
    const maxAttempts = 60; // 5 minutos máximo
    
    while (status === 'processing' && attempts < maxAttempts) {
      await new Promise(resolve => setTimeout(resolve, 5000)); // 5s
      
      const statusResult = await getNoteStatus(noteId);
      status = statusResult.status;
      attempts++;
      
      console.log(`📊 Tentativa ${attempts}: Status ${status}`);
      
      if (status === 'completed') {
        console.log('✅ Retry concluído com sucesso!');
        return { success: true, status };
      } else if (status === 'failed') {
        console.log('❌ Retry falhou novamente');
        return { success: false, status };
      }
    }
    
    if (attempts >= maxAttempts) {
      console.log('⏰ Timeout: Retry demorou muito');
      return { success: false, status: 'timeout' };
    }
    
  } catch (error) {
    console.error('❌ Erro no retry:', error.message);
    return { success: false, error: error.message };
  }
}

Retry Inteligente com Backoff

async function intelligentRetry(noteId, maxRetries = 3) {
  let attempt = 0;
  
  while (attempt < maxRetries) {
    try {
      // Verificar status atual
      const status = await getNoteStatus(noteId);
      
      if (status.status === 'processing') {
        console.log('⏳ Nota ainda em processamento, aguardando...');
        await new Promise(resolve => setTimeout(resolve, 30000));
        continue;
      }
      
      if (status.status === 'completed') {
        console.log('✅ Nota já processada com sucesso');
        return { success: true, alreadyCompleted: true };
      }
      
      // Iniciar retry
      await retryTranscription(noteId);
      console.log(`🔄 Retry ${attempt + 1}/${maxRetries} iniciado`);
      
      // Aguardar processamento
      const result = await waitForCompletion(noteId);
      
      if (result.status === 'completed') {
        console.log('✅ Retry bem-sucedido!');
        return { success: true, attempt: attempt + 1 };
      }
      
      attempt++;
      
      if (attempt < maxRetries) {
        // Backoff exponencial: 2^attempt minutos
        const delayMinutes = Math.pow(2, attempt);
        console.log(`⏰ Aguardando ${delayMinutes} minutos antes do próximo retry...`);
        await new Promise(resolve => setTimeout(resolve, delayMinutes * 60 * 1000));
      }
      
    } catch (error) {
      console.error(`❌ Erro no retry ${attempt + 1}:`, error.message);
      attempt++;
      
      if (attempt < maxRetries) {
        await new Promise(resolve => setTimeout(resolve, 60000)); // 1 minuto
      }
    }
  }
  
  console.log(`❌ Falha após ${maxRetries} tentativas`);
  return { success: false, attempts: maxRetries };
}

Monitoramento após Retry

Verificação de Status

Após iniciar um retry, use o endpoint /notes/{id}/status para monitorar o progresso:
async function monitorRetry(noteId) {
  console.log('📊 Monitorando retry...');
  
  let status = 'processing';
  let checkCount = 0;
  
  while (status === 'processing') {
    await new Promise(resolve => setTimeout(resolve, 10000)); // 10s
    
    const result = await getNoteStatus(noteId);
    status = result.status;
    checkCount++;
    
    console.log(`Verificação ${checkCount}: ${status}`);
    
    if (status === 'completed') {
      console.log('🎉 Retry concluído!');
      break;
    } else if (status === 'failed') {
      console.log('💥 Retry falhou');
      break;
    }
    
    // Timeout após 10 minutos
    if (checkCount > 60) {
      console.log('⏰ Timeout do monitoramento');
      break;
    }
  }
  
  return status;
}

Boas Práticas

🔄 Gestão de Retries

  • Limite tentativas: Não faça retry infinitamente
  • Use backoff: Aguarde entre tentativas com delay crescente
  • Monitore status: Verifique se a nota já está em processamento
  • Log adequadamente: Registre tentativas e resultados

⏰ Timing

  • Aguarde falhas: Não faça retry imediatamente após falha
  • Respeite processamento: Não tente retry em notas processing
  • Use polling inteligente: Interval de 5-10s para verificar status

🚨 Tratamento de Erros

function shouldRetry(error) {
  // Não retry em casos irrecuperáveis
  const nonRetryableErrors = [
    'NOTE_NOT_FOUND',
    'NOTE_ACCESS_DENIED',
    'INVALID_NOTE_ID'
  ];
  
  return !nonRetryableErrors.includes(error.code);
}

async function safeRetry(noteId) {
  try {
    return await retryTranscription(noteId);
  } catch (error) {
    if (shouldRetry(error)) {
      console.log('Erro temporário, pode tentar novamente');
    } else {
      console.log('Erro permanente, não tentar novamente');
    }
    throw error;
  }
}

📈 Métricas

Monitore métricas importantes:
  • Taxa de sucesso dos retries
  • Tempo médio de processamento
  • Notas que falharam múltiplas vezes
  • Patterns de falhas para feedback à equipe

Authorizations

X-API-KEY
string
header
required

API Key para autenticação

Path Parameters

noteId
string<uuid>
required

ID único da nota para reprocessar

Body

application/json

Body vazio para reprocessamento

Response

Reprocessamento iniciado com sucesso

data
object
message
string

Mensagem de confirmação

Example:

"Note reprocessing started successfully"