CBCTHubCBCTHub
PreciosBlogAyuda
 
 
Volver al blog
apiintegrationtutorialpmsdevelopers

Cómo integrar tu software de gestión dental con CBCTHub: tutorial completo de la API

CBCTHub·24 de junio de 2026

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 o cbct_test_... para sandbox.
  • Los scopes exams:read y exams: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-ID de 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.

Crea una cuenta gratis · Lee la documentación 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: 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

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.

CBCTHubCBCTHub

La plataforma de entrega digital de exámenes CBCT. Procesamiento 100% local.

Disponible enApp Store
Disponible enGoogle Play

Soluciones

Centros radiológicosRadiólogos dentalesVisor CBCT online

Producto

FuncionesPreciosBlogAlternativasAprendeEducaciónNuevoDesarrolladoresAPIDemo

Soporte

Centro de ayudaFAQContactosoporte@cbcthub.comStatus+56 9 7632 9096

Empresa

Acerca deSeguridadTérminos de servicioPolítica de privacidad

Por país

ChileMéxicoColombiaArgentinaPerúEcuadorUruguayEspaña
HIPAA-readyGDPRLGPDLey 21.719

© 2026 CBCTHub. Todos los derechos reservados.

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