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

Recursos Disponíveis

Inteligência Artificial
  • Transcrição automática de áudio
  • Geração de relatórios SOAP
  • Processamento em tempo real
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 (v3)

Integre facilmente gravação de áudio e processamento em tempo real no seu sistema com nosso widget v3 (Cápsula).

Widget de Gravação SoulClinic

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

Características

Zero Config

O JS carrega automaticamente estilos e dependências.

Design Cápsula

Interface ultra-compacta, moderna e flutuante.

Feedback Visual

Visualizador de ondas sonoras em tempo real.

Histórico Completo

Painel integrado para ouvir e reenviar gravações antigas.

Instalação Rápida

2 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
Inicialize

Configure e inicie o widget:

<script>
const recorder = new SoulClinicRecorder({
    // Sua chave de API
    apiKey: 'sua_chave_api_aqui',
    
    // URL base da API (importante: sem /consultas no final)
    apiUrl: 'https://soulscribe.soulclinic.com.br/api/v1',
    
    // Callbacks (opcional)
    onSuccess: (resultado) => {
        console.log('Sucesso!', resultado);
        alert('Transcrição concluída!');
    },
    
    onError: (erro) => {
        console.error('Erro:', erro);
    }
});
</script>

Opções de Configuração

Opção Tipo Padrão Descrição
apiKey string - OBRIGATÓRIO Sua chave de API
apiUrl string '/api/v1' URL base da API (o widget adiciona /consultas automaticamente)
containerId string 'soulclinic-recorder' ID do elemento HTML (opcional se floating=true)
floating boolean true Widget flutuante sobre a página (position fixed)
position string 'bottom-right' 'bottom-left', 'bottom-center', 'bottom-right'
historicoHabilitado boolean true Exibe botão e painel de histórico recente
endpointCompleto boolean false Se true, usa a apiUrl exatamente como passada (sem sufixos)
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

1