CBCTHubCBCTHub
PreciosBlogAyuda
 
 
Volver al blog
apiintegrationtutorialpmsdevelopers

Como integrar seu software de gestão odontológica com o CBCTHub: tutorial completo da API

CBCTHub·24 de junio de 2026

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 ou cbct_test_... para sandbox.
  • Os scopes exams:read e exams: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-ID de 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.

Crie uma conta grátis · Leia a documentação completa

Probar visor gratisVer soluciones

Prueba CBCTHub gratis

Sube, visualiza y comparte examenes DICOM en la nube. Sin instalar nada.

Crear cuenta gratis

Articulos 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

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.

CBCTHubCBCTHub

Entrega digital de CBCT. Processamento 100% local. Sem CDs, nunca.

Disponível naApp Store
Disponível noGoogle Play

Soluções

Centros de imagemRadiologistas odontológicosVisualizador CBCT online

Produto

RecursosPreçosBlogAlternativasAprendaEducaçãoNovoDesenvolvedoresAPIDemo

Suporte

Central de ajudaFAQContatosoporte@cbcthub.comStatus+56 9 7632 9096

Empresa

SobreSegurançaTermos de serviçoPolítica de privacidade

Por país

Brasil
HIPAA-readyGDPRLGPDLey 21.719

© 2026 CBCTHub. Todos os direitos reservados.

AppLab Software LLC · 1021 E Lincolnway, Cheyenne, WY 82001