Como integrar seu software de gestão odontológica com o CBCTHub: tutorial completo da API
Se você desenvolve ou mantém um software de gestão para clínicas odontológicas, seus clientes não deveriam precisar sair do seu app para compartilhar uma tomografia CBCT. Não deveriam gravar CDs, anexar ZIPs DICOM de 800 MB por e-mail, nem copiar nomes de pacientes entre sistemas. Este tutorial percorre uma integração pronta para produção com a API REST do CBCTHub: criar o exame, enviar os arquivos DICOM, confirmar, escutar webhooks e embutir o visualizador dentro do seu PMS.
Tudo abaixo aponta para https://cbcthub.com/api/v1 e funciona contra uma conta real. Os exemplos estão em Node.js, Python e PHP.
O que você ganha integrando
- Um único fluxo para o usuário da recepção: envia o DICOM de dentro do PMS e recebe um link compartilhável automaticamente.
- Visualizador 3D embutido na ficha do paciente, sem instalar plugins.
- Entrega automática por e-mail ou WhatsApp ao dentista solicitante, com o logo e a marca da clínica.
- Notificações via webhook para que seu PMS marque a consulta como "entregue" no momento exato em que o exame fica pronto.
Pré-requisitos
- Uma conta CBCTHub (Free serve para desenvolvimento, Pro ou superior para produção).
- Uma API key em Configurações → API keys. Formato:
cbct_live_...para produção oucbct_test_...para sandbox. - Os scopes
exams:readeexams:write. - Um ambiente server-side. Nunca chame a API pelo navegador — sua key ficaria exposta.
Verificação rápida
Antes de escrever código, confirme que a key funciona:
curl -H "Authorization: Bearer cbct_test_..." \
https://cbcthub.com/api/v1/me
Uma resposta 200 com seu user_id, plano e cota de armazenamento confirma que você está pronto.
Passo 1: Criar o exame
Faça POST em /api/v1/exams com os metadados do paciente e a lista de arquivos ou o tamanho do ZIP. O endpoint suporta dois modos de envio:
upload_mode: "files"(padrão): você envia N arquivos e recebe N URLs pré-assinadas. Recomendado quando seu PMS já conhece a estrutura do DICOM.upload_mode: "zip": você envia um único ZIP e o servidor descompacta. Recomendado quando o tomógrafo gera uma pasta que você quer enviar como está.
Node.js — modo files
const res = await fetch('https://cbcthub.com/api/v1/exams', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.CBCTHUB_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'CBCT mandíbula — planejamento implante #46',
exam_type: 'cbct',
patient_name: 'Marina Souza',
patient_id: 'CPF-123.456.789-00',
birth_date: '1978-03-12',
reason: 'Planejamento de implante no dente 46',
expiration_days: 90,
upload_mode: 'files',
files: dicomFiles.map(f => ({ name: f.name, size: f.size })),
}),
});
const { exam_id, upload_urls, confirm_url, share_url, viewer_url } = await res.json();
Python — modo ZIP
import os, requests
resp = requests.post(
'https://cbcthub.com/api/v1/exams',
headers={
'Authorization': f"Bearer {os.environ['CBCTHUB_KEY']}",
'Content-Type': 'application/json',
},
json={
'name': 'CBCT mandíbula — planejamento implante #46',
'exam_type': 'cbct',
'patient_name': 'Marina Souza',
'expiration_days': 90,
'upload_mode': 'zip',
'zip_size_bytes': os.path.getsize('estudo.zip'),
},
timeout=30,
)
resp.raise_for_status()
data = resp.json()
PHP
$ch = curl_init('https://cbcthub.com/api/v1/exams');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CBCTHUB_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'CBCT mandíbula — implante #46',
'exam_type' => 'cbct',
'patient_name' => 'Marina Souza',
'expiration_days' => 90,
'upload_mode' => 'files',
'files' => $fileList,
]),
]);
$response = json_decode(curl_exec($ch), true);
Passo 2: Enviar os arquivos
As URLs pré-assinadas devolvidas pela criação apontam direto para o Cloudflare R2. Seu cliente (ou seu servidor) faz PUT com os bytes brutos: essas requisições não contam contra o rate limit e não passam pelos servidores do CBCTHub. Uma tomografia de 500 MB sobe na velocidade total da sua conexão.
Modo files — envios concorrentes
// Node.js — enviar todos os slices com concorrência limitada a 5
import pLimit from 'p-limit';
const limit = pLimit(5);
await Promise.all(
upload_urls.map((u, i) =>
limit(() => fetch(u.url, { method: 'PUT', body: dicomFiles[i].buffer }))
)
);
Modo ZIP — um único envio + descompactação no servidor
// 1. PUT do ZIP para a URL de staging
await fetch(upload_urls[0].url, {
method: 'PUT',
body: fs.readFileSync('estudo.zip'),
});
// 2. Peça ao servidor que processe
const procRes = await fetch(`https://cbcthub.com/api/v1/exams/${exam_id}/process-zip`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.CBCTHUB_KEY}` },
});
// A resposta inclui a contagem final de arquivos e status: 'ready'
Passo 3: Confirmar o exame
No modo files você precisa fechar o exame explicitamente quando todos os PUT terminarem. O modo ZIP confirma automaticamente via /process-zip.
await fetch(confirm_url, {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.CBCTHUB_KEY}` },
});
O exame passa de uploading para ready. As URLs de visualizador e de compartilhamento devolvidas no passo 1 ficam ativas.
Passo 4: Receber webhooks
Em vez de fazer polling em loop em GET /v1/exams/{id}, registre um endpoint webhook e deixe que o CBCTHub avise seu PMS quando o exame estiver pronto, for visto ou assinado. Cada evento vem assinado com HMAC SHA-256 no header X-CBCTHub-Signature e traz um identificador único X-CBCTHub-Delivery para idempotência.
// Verificação no Express
import crypto from 'crypto';
app.post('/cbcthub/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.header('X-CBCTHub-Signature') ?? '';
const expected = crypto
.createHmac('sha256', process.env.CBCTHUB_WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.status(401).send('assinatura inválida');
}
const event = JSON.parse(req.body.toString());
// event.type: 'exam.created' | 'exam.confirmed' | 'report.published' | ...
return res.status(200).send('ok');
});
O catálogo completo de eventos está na referência de webhooks.
Passo 5: Embutir o visualizador
A forma mais simples de mostrar o exame dentro do seu PMS é inserir um iframe com a viewer_url devolvida pela criação. O visualizador se adapta a celular e suporta MPR, panorâmica, 3D e malhas STL.
<iframe
src="https://cbcthub.com/viewer/a3f9b1c2-d4e5-..."
width="100%"
height="720"
allow="fullscreen"
style="border: 0;"
></iframe>
Se precisar de um embed anonimizado (sem o nome do paciente visível), use o endpoint de embed token descrito na referência de endpoints.
Boas práticas em produção
- Idempotência: se a criação cair por timeout, faça novamente com o mesmo payload — duplicatas são filtradas no servidor com um hash de
(patient_id, name, quantidade de arquivos). - Retries: backoff exponencial apenas em 429 (respeite o
Retry-After) e 5xx. Nunca tente novamente outros 4xx. - Gestão de segredos: guarde a key no seu secret manager (AWS Secrets Manager, Vault, Doppler). Rotacione a cada 90 dias.
- Sandbox primeiro: use keys
cbct_test_durante o desenvolvimento. Os dados de teste ficam isolados e não consomem storage. - Observabilidade: registre o header
X-Request-IDde cada resposta. É a forma mais rápida de pedir suporte quando algo falha.
Conclusão
Uma integração completa entre um PMS odontológico e o CBCTHub gira em torno de 200 linhas de código: criar, enviar, confirmar, escutar, embutir. A partir daí seus clientes recebem CBCT instantaneamente sem sair do seu produto, e você ganha uma funcionalidade defensável nas conversas de venda com dentistas solicitantes.
Prueba CBCTHub gratis
Sube, visualiza y comparte examenes DICOM en la nube. Sin instalar nada.
Crear cuenta gratisArticulos relacionados
Webhooks vs polling: notificações de exames em tempo real para fluxos de imagem odontológica
Fazer polling a cada 30 segundos desperdiça computação na nuvem e drena bateria do celular. Veja como construir notificações CBCT em tempo real com webhooks HMAC.
APIs de imagem odontológica compatíveis com HIPAA: lista de verificação de segurança para integrações de saúde nos EUA
Checklist de 10 pontos para garantir compliance HIPAA em qualquer integração de API de imagem odontológica nos EUA. Criptografia, BAAs, audit logs, notificação de brechas.
Protecao de dados de pacientes nos EUA: guia HIPAA e HITECH para centros de radiologia dentaria
Como cumprir HIPAA (Public Law 104-191), Privacy Rule, Security Rule e HITECH Act em uma clinica de imagem dentaria. PHI, BAA, multas OCR ate USD 1.5M por ano.