Referência de endpoints

Todos os endpoints REST da API v1

Referência completa de cada endpoint disponível na API v1. URL base: https://cbcthub.com/api/v1

GET/api/v1/me

Retorna info da sua conta (plano, storage, contagem de exames). Útil para verificar que a key funciona.

json
{
  "user_id": "...",
  "email": "soporte@miclinica.com",
  "plan": "pro",
  "scopes": ["exams:read", "exams:write"],
  "storage": { "used_bytes": 41200000000, "limit_bytes": 375809638400, "used_percent": 11 },
  "exams": { "count": 110, "limit": 999999 }
}
POST/api/v1/exams

Cria um exame e retorna URLs pré-assinadas para upload direto ao R2.

CampoTipoObrigatórioNotas
namestringNome interno do exame (máx 200 chars).
exam_typestringcbct (padrão), radiografia, mesh, atm. Radiografia exige Pro.
patient_namestringNome do paciente. Mostrado no visualizador.
patient_idstringCPF, RG ou número de prontuário.
birth_datestring ISOYYYY-MM-DD.
reasonstringMotivo / achados solicitados.
expiration_daysnumberDias até expirar. null = nunca.
upload_modestring"files" (padrão) ou "zip". No modo zip recebe 1 URL e depois chama /process-zip.
filesarray[{ name, size }]. Obrigatório se upload_mode="files". Mín 1, máx 5000.
zip_size_bytesnumberObrigatório se upload_mode="zip". Máximo 1 GB (1073741824).
GET/api/v1/exams?limit=20&offset=0

Lista os exames da sua conta, paginado. Default limit=20, máx 100.

GET/api/v1/exams/{id}

Detalhes de um exame. Inclui share_url, viewer_url, share_password e public_page_pin.

POST/api/v1/exams/{id}/confirm

Marca o exame como ready após enviar os arquivos (modo files). Idempotente.

POST/api/v1/exams/{id}/process-zip

Para exames criados com upload_mode="zip": descompacta server-side (streaming) o ZIP enviado ao staging, faz upload de cada DICOM ao R2 e marca o exame como ready. Idempotente. Limites: 1 GB de ZIP, 5000 arquivos, 5 GB expandidos, 1,6 TB por arquivo individual, 300 s de timeout.

DELETE/api/v1/exams/{id}

Exclui o exame. Os arquivos no R2 são removidos em background. Idempotente: retorna already_deleted=true se o exame já não existir. Scope: exams:write.

bash
curl -X DELETE "https://cbcthub.com/api/v1/exams/EXAM_ID" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

# → { "deleted": true, "exam_id": "EXAM_ID" }
PATCH/api/v1/exams/{id}

Atualização parcial — apenas os campos enviados são modificados. Permitidos: name, patient_name, patient_id, birth_date, reason, expiration_days, radiograph_subtype (apenas radiografia). Não muda exam_type, share_token, storage nem contadores.

bash
curl -X PATCH "https://cbcthub.com/api/v1/exams/EXAM_ID" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"patient_name":"Juan Pérez","expiration_days":90}'
POST/api/v1/exams/{id}/share

Envia o exame por email ao destinatário. Body: { to, cc?, message?, locale? }. Em sandbox não envia email real (sent=false, reason=test_mode_no_send). Para radiografias anexa as imagens; para CBCT o email leva o link do visualizador.

bash
curl -X POST "https://cbcthub.com/api/v1/exams/EXAM_ID/share" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"paciente@example.com","locale":"es"}'
POST/api/v1/exams/{id}/extras

Inicia uma tomada adicional para CBCT/ATM (multi-tomada). Retorna URLs pré-assinadas para cada arquivo. Body: { label, files: [{name, size}] }. Máximo 2 extras por exame (3 tomadas no total). Não se aplica a radiografias. Scope: exams:write.

bash
curl -X POST "https://cbcthub.com/api/v1/exams/EXAM_ID/extras" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Segunda toma post-ortodoncia",
    "files": [{ "name": "IM0001.dcm", "size": 524288 }]
  }'

# → { "index": 1, "upload_urls": [...], "confirm_url": ".../extras/1/confirm" }
POST/api/v1/exams/{id}/extras/{index}/confirm

Confirma que a tomada extra terminou o envio. Verifica os arquivos no R2 e atualiza extra_series + storage. Body opcional: { label }. Idempotente. Scope: exams:write.

bash
curl -X POST "https://cbcthub.com/api/v1/exams/EXAM_ID/extras/1/confirm" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"label":"Segunda toma post-ortodoncia"}'
GET/api/v1/exams/{id}/access-pin

Retorna o PIN atual + info da página pública do centro. Útil para mostrar o PIN ao paciente sem precisar consultar o dashboard. Scope: exams:read.

bash
curl "https://cbcthub.com/api/v1/exams/EXAM_ID/access-pin" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

# → { "pin": "482931", "clinic_slug": "miclinica", "public_url": "https://cbcthub.com/centro/miclinica" }
POST/api/v1/exams/{id}/access-pin

Rotaciona o PIN: gera um novo e invalida o antigo na hora. Body vazio. Use isto se um paciente vazou o PIN ou após um incidente de segurança. Scope: exams:write.

bash
curl -X POST "https://cbcthub.com/api/v1/exams/EXAM_ID/access-pin" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

# → { "pin": "739184", "rotated_at": "2026-06-27T18:20:11Z" }
GET/api/v1/exams/{id}/embed

Retorna o estado do embed (enabled, token, snippet, view_count). Scope: exams:read.

bash
curl "https://cbcthub.com/api/v1/exams/EXAM_ID/embed" \
  -H "Authorization: Bearer $CBCTHUB_KEY"
POST/api/v1/exams/{id}/embed

Habilita o embed (gera token se não existir). Retorna embed_url e iframe_snippet pronto para colar. Body opcional: { title, show_year, show_study_type }.

bash
curl -X POST "https://cbcthub.com/api/v1/exams/EXAM_ID/embed" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"Caso 12345","show_year":true}'
DELETE/api/v1/exams/{id}/embed

Revoga o embed: apaga o token e quebra a URL existente. Para reativar, chame POST novamente (retorna um token novo). Scope: exams:write.

bash
curl -X DELETE "https://cbcthub.com/api/v1/exams/EXAM_ID/embed" \
  -H "Authorization: Bearer $CBCTHUB_KEY"
GET/api/v1/exams/{id}/thumbnail

Baixa o thumbnail do exame (JPEG/PNG) em binário. Retorna 404 com thumbnail_not_ready se ainda não foi gerado. Ideal para mostrar miniaturas na sua UI. Scope: exams:read.

bash
curl -o thumb.jpg "https://cbcthub.com/api/v1/exams/EXAM_ID/thumbnail" \
  -H "Authorization: Bearer $CBCTHUB_KEY"
GET/api/v1/exams/{id}/patient-exams

Lista os outros exames do mesmo paciente (match por patient_id; fallback ao nome normalizado). Útil para mostrar histórico ou habilitar comparadores. Scope: exams:read.

bash
curl "https://cbcthub.com/api/v1/exams/EXAM_ID/patient-exams" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

# → { "exams": [{ "id": "...", "name": "...", "exam_type": "cbct", "created_at": "..." }] }

Consentimento informado

Fluxo legal completo: inicialização por país/idioma, assinatura presencial (paciente presente com um tablet) ou por email (link enviado ao paciente), download do PDF assinado com SHA-256 e QR de verificação pública.

GET/api/v1/exams/{id}/consent

Retorna o estado atual do consentimento (status, signing_method, signed_at, hash). Se ainda não foi inicializado, retorna { consent: null }. Scope: exams:read.

bash
curl "https://cbcthub.com/api/v1/exams/EXAM_ID/consent" \
  -H "Authorization: Bearer $CBCTHUB_KEY"
POST/api/v1/exams/{id}/consent

Inicializa (ou re-inicializa se estiver pending) o consentimento. Body opcional: { country_code, locale }. Retorna 409 se já estiver assinado. Scope: exams:write.

bash
curl -X POST "https://cbcthub.com/api/v1/exams/EXAM_ID/consent" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"country_code":"CL","locale":"es"}'
POST/api/v1/exams/{id}/consent/sign-inperson

Assinatura presencial. Body: { signer_name, signer_rut, patient_birth_date?, signature_image (PNG base64), accepted: true }. O servidor gera o PDF assinado e calcula SHA-256. Scope: exams:write.

bash
curl -X POST "https://cbcthub.com/api/v1/exams/EXAM_ID/consent/sign-inperson" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "signer_name": "Juan Perez",
    "signer_rut": "12345678-9",
    "signature_image": "iVBORw0KGgoAAAANSUhEUgAA...",
    "accepted": true
  }'
POST/api/v1/exams/{id}/consent/email

Envia o link de assinatura ao paciente. Body: { to, patient_name? }. Em sandbox não envia email real. Retorna sign_url para que você também possa renderizá-lo como QR. Scope: exams:write.

bash
curl -X POST "https://cbcthub.com/api/v1/exams/EXAM_ID/consent/email" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"paciente@example.com","patient_name":"Juan Perez"}'
GET/api/v1/exams/{id}/consent/pdf?type=blank|signed

Baixa o PDF binário do consentimento. type=blank retorna o documento não assinado (útil para imprimir). type=signed exige que o consentimento esteja assinado. Scope: exams:read.

bash
curl -o consent.pdf \
  "https://cbcthub.com/api/v1/exams/EXAM_ID/consent/pdf?type=signed" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

Laudos radiológicos

Endpoints para enviar, ler, excluir e assinar eletronicamente laudos em PDF. Detalhes completos na seção API de laudos.

POST/api/v1/exams/{id}/report

Envia ou substitui o PDF do laudo. Body: { pdf_base64, filename? }.

GET/api/v1/exams/{id}/report

Retorna URL pré-assinada do PDF + dados de assinatura se estiver assinado.

DELETE/api/v1/exams/{id}/report

Exclui o laudo. Idempotente: retorna 200 mesmo se não existir.

POST/api/v1/exams/{id}/report/sign

Assina eletronicamente o laudo. Retorna signature_id e URL pública de verificação.

Webhooks

Endpoints para gerenciar subscriptions de webhooks. Detalhes completos (eventos, assinatura HMAC, retries) na seção Webhooks.

POST/api/v1/webhooks

Cria uma subscription. Retorna o secret UMA ÚNICA VEZ.

GET/api/v1/webhooks

Lista todas as subscriptions da conta.

GET/api/v1/webhooks/{id}

Detalhes de uma subscription.

PATCH/api/v1/webhooks/{id}

Atualiza events, description ou enabled.

DELETE/api/v1/webhooks/{id}

Exclui a subscription. Não pode ser reativada.

POST/api/v1/webhooks/{id}/test

Envia um ping de teste ao endpoint configurado.

GET/api/v1/webhooks/{id}/deliveries

Audit log das últimas 50 entregas (status, response, retry count).

Solicitantes (Referrers)

CRUD do diretório de dentistas solicitantes. Novos scopes: referrers:read e referrers:write. Sandbox: as leituras retornam lista vazia e as escritas retornam um mock com id "rfr_test_*" sem persistir, assim você pode testar a integração sem sujar a base produtiva.

GET/api/v1/referrers

Lista todos os solicitantes da conta, ordenados alfabeticamente por nome. Scope: referrers:read.

bash
curl "https://cbcthub.com/api/v1/referrers" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

# → { "referrers": [{ "id": "rfr_...", "name": "Dra. Maria Lopez", "email": "...", "specialty": "..." }] }
POST/api/v1/referrers

Cria um solicitante. Body: { name (obrigatório), email?, phone?, specialty? }.

bash
curl -X POST "https://cbcthub.com/api/v1/referrers" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Dra. Maria Lopez","email":"maria@example.com","specialty":"Endodoncia"}'
GET/api/v1/referrers/{id}

Detalhe de um solicitante. Scope: referrers:read.

PATCH/api/v1/referrers/{id}

Atualização parcial — apenas os campos enviados são modificados. Scope: referrers:write.

bash
curl -X PATCH "https://cbcthub.com/api/v1/referrers/rfr_xyz" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"phone":"+56 9 1234 5678"}'
DELETE/api/v1/referrers/{id}

Exclui o solicitante. Idempotente: retorna already_deleted=true se não existir. Scope: referrers:write.

bash
curl -X DELETE "https://cbcthub.com/api/v1/referrers/rfr_xyz" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

Modelos de laudo (Templates)

CRUD de modelos de placas para laudos radiológicos. Modelos com is_default=true são do sistema, visíveis para todos os usuários, e não podem ser editados nem excluídos. Novos scopes: templates:read e templates:write. Sandbox: GET retorna apenas os defaults e os writes são no-op (mock com id "tpl_test_*").

GET/api/v1/templates

Lista os modelos visíveis (defaults do sistema + os próprios do usuário). Scope: templates:read.

bash
curl "https://cbcthub.com/api/v1/templates" \
  -H "Authorization: Bearer $CBCTHUB_KEY"
POST/api/v1/templates

Cria um modelo do usuário. Body: { name, description?, pages: PageDef[] }. Cada página: { name?, slots: [{ x, y, w, h, label? }] } com coordenadas 0..1. Scope: templates:write.

bash
curl -X POST "https://cbcthub.com/api/v1/templates" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Periapical 14 placas",
    "pages": [{
      "name": "Pagina 1",
      "slots": [
        { "x": 0.05, "y": 0.05, "w": 0.2, "h": 0.3, "label": "11" },
        { "x": 0.30, "y": 0.05, "w": 0.2, "h": 0.3, "label": "12" }
      ]
    }]
  }'
GET/api/v1/templates/{id}

Detalhe de um modelo (do sistema ou próprio). Scope: templates:read.

bash
curl "https://cbcthub.com/api/v1/templates/tpl_xyz" \
  -H "Authorization: Bearer $CBCTHUB_KEY"
PATCH/api/v1/templates/{id}

Atualiza um modelo próprio. Os defaults do sistema retornam 400. Scope: templates:write.

bash
curl -X PATCH "https://cbcthub.com/api/v1/templates/tpl_xyz" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Periapical 14 placas v2"}'
DELETE/api/v1/templates/{id}

Exclui um modelo próprio. Idempotente. Os defaults do sistema retornam 400. Scope: templates:write.

bash
curl -X DELETE "https://cbcthub.com/api/v1/templates/tpl_xyz" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

Catálogo de implantes

Catálogo global de modelos de implantes (brand, product_line, comprimento e diâmetro). Somente leitura. Recurso de referência, não por-usuário: usa o scope exams:read. Sandbox: o catálogo é idêntico ao live.

GET/api/v1/implants

Sem parâmetros retorna a lista de marcas com count(*). Filtros: ?brand=Neodent (modelos dessa marca), ?search=helix (texto livre em brand+product_line), ?length=11.5&diameter=4 (busca inversa por dimensão; também retorna near_matches em ±0.5 mm). Suporta ?limit= e ?offset=.

bash
curl "https://cbcthub.com/api/v1/implants?brand=Neodent&limit=20" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

# Busqueda por dimension
curl "https://cbcthub.com/api/v1/implants?length=11.5&diameter=4" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

Tickets de suporte

Cria e lê tickets de suporte programaticamente. Novos scopes: support:read e support:write. Ao criar um ticket em live envia email à equipe de suporte e um email de confirmação ao solicitante. Sandbox: NÃO persiste, NÃO envia emails, retorna um mock com id "tkt_test_*" e test_mode=true.

GET/api/v1/support/tickets

Lista os 50 tickets mais recentes da conta (configurável com ?limit=). Scope: support:read.

bash
curl "https://cbcthub.com/api/v1/support/tickets?limit=20" \
  -H "Authorization: Bearer $CBCTHUB_KEY"
POST/api/v1/support/tickets

Cria um ticket. Body: { subject, message, category?, exam_id? }. Categorias válidas: general, bug, billing, feature_request, account, viewer.

bash
curl -X POST "https://cbcthub.com/api/v1/support/tickets" \
  -H "Authorization: Bearer $CBCTHUB_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subject":"Mi examen no se subio",
    "message":"Subi un ZIP de 800 MB y aparece pending desde hace 2 horas.",
    "category":"bug",
    "exam_id":"b1f7c9c6-8c10-4d27-8d80-93e1f1a5d4af"
  }'
GET/api/v1/support/tickets/{id}

Detalhe do ticket + lista de respostas do admin (em ordem cronológica). Scope: support:read.

bash
curl "https://cbcthub.com/api/v1/support/tickets/tkt_xyz" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

# → { "ticket": {...}, "replies": [{ "body": "...", "created_at": "..." }] }

Activity e notificações

Lê o log de atividade da conta e as notificações geradas (respostas de suporte, eventos do sistema). Novos scopes: account:read e account:write. Sandbox: retorna listas vazias.

GET/api/v1/activity

Log de atividade paginado (descendente). Query: ?limit=50 (1-100), ?before=ISO_DATE (cursor — use next_cursor da resposta), ?action=exam.created (filtro opcional).

bash
curl "https://cbcthub.com/api/v1/activity?limit=20&action=exam.created" \
  -H "Authorization: Bearer $CBCTHUB_KEY"
GET/api/v1/notifications

Lista as notificações genéricas + unread_count. Query: ?unread_only=true, ?limit=30. NÃO inclui aberturas de exames (esses eventos viajam por webhooks). Scope: account:read.

bash
curl "https://cbcthub.com/api/v1/notifications?unread_only=true&limit=30" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

# → { "notifications": [...], "unread_count": 4 }
POST/api/v1/notifications/{id}/mark-read

Marca uma notificação como lida. Idempotente. Scope: account:write.

bash
curl -X POST "https://cbcthub.com/api/v1/notifications/ntf_xyz/mark-read" \
  -H "Authorization: Bearer $CBCTHUB_KEY"
POST/api/v1/notifications/mark-all-read

Marca TODAS as não lidas como lidas e retorna marked_count. Scope: account:write.

bash
curl -X POST "https://cbcthub.com/api/v1/notifications/mark-all-read" \
  -H "Authorization: Bearer $CBCTHUB_KEY"

# → { "marked_count": 4 }

Teste estes endpoints ao vivo

Os playgrounds abaixo executam chamadas REAIS contra sua conta. Para testar sem afetar a produção, use uma key cbct_test_* (crie em Ajustes → API, aba Sandbox).

GET /api/v1/exams

GET/api/v1/examsScope: exams:readTeste agora

Lista os exames da sua conta, paginados (mais recentes primeiro).

Cole aqui uma API key (live ou test) gerada em Ajustes → API. Criar ou gerenciar keys →

Parâmetros de query

Request

GET https://cbcthub.com/api/v1/exams?limit=5&offset=0
Cole sua API key acima para habilitar o botão.

Sua API key fica salva só neste navegador durante a sessão. Não é enviada ao CBCTHub fora da request, e some quando você fecha a aba.

POST /api/v1/exams

POST/api/v1/examsScope: exams:writeTeste agora

Cria um exame e obtém URLs pré-assinadas para upload direto ao R2.

Cole aqui uma API key (live ou test) gerada em Ajustes → API. Criar ou gerenciar keys →

Body JSON

Request

POST https://cbcthub.com/api/v1/exams
Cole sua API key acima para habilitar o botão.

Sua API key fica salva só neste navegador durante a sessão. Não é enviada ao CBCTHub fora da request, e some quando você fecha a aba.

GET /api/v1/exams/{id}

GET/api/v1/exams/{id}Scope: exams:readTeste agora

Detalhes de um exame. Você precisa de um id da sua conta (obtenha-o no playground da lista acima).

Cole aqui uma API key (live ou test) gerada em Ajustes → API. Criar ou gerenciar keys →

Parâmetros de path

Request

GET https://cbcthub.com/api/v1/exams/{id}
Cole sua API key acima para habilitar o botão.

Sua API key fica salva só neste navegador durante a sessão. Não é enviada ao CBCTHub fora da request, e some quando você fecha a aba.

POST /api/v1/webhooks

POST/api/v1/webhooksScope: webhooks:writeTeste agora

Cria uma subscription de webhook. A response retorna o secret UMA ÚNICA VEZ.

Cole aqui uma API key (live ou test) gerada em Ajustes → API. Criar ou gerenciar keys →

Body JSON

Request

POST https://cbcthub.com/api/v1/webhooks
Cole sua API key acima para habilitar o botão.

Sua API key fica salva só neste navegador durante a sessão. Não é enviada ao CBCTHub fora da request, e some quando você fecha a aba.

POST /api/v1/webhooks/{id}/test

POST/api/v1/webhooks/{id}/testScope: webhooks:writeTeste agora

Envia um ping de teste (test.ping) ao endpoint configurado.

Cole aqui uma API key (live ou test) gerada em Ajustes → API. Criar ou gerenciar keys →

Parâmetros de path

Body JSON

Request

POST https://cbcthub.com/api/v1/webhooks/{id}/test
Cole sua API key acima para habilitar o botão.

Sua API key fica salva só neste navegador durante a sessão. Não é enviada ao CBCTHub fora da request, e some quando você fecha a aba.