Cómo integrar tu software de gestión dental con CBCTHub: tutorial completo de la API
Si construyes o mantienes un software de gestión para clínicas dentales, tus clientes no deberían tener que salir de tu app para compartir una tomografía CBCT. No deberían grabar CDs, adjuntar ZIPs DICOM de 800 MB por correo, ni copiar nombres de pacientes entre sistemas. Este tutorial recorre una integración lista para producción con la API REST de CBCTHub: crear el examen, subir los archivos DICOM, confirmar, escuchar webhooks y embeber el visor dentro de tu PMS.
Todo lo siguiente apunta a https://cbcthub.com/api/v1 y funciona contra una cuenta real. Los ejemplos están en Node.js, Python y PHP.
Qué ganas al integrar
- Un único flujo para el usuario de recepción: sube el DICOM desde el PMS y obtén un link compartible automáticamente.
- Visor 3D embebido en la ficha del paciente, sin instalar plugins.
- Entrega automática por correo o WhatsApp al dentista derivador, con el logo y la marca del centro.
- Notificaciones webhook para que tu PMS marque la cita como "entregada" en el momento exacto en que el examen está listo.
Prerrequisitos
- Una cuenta CBCTHub (Free sirve para desarrollo, Pro o superior para producción).
- Una API key desde Ajustes → API keys. Formato:
cbct_live_...para producción ocbct_test_...para sandbox. - Los scopes
exams:readyexams:write. - Un entorno de servidor. Nunca llames a la API desde el navegador — tu key quedaría expuesta.
Verificación rápida
Antes de escribir código, comprueba que la key funciona:
curl -H "Authorization: Bearer cbct_test_..." \
https://cbcthub.com/api/v1/me
Una respuesta 200 con tu user_id, plan y cuota de almacenamiento confirma que estás listo.
Paso 1: Crear el examen
Haz POST a /api/v1/exams con los metadatos del paciente y la lista de archivos o el tamaño del ZIP. El endpoint soporta dos modos de subida:
upload_mode: "files"(por defecto): envías N archivos y recibes N URLs presignadas. Recomendado cuando tu PMS ya conoce la estructura del DICOM.upload_mode: "zip": envías un único ZIP y el servidor lo descomprime. Recomendado cuando el tomógrafo genera una carpeta que quieres enviar tal cual.
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 — planificación implante #46',
exam_type: 'cbct',
patient_name: 'Ana Morales',
patient_id: 'RUT-19234567-K',
birth_date: '1978-03-12',
reason: 'Planificación de implante en pieza 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 — planificación implante #46',
'exam_type': 'cbct',
'patient_name': 'Ana Morales',
'expiration_days': 90,
'upload_mode': 'zip',
'zip_size_bytes': os.path.getsize('estudio.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' => 'Ana Morales',
'expiration_days' => 90,
'upload_mode' => 'files',
'files' => $fileList,
]),
]);
$response = json_decode(curl_exec($ch), true);
Paso 2: Subir los archivos
Las URLs presignadas que devuelve la creación apuntan directo a Cloudflare R2. Tu cliente (o tu servidor) hace PUT con los bytes crudos: estas peticiones no cuentan contra tu rate limit y no pasan por servidores de CBCTHub. Una tomografía de 500 MB sube a la velocidad total de tu conexión.
Modo files — subidas concurrentes
// Node.js — subir todos los slices con concurrencia 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 — una sola subida + descompresión server-side
// 1. PUT del ZIP a la URL de staging
await fetch(upload_urls[0].url, {
method: 'PUT',
body: fs.readFileSync('estudio.zip'),
});
// 2. Pide al servidor que lo procese
const procRes = await fetch(`https://cbcthub.com/api/v1/exams/${exam_id}/process-zip`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.CBCTHUB_KEY}` },
});
// La respuesta incluye el conteo final de archivos y status: 'ready'
Paso 3: Confirmar el examen
En modo files debes cerrar el examen explícitamente cuando todos los PUT terminaron. El modo ZIP confirma automáticamente vía /process-zip.
await fetch(confirm_url, {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.CBCTHUB_KEY}` },
});
El examen pasa de uploading a ready. Las URLs de visor y de compartir devueltas en el paso 1 quedan activas.
Paso 4: Recibir webhooks
En lugar de hacer polling en bucle a GET /v1/exams/{id}, registra un endpoint webhook y deja que CBCTHub notifique a tu PMS cuando el examen esté listo, sea visto o firmado. Cada evento viene firmado con HMAC SHA-256 en la cabecera X-CBCTHub-Signature y trae un identificador único X-CBCTHub-Delivery para idempotencia.
// Verificación en 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('firma inválida');
}
const event = JSON.parse(req.body.toString());
// event.type: 'exam.created' | 'exam.confirmed' | 'report.published' | ...
return res.status(200).send('ok');
});
El catálogo completo de eventos está en la referencia de webhooks.
Paso 5: Embeber el visor
La forma más simple de mostrar el examen dentro de tu PMS es insertar un iframe con la viewer_url que devolvió la creación. El visor se adapta a móvil y soporta MPR, panorámica, 3D y mallas STL.
<iframe
src="https://cbcthub.com/viewer/a3f9b1c2-d4e5-..."
width="100%"
height="720"
allow="fullscreen"
style="border: 0;"
></iframe>
Si necesitas un embed anonimizado (sin nombre del paciente visible), usa el endpoint de embed token descrito en la referencia de endpoints.
Buenas prácticas en producción
- Idempotencia: si la creación se cae por timeout, reintenta con el mismo payload — los duplicados se filtran en el servidor con un hash de
(patient_id, name, cantidad de archivos). - Reintentos: backoff exponencial solo en 429 (respeta
Retry-After) y 5xx. Nunca reintentes otros 4xx. - Gestión de secretos: guarda la key en tu secret manager (AWS Secrets Manager, Vault, Doppler). Rota cada 90 días.
- Sandbox primero: usa keys
cbct_test_durante el desarrollo. Los datos de prueba están aislados y no consumen storage. - Observabilidad: registra la cabecera
X-Request-IDde cada respuesta. Es la forma más rápida de pedir soporte cuando algo falla.
Conclusión
Una integración completa entre un PMS dental y CBCTHub son aproximadamente 200 líneas de código: crear, subir, confirmar, escuchar, embeber. A partir de ahí tus clientes reciben CBCT al instante sin salir de tu producto y tú obtienes una funcionalidad defendible en tus conversaciones de venta con dentistas derivadores.
Prueba CBCTHub gratis
Sube, visualiza y comparte examenes DICOM en la nube. Sin instalar nada.
Crear cuenta gratisArticulos relacionados
Webhooks vs polling: notificaciones de exámenes en tiempo real para flujos de imagen dental
Hacer polling cada 30 segundos desperdicia cómputo en la nube y descarga la batería del móvil. Te mostramos cómo construir notificaciones CBCT en tiempo real con webhooks HMAC.
APIs de imagen dental con cumplimiento HIPAA: lista de verificación de seguridad para integraciones en salud de EE. UU.
Lista de 10 puntos para garantizar el cumplimiento HIPAA en cualquier integración de API de imagen dental en EE. UU. Cifrado, BAAs, audit logs, notificación de brechas.
Proteccion de datos de pacientes en Mexico: guia LFPDPPP, INAI y NOM-024 para centros radiologicos dentales
Como cumplir la LFPDPPP, su Reglamento, la NOM-024-SSA3-2012 y la NOM-004 en una clinica de imagen dental. INAI, Aviso de Privacidad, multas en UMA. Como ayuda CBCTHub.