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
/api/v1/meRetorna info da sua conta (plano, storage, contagem de exames). Útil para verificar que a key funciona.
{
"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 }
}/api/v1/examsCria um exame e retorna URLs pré-assinadas para upload direto ao R2.
| Campo | Tipo | Obrigatório | Notas |
|---|---|---|---|
| name | string | ✓ | Nome interno do exame (máx 200 chars). |
| exam_type | string | — | cbct (padrão), radiografia, mesh, atm. Radiografia exige Pro. |
| patient_name | string | — | Nome do paciente. Mostrado no visualizador. |
| patient_id | string | — | CPF, RG ou número de prontuário. |
| birth_date | string ISO | — | YYYY-MM-DD. |
| reason | string | — | Motivo / achados solicitados. |
| expiration_days | number | — | Dias até expirar. null = nunca. |
| upload_mode | string | — | "files" (padrão) ou "zip". No modo zip recebe 1 URL e depois chama /process-zip. |
| files | array | — | [{ name, size }]. Obrigatório se upload_mode="files". Mín 1, máx 5000. |
| zip_size_bytes | number | — | Obrigatório se upload_mode="zip". Máximo 1 GB (1073741824). |
/api/v1/exams?limit=20&offset=0Lista os exames da sua conta, paginado. Default limit=20, máx 100.
/api/v1/exams/{id}Detalhes de um exame. Inclui share_url, viewer_url, share_password e public_page_pin.
/api/v1/exams/{id}/confirmMarca o exame como ready após enviar os arquivos (modo files). Idempotente.
/api/v1/exams/{id}/process-zipPara 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.
/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.
curl -X DELETE "https://cbcthub.com/api/v1/exams/EXAM_ID" \
-H "Authorization: Bearer $CBCTHUB_KEY"
# → { "deleted": true, "exam_id": "EXAM_ID" }/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.
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}'/api/v1/exams/{id}/shareEnvia 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.
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"}'/api/v1/exams/{id}/extrasInicia 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.
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" }/api/v1/exams/{id}/extras/{index}/confirmConfirma que a tomada extra terminou o envio. Verifica os arquivos no R2 e atualiza extra_series + storage. Body opcional: { label }. Idempotente. Scope: exams:write.
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"}'/api/v1/exams/{id}/access-pinRetorna 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.
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" }/api/v1/exams/{id}/access-pinRotaciona 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.
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" }/api/v1/exams/{id}/embedRetorna o estado do embed (enabled, token, snippet, view_count). Scope: exams:read.
curl "https://cbcthub.com/api/v1/exams/EXAM_ID/embed" \
-H "Authorization: Bearer $CBCTHUB_KEY"/api/v1/exams/{id}/embedHabilita 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 }.
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}'/api/v1/exams/{id}/embedRevoga o embed: apaga o token e quebra a URL existente. Para reativar, chame POST novamente (retorna um token novo). Scope: exams:write.
curl -X DELETE "https://cbcthub.com/api/v1/exams/EXAM_ID/embed" \
-H "Authorization: Bearer $CBCTHUB_KEY"/api/v1/exams/{id}/thumbnailBaixa 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.
curl -o thumb.jpg "https://cbcthub.com/api/v1/exams/EXAM_ID/thumbnail" \
-H "Authorization: Bearer $CBCTHUB_KEY"/api/v1/exams/{id}/patient-examsLista 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.
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.
/api/v1/exams/{id}/consentRetorna o estado atual do consentimento (status, signing_method, signed_at, hash). Se ainda não foi inicializado, retorna { consent: null }. Scope: exams:read.
curl "https://cbcthub.com/api/v1/exams/EXAM_ID/consent" \
-H "Authorization: Bearer $CBCTHUB_KEY"/api/v1/exams/{id}/consentInicializa (ou re-inicializa se estiver pending) o consentimento. Body opcional: { country_code, locale }. Retorna 409 se já estiver assinado. Scope: exams:write.
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"}'/api/v1/exams/{id}/consent/sign-inpersonAssinatura 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.
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
}'/api/v1/exams/{id}/consent/emailEnvia 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.
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"}'/api/v1/exams/{id}/consent/pdf?type=blank|signedBaixa 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.
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.
/api/v1/exams/{id}/reportEnvia ou substitui o PDF do laudo. Body: { pdf_base64, filename? }.
/api/v1/exams/{id}/reportRetorna URL pré-assinada do PDF + dados de assinatura se estiver assinado.
/api/v1/exams/{id}/reportExclui o laudo. Idempotente: retorna 200 mesmo se não existir.
/api/v1/exams/{id}/report/signAssina 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.
/api/v1/webhooksCria uma subscription. Retorna o secret UMA ÚNICA VEZ.
/api/v1/webhooksLista todas as subscriptions da conta.
/api/v1/webhooks/{id}Detalhes de uma subscription.
/api/v1/webhooks/{id}Atualiza events, description ou enabled.
/api/v1/webhooks/{id}Exclui a subscription. Não pode ser reativada.
/api/v1/webhooks/{id}/testEnvia um ping de teste ao endpoint configurado.
/api/v1/webhooks/{id}/deliveriesAudit 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.
/api/v1/referrersLista todos os solicitantes da conta, ordenados alfabeticamente por nome. Scope: referrers:read.
curl "https://cbcthub.com/api/v1/referrers" \
-H "Authorization: Bearer $CBCTHUB_KEY"
# → { "referrers": [{ "id": "rfr_...", "name": "Dra. Maria Lopez", "email": "...", "specialty": "..." }] }/api/v1/referrersCria um solicitante. Body: { name (obrigatório), email?, phone?, specialty? }.
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"}'/api/v1/referrers/{id}Detalhe de um solicitante. Scope: referrers:read.
/api/v1/referrers/{id}Atualização parcial — apenas os campos enviados são modificados. Scope: referrers:write.
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"}'/api/v1/referrers/{id}Exclui o solicitante. Idempotente: retorna already_deleted=true se não existir. Scope: referrers:write.
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_*").
/api/v1/templatesLista os modelos visíveis (defaults do sistema + os próprios do usuário). Scope: templates:read.
curl "https://cbcthub.com/api/v1/templates" \
-H "Authorization: Bearer $CBCTHUB_KEY"/api/v1/templatesCria 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.
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" }
]
}]
}'/api/v1/templates/{id}Detalhe de um modelo (do sistema ou próprio). Scope: templates:read.
curl "https://cbcthub.com/api/v1/templates/tpl_xyz" \
-H "Authorization: Bearer $CBCTHUB_KEY"/api/v1/templates/{id}Atualiza um modelo próprio. Os defaults do sistema retornam 400. Scope: templates:write.
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"}'/api/v1/templates/{id}Exclui um modelo próprio. Idempotente. Os defaults do sistema retornam 400. Scope: templates:write.
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.
/api/v1/implantsSem 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=.
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.
/api/v1/support/ticketsLista os 50 tickets mais recentes da conta (configurável com ?limit=). Scope: support:read.
curl "https://cbcthub.com/api/v1/support/tickets?limit=20" \
-H "Authorization: Bearer $CBCTHUB_KEY"/api/v1/support/ticketsCria um ticket. Body: { subject, message, category?, exam_id? }. Categorias válidas: general, bug, billing, feature_request, account, viewer.
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"
}'/api/v1/support/tickets/{id}Detalhe do ticket + lista de respostas do admin (em ordem cronológica). Scope: support:read.
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.
/api/v1/activityLog de atividade paginado (descendente). Query: ?limit=50 (1-100), ?before=ISO_DATE (cursor — use next_cursor da resposta), ?action=exam.created (filtro opcional).
curl "https://cbcthub.com/api/v1/activity?limit=20&action=exam.created" \
-H "Authorization: Bearer $CBCTHUB_KEY"/api/v1/notificationsLista 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.
curl "https://cbcthub.com/api/v1/notifications?unread_only=true&limit=30" \
-H "Authorization: Bearer $CBCTHUB_KEY"
# → { "notifications": [...], "unread_count": 4 }/api/v1/notifications/{id}/mark-readMarca uma notificação como lida. Idempotente. Scope: account:write.
curl -X POST "https://cbcthub.com/api/v1/notifications/ntf_xyz/mark-read" \
-H "Authorization: Bearer $CBCTHUB_KEY"/api/v1/notifications/mark-all-readMarca TODAS as não lidas como lidas e retorna marked_count. Scope: account:write.
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
GET /api/v1/exams
/api/v1/examsScope: exams:readTeste agoraLista 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=0Sua 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
/api/v1/examsScope: exams:writeTeste agoraCria 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 →
Request
POST https://cbcthub.com/api/v1/examsSua 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}
/api/v1/exams/{id}Scope: exams:readTeste agoraDetalhes 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}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
/api/v1/webhooksScope: webhooks:writeTeste agoraCria 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 →
Request
POST https://cbcthub.com/api/v1/webhooksSua 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
/api/v1/webhooks/{id}/testScope: webhooks:writeTeste agoraEnvia 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
Request
POST https://cbcthub.com/api/v1/webhooks/{id}/testSua 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.