Documentação da API SoulScribe

Bem-vindo à documentação completa da API SoulScribe! Esta API permite transcrever consultas médicas, gerar relatórios SOAP estruturados e integrar inteligência artificial ao seu sistema de saúde.

O que você pode fazer com esta API?
  • Transcrever áudio de consultas médicas automaticamente
  • Gerar relatórios SOAP estruturados e profissionais
  • Processar em background sem timeouts para arquivos grandes
  • Integrar facilmente com nosso widget JavaScript pronto
  • Receber notificações via webhooks quando o processamento terminar

Base URL

https://soulscribe.soulclinic.com.br/api/v1

Tecnologias Utilizadas

IAs Suportadas
  • OpenAI GPT-4 + Whisper
  • Google Gemini Pro
  • Anthropic Claude (em breve)
Formatos de Áudio
  • MP3, WAV, M4A
  • WebM, OGG
  • Até 500MB por arquivo

Autenticação

Todas as requisições para a API devem incluir dois headers de autenticação:

  • X-API-Key: Sua chave pública de API
  • X-API-Secret: Sua chave secreta de API
POST /api/v1/consultas
Host: soulscribe.soulclinic.com.br
X-API-Key: sua_chave_publica_aqui
X-API-Secret: sua_chave_secreta_aqui
Content-Type: multipart/form-data
Importante: Nunca compartilhe suas chaves de API publicamente. Mantenha-as seguras em variáveis de ambiente.
Segurança: Ambos os headers são obrigatórios. Requisições sem qualquer um deles retornarão erro 401.

Passo 1: Criar sua Conta

Para começar a usar a API, primeiro você precisa criar uma conta no painel administrativo.

1
Acesse o Dashboard

Entre em contato com a SoulClinic para criar sua organização. Você receberá credenciais de acesso ao dashboard.

https://soulscribe.soulclinic.com.br/dashboard
2
Verifique seu Tenant ID

Após o login, você verá seu Tenant ID no canto superior direito do dashboard. Anote-o, pois você precisará dele.

3
Escolha seu Plano

A SoulScribe oferece planos flexíveis baseados em uso:

  • Pay-as-you-go: Pague apenas pelo que usar
  • Empresarial: Cota mensal com desconto
  • Personalizado: Para grandes volumes

Passo 2: Gerar sua Chave de API

Com sua conta criada, agora você pode gerar chaves de API para autenticar suas requisições.

1
Acesse Chaves de API

No dashboard, vá até o menu Configurações → Chaves de API

2
Criar Nova Chave

Clique em "Nova Chave de API" e preencha:

  • Nome: Ex: "Produção Frontend" ou "App Mobile"
  • Permissões: Selecione os recursos que esta chave pode acessar
  • Webhook URL (opcional): URL para receber notificações
3
Copie e Guarde a Chave
ATENÇÃO: A chave completa será exibida apenas UMA VEZ. Copie e guarde-a em um local seguro. Se perder, precisará gerar uma nova.
4
Teste suas Chaves

Faça um teste rápido com curl:

curl -X GET "https://soulscribe.soulclinic.com.br/api/v1/test/ping-auth" \
  -H "X-API-Key: sua_chave_publica_aqui" \
  -H "X-API-Secret: sua_chave_secreta_aqui"
Dica: Use o endpoint /api/v1/test/ping-auth para testar sua autenticação sem consumir cota.

Endpoints Disponíveis

Visão geral de todos os endpoints da API:

Método Endpoint Descrição
POST /api/v1/consultas Envia áudio para processamento
GET /api/v1/consultas/:id Consulta status de processamento
GET /api/v1/consultas Lista todas as consultas
GET /api/v1/consultas/:id/resultado Obtém resultado completo

POST /api/v1/consultas

Envia um arquivo de áudio para transcrição e geração de relatório SOAP.

POST https://soulscribe.soulclinic.com.br/api/v1/consultas
Headers
Header Tipo Descrição
X-API-Key OBRIGATÓRIO string Sua chave pública de API
X-API-Secret OBRIGATÓRIO string Sua chave secreta de API
Content-Type string multipart/form-data
Body Parameters
Parâmetro Tipo Descrição
audio OBRIGATÓRIO file Arquivo de áudio (MP3, WAV, M4A, WebM, OGG)
Máximo: 500MB
webhook_url OPCIONAL string URL para receber notificação quando concluir
metadata OPCIONAL json Metadados customizados (ex: ID do paciente, médico, etc)
Exemplo de Requisição
curl -X POST "https://soulscribe.soulclinic.com.br/api/v1/consultas" \
  -H "X-API-Key: sua_chave_publica_aqui" \
  -H "X-API-Secret: sua_chave_secreta_aqui" \
  -F "audio=@/caminho/para/consulta.mp3" \
  -F "webhook_url=https://seu-site.com/webhook" \
  -F 'metadata={"paciente_id": "12345", "medico": "Dr. Silva"}'
const formData = new FormData();
formData.append('audio', audioFile);
formData.append('webhook_url', 'https://seu-site.com/webhook');
formData.append('metadata', JSON.stringify({
    paciente_id: '12345',
    medico: 'Dr. Silva'
}));

const response = await fetch('https://soulscribe.soulclinic.com.br/api/v1/consultas', {
    method: 'POST',
    headers: {
        'X-API-Key': 'sua_chave_publica_aqui',
        'X-API-Secret': 'sua_chave_secreta_aqui'
    },
    body: formData
});

const data = await response.json();
console.log(data);
$ch = curl_init();

curl_setopt_array($ch, [
    CURLOPT_URL => 'https://soulscribe.soulclinic.com.br/api/v1/consultas',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'X-API-Key: sua_chave_publica_aqui',
        'X-API-Secret: sua_chave_secreta_aqui'
    ],
    CURLOPT_POSTFIELDS => [
        'audio' => new CURLFile('/caminho/para/consulta.mp3'),
        'webhook_url' => 'https://seu-site.com/webhook',
        'metadata' => json_encode([
            'paciente_id' => '12345',
            'medico' => 'Dr. Silva'
        ])
    ]
]);

$response = curl_exec($ch);
$data = json_decode($response, true);
curl_close($ch);
import requests

url = 'https://soulscribe.soulclinic.com.br/api/v1/consultas'
headers = {
    'X-API-Key': 'sua_chave_publica_aqui',
    'X-API-Secret': 'sua_chave_secreta_aqui'
}

files = {'audio': open('consulta.mp3', 'rb')}
data = {
    'webhook_url': 'https://seu-site.com/webhook',
    'metadata': '{"paciente_id": "12345", "medico": "Dr. Silva"}'
}

response = requests.post(url, headers=headers, files=files, data=data)
print(response.json())
Resposta de Sucesso (202 Accepted)
{
  "success": true,
  "message": "Áudio recebido e em processamento",
  "consulta_id": 42,
  "uuid": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pendente",
  "status_url": "https://soulscribe.soulclinic.com.br/api/v1/consultas/42"
}
Processamento Assíncrono: O áudio é processado em background. Use o status_url para consultar o progresso ou configure um webhook para ser notificado automaticamente.

GET /api/v1/consultas/:id

Consulta o status e progresso do processamento de uma consulta.

GET https://soulscribe.soulclinic.com.br/api/v1/consultas/:id
Path Parameters
Parâmetro Tipo Descrição
id OBRIGATÓRIO integer ID da consulta retornado no POST
Exemplo de Requisição
curl -X GET "https://soulscribe.soulclinic.com.br/api/v1/consultas/42" \
  -H "X-API-Key: sua_chave_publica_aqui" \
  -H "X-API-Secret: sua_chave_secreta_aqui"
Resposta - Processando (200 OK)
{
  "success": true,
  "consulta_id": 42,
  "uuid": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processando",
  "status_processamento": "processando",
  "progresso": 60,
  "tempo_decorrido": "2m 15s"
}
Resposta - Concluído (200 OK)
{
  "success": true,
  "consulta_id": 42,
  "uuid": "550e8400-e29b-41d4-a716-446655440000",
  "status": "concluida",
  "status_processamento": "concluido",
  "progresso": 100,
  "tempo_decorrido": "3m 42s",
  "transcricao": "Paciente relata dor de cabeça há 3 dias...",
  "relatorio_soap": {
    "SOAP": {
      "S": {
        "Queixa_principal": "Dor de cabeça",
        "Historia_da_doenca_atual": "Paciente refere cefaleia há 3 dias..."
      },
      "O": {
        "Sinais_vitais": "PA: 120/80 mmHg, FC: 72 bpm",
        "Achados_do_exame_fisico": "Paciente alerta e orientado..."
      },
      "A": {
        "Diagnostico_principal": "Cefaleia tensional",
        "Diagnosticos_diferenciais": ["Enxaqueca", "Hipertensão"]
      },
      "P": {
        "Medicacoes_prescritas": ["Dipirona 500mg"],
        "Orientacoes_dadas": ["Repouso", "Hidratação"]
      }
    }
  }
}
Dica: Faça polling a cada 2-5 segundos enquanto status_processamento não for "concluido" ou "falhou".

GET /api/v1/consultas

Lista todas as consultas da sua conta com paginação.

GET https://soulscribe.soulclinic.com.br/api/v1/consultas
Query Parameters
Parâmetro Tipo Descrição
page OPCIONAL integer Número da página (padrão: 1)
per_page OPCIONAL integer Itens por página (padrão: 20, máx: 100)
status OPCIONAL string Filtrar por status: "pendente", "processando", "concluida", "falhou"
Exemplo de Requisição
curl -X GET "https://soulscribe.soulclinic.com.br/api/v1/consultas?page=1&per_page=10&status=concluida" \
  -H "X-API-Key: sua_chave_publica_aqui" \
  -H "X-API-Secret: sua_chave_secreta_aqui"
Resposta (200 OK)
{
  "success": true,
  "data": [
    {
      "id": 42,
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "status": "concluida",
      "created_at": "2025-10-02 14:30:00",
      "tempo_processamento": "3m 42s"
    }
  ],
  "pagination": {
    "total": 150,
    "per_page": 10,
    "current_page": 1,
    "last_page": 15,
    "next_page_url": "https://soulscribe.soulclinic.com.br/api/v1/consultas?page=2",
    "prev_page_url": null
  }
}

Webhooks

Receba notificações automáticas quando o processamento de uma consulta for concluído.

Como Funcionam os Webhooks?

  1. Você envia uma requisição POST com webhook_url
  2. Quando o processamento terminar, enviamos um POST para sua URL
  3. Você recebe os dados completos da transcrição e SOAP
  4. Se sua URL estiver offline, tentamos novamente com backoff exponencial (até 10 tentativas)

Estrutura do Payload

Quando o processamento termina, enviamos este JSON para sua webhook_url:

{
  "event": "consulta.concluida",
  "timestamp": "2025-10-02T14:35:22Z",
  "data": {
    "consulta_id": 42,
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "status": "concluida",
    "transcricao": "Texto completo da transcrição...",
    "relatorio_soap": {
      "SOAP": {
        "S": {...},
        "O": {...},
        "A": {...},
        "P": {...}
      }
    },
    "custos": {
      "total_usd": 0.0234,
      "total_brl": 0.117,
      "minutos_audio": 3.5
    },
    "metadata": {
      "paciente_id": "12345",
      "medico": "Dr. Silva"
    }
  },
  "signature": "sha256=abc123..."
}

Verificando a Assinatura

Para garantir que o webhook veio realmente da SoulClinic, verificamos cada requisição com HMAC-SHA256:

// webhook-receiver.php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$secret = 'sua_chave_api_aqui';

$expectedSignature = 'sha256=' . hash_hmac('sha256', $payload, $secret);

if (!hash_equals($expectedSignature, $signature)) {
    http_response_code(401);
    die('Assinatura inválida');
}

$data = json_decode($payload, true);

if ($data['event'] === 'consulta.concluida') {
    // Processar consulta concluída
    $consultaId = $data['data']['consulta_id'];
    $transcricao = $data['data']['transcricao'];
    $soap = $data['data']['relatorio_soap'];
    
    // Salvar no banco, enviar email, etc.
}

http_response_code(200);
echo json_encode(['success' => true]);
const crypto = require('crypto');
const express = require('express');
const app = express();

app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
    const signature = req.headers['x-webhook-signature'];
    const secret = 'sua_chave_api_aqui';
    
    const expectedSignature = 'sha256=' + 
        crypto.createHmac('sha256', secret)
              .update(req.body)
              .digest('hex');
    
    if (signature !== expectedSignature) {
        return res.status(401).json({error: 'Assinatura inválida'});
    }
    
    const data = JSON.parse(req.body);
    
    if (data.event === 'consulta.concluida') {
        console.log('Consulta concluída:', data.data.consulta_id);
        // Processar dados...
    }
    
    res.json({success: true});
});
from flask import Flask, request, jsonify
import hmac
import hashlib

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Webhook-Signature', '')
    secret = 'sua_chave_api_aqui'
    payload = request.data
    
    expected_signature = 'sha256=' + hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    
    if not hmac.compare_digest(signature, expected_signature):
        return jsonify({'error': 'Assinatura inválida'}), 401
    
    data = request.get_json()
    
    if data['event'] == 'consulta.concluida':
        consulta_id = data['data']['consulta_id']
        # Processar dados...
    
    return jsonify({'success': True})
Segurança: Sempre valide a assinatura do webhook antes de processar os dados!

Widget JavaScript

Integre facilmente gravação de áudio e processamento em tempo real no seu sistema com nosso widget pronto.

Widget de Gravação SoulClinic

Grave consultas médicas diretamente no navegador com um clique!

Características

Fácil Instalação

Adicione 2 linhas de código e está pronto!

Design Moderno

Interface bonita e responsiva com Bootstrap 5.3

Flutuante

Posicione no canto da tela sem interferir no layout

Feedback Visual

Ondas sonoras animadas durante a gravação

Instalação Rápida

3 Passos Simples:
1
Inclua o Script

Adicione no final do seu HTML, antes do </body>:

<script src="https://soulscribe.soulclinic.com.br/widget/soulclinic-recorder.js"></script>
2
Crie o Container

Adicione uma div onde o widget será renderizado:

<div id="soulclinic-recorder"></div>
3
Inicialize

Configure e inicie o widget:

<script>
const recorder = new SoulClinicRecorder({
    // Container onde o widget será renderizado
    containerId: 'soulclinic-recorder',
    
    // Sua chave de API
    apiKey: 'sua_chave_api_aqui',
    
    // URL da API
    apiUrl: 'https://soulscribe.soulclinic.com.br/api/v1/consultas',
    
    // Posição do widget (opcional)
    position: 'bottom-right', // 'bottom-left', 'bottom-center', 'bottom-right'
    
    // Widget flutuante? (opcional)
    floating: true,
    
    // Callbacks (opcional)
    onSuccess: (resultado) => {
        console.log('Sucesso!', resultado);
        alert('Transcrição: ' + resultado.transcricao);
    },
    
    onError: (erro) => {
        console.error('Erro:', erro);
        alert('Erro: ' + erro.message);
    }
});
</script>

Exemplo Completo

<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>Minha Clínica</title>
</head>
<body>
    <h1>Sistema da Minha Clínica</h1>
    
    <!-- Container do Widget -->
    <div id="soulclinic-recorder"></div>
    
    <!-- Script do Widget -->
    <script src="https://soulscribe.soulclinic.com.br/widget/soulclinic-recorder.js"></script>
    
    <!-- Inicialização -->
    <script>
    const recorder = new SoulClinicRecorder({
        containerId: 'soulclinic-recorder',
        apiKey: 'sua_chave_api_aqui',
        apiUrl: 'https://soulscribe.soulclinic.com.br/api/v1/consultas',
        position: 'bottom-right',
        floating: true,
        
        onSuccess: (resultado) => {
            // Exibir transcrição
            document.getElementById('transcricao').textContent = resultado.transcricao;
            
            // Salvar no seu banco de dados
            fetch('/sua-api/salvar-consulta', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({
                    paciente_id: 12345,
                    transcricao: resultado.transcricao,
                    soap: resultado.relatorio_soap
                })
            });
        },
        
        onError: (erro) => {
            alert('Erro ao processar áudio: ' + erro.message);
        }
    });
    </script>
</body>
</html>

Opções de Configuração

Opção Tipo Padrão Descrição
containerId string - OBRIGATÓRIO ID do elemento HTML
apiKey string - OBRIGATÓRIO Sua chave de API
apiUrl string - OBRIGATÓRIO URL da API
position string 'bottom-right' 'bottom-left', 'bottom-center', 'bottom-right'
floating boolean false Widget flutuante sobre a página
onSuccess function null Callback quando processamento terminar
onError function null Callback em caso de erro
Download: Você pode baixar o widget completo em: soulclinic-recorder.js

Exemplos Práticos

Casos de uso reais para ajudar você a começar rapidamente.

Exemplo 1: Sistema de Telemedicina

// Durante videochamada, gravar consulta
const mediaRecorder = new MediaRecorder(stream);
const chunks = [];

mediaRecorder.ondataavailable = (e) => chunks.push(e.data);

mediaRecorder.onstop = async () => {
    const blob = new Blob(chunks, {type: 'audio/webm'});
    const formData = new FormData();
    formData.append('audio', blob, 'consulta.webm');
    formData.append('metadata', JSON.stringify({
        paciente_id: pacienteAtual.id,
        medico_id: medicoAtual.id,
        especialidade: 'cardiologia'
    }));
    
    const response = await fetch('https://soulscribe.soulclinic.com.br/api/v1/consultas', {
        method: 'POST',
        headers: {
            'X-API-Key': API_KEY_PUBLIC,
            'X-API-Secret': API_KEY_SECRET
        },
        body: formData
    });
    
    const data = await response.json();
    
    // Fazer polling do resultado
    const checkStatus = setInterval(async () => {
        const status = await fetch(data.status_url, {
            headers: {
                'X-API-Key': API_KEY_PUBLIC,
                'X-API-Secret': API_KEY_SECRET
            }
        }).then(r => r.json());
        
        if (status.status_processamento === 'concluido') {
            clearInterval(checkStatus);
            salvarProntuario(status.transcricao, status.relatorio_soap);
        }
    }, 3000);
};

Exemplo 2: Prontuário Eletrônico

// prontuario.php
class ProntuarioService {
    private $apiKey = 'sua_chave_aqui';
    private $apiUrl = 'https://soulscribe.soulclinic.com.br/api/v1/consultas';
    
    public function processarConsulta($audioPath, $pacienteId) {
        $ch = curl_init($this->apiUrl);
        
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => [
                'X-API-Key: ' . $this->apiKeyPublic,
                'X-API-Secret: ' . $this->apiKeySecret
            ],
            CURLOPT_POSTFIELDS => [
                'audio' => new CURLFile($audioPath),
                'webhook_url' => 'https://meu-sistema.com/webhook/consulta',
                'metadata' => json_encode([
                    'paciente_id' => $pacienteId,
                    'timestamp' => date('c')
                ])
            ]
        ]);
        
        $response = json_decode(curl_exec($ch), true);
        curl_close($ch);
        
        // Salvar ID da consulta no banco
        DB::table('consultas_processando')->insert([
            'paciente_id' => $pacienteId,
            'soulclinic_id' => $response['consulta_id'],
            'uuid' => $response['uuid'],
            'status' => 'aguardando'
        ]);
        
        return $response;
    }
    
    public function receberWebhook($payload) {
        // Validar assinatura...
        
        if ($payload['event'] === 'consulta.concluida') {
            DB::table('prontuarios')->insert([
                'paciente_id' => $payload['data']['metadata']['paciente_id'],
                'transcricao' => $payload['data']['transcricao'],
                'soap_subjetivo' => json_encode($payload['data']['relatorio_soap']['SOAP']['S']),
                'soap_objetivo' => json_encode($payload['data']['relatorio_soap']['SOAP']['O']),
                'soap_avaliacao' => json_encode($payload['data']['relatorio_soap']['SOAP']['A']),
                'soap_plano' => json_encode($payload['data']['relatorio_soap']['SOAP']['P']),
                'created_at' => now()
            ]);
        }
    }
}

Exemplo 3: App Mobile (React Native)

import AudioRecorderPlayer from 'react-native-audio-recorder-player';

const ConsultaScreen = () => {
    const [recording, setRecording] = useState(false);
    const audioRecorderPlayer = new AudioRecorderPlayer();
    
    const startRecording = async () => {
        const uri = await audioRecorderPlayer.startRecorder();
        setRecording(true);
    };
    
    const stopRecording = async () => {
        const uri = await audioRecorderPlayer.stopRecorder();
        setRecording(false);
        
        // Enviar para API
        const formData = new FormData();
        formData.append('audio', {
            uri: uri,
            type: 'audio/m4a',
            name: 'consulta.m4a'
        });
        
        const response = await fetch('https://soulscribe.soulclinic.com.br/api/v1/consultas', {
            method: 'POST',
            headers: {
                'X-API-Key': 'sua_chave_publica_aqui',
                'X-API-Secret': 'sua_chave_secreta_aqui'
            },
            body: formData
        });
        
        const data = await response.json();
        navigation.navigate('Resultado', {consultaId: data.consulta_id});
    };
    
    return (
        <View>
            <Button 
                title={recording ? 'Parar' : 'Gravar'}
                onPress={recording ? stopRecording : startRecording}
            />
        </View>
    );
};

Códigos de Erro

Referência completa de erros e como resolvê-los.

Código HTTP Erro Descrição Solução
400 Bad Request Parâmetros inválidos ou arquivo ausente Verifique se enviou o arquivo de áudio corretamente
401 Unauthorized Chaves de API inválidas ou ausentes Verifique se incluiu ambos os headers X-API-Key e X-API-Secret corretamente
403 Forbidden Cota excedida ou conta suspensa Verifique seu plano no dashboard ou entre em contato
404 Not Found Consulta não encontrada Verifique se o ID da consulta está correto
413 Payload Too Large Arquivo maior que 500MB Reduza o tamanho do arquivo ou divida em partes
415 Unsupported Media Type Formato de áudio não suportado Use MP3, WAV, M4A, WebM ou OGG
429 Too Many Requests Rate limit excedido Aguarde alguns segundos antes de tentar novamente
500 Internal Server Error Erro interno no servidor Entre em contato com o suporte
503 Service Unavailable Serviço temporariamente indisponível Tente novamente em alguns minutos

Exemplo de Resposta de Erro

{
  "success": false,
  "error": {
    "code": "INVALID_API_KEY",
    "message": "Chave de API inválida ou expirada",
    "details": "Verifique se sua chave está correta e ativa no dashboard"
  }
}

Limites e Custos

Entenda os limites da API e como são calculados os custos.

Rate Limits

  • Requisições por minuto: 60 (plano básico) / 300 (plano empresarial)
  • Uploads simultâneos: 5 (plano básico) / 20 (plano empresarial)
  • Tamanho máximo: 500MB por arquivo
  • Duração máxima: 4 horas por consulta

Custos de Processamento

Os custos são calculados baseados em:

  • Transcrição: $0.006 por minuto de áudio
  • Geração SOAP: Incluído na transcrição
  • Armazenamento: Grátis por 30 dias, depois $0.01/GB/mês
Exemplo: Uma consulta de 15 minutos custaria: 15 × $0.006 = $0.09 (≈ R$ 0,45)

Headers de Rate Limit

Todas as respostas incluem headers informativos:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1696347600

Precisa de Ajuda?

Nossa equipe está pronta para ajudar você!

Chat

Segunda a Sexta, 9h-18h