Pular para conteúdo

Digital Face — Integration Protocol

Documento para o dev do ByClinic Data: 2026-04-16 Autor: Gabriel Mowses / Digital Face


Contexto

A Digital Face está construindo 3 produtos SaaS independentes que se integram opcionalmente:

Produto Função Stack
ChatDigi Atendimento WhatsApp + AI Studio + CRM Node.js + React
Agenda Agendamento online (novo, em construção) FastAPI + Next.js
ByClinic Gestão clínica (prontuário, pacientes, financeiro) FastAPI + Next.js

Cada produto: - Tem auth, billing e banco de dados próprios - Funciona 100% standalone - Integração com os outros é opcional — ativada pelo admin via API key


Como funciona a integração

Fluxo de conexão

1. Admin do ByClinic acessa /settings → aba "Integrações"
2. Clica "Conectar ChatDigi" (ou Agenda)
3. Cola a API key gerada no outro produto
4. Sistema valida a key + descobre features disponíveis
5. A partir daí, UI do ByClinic exibe ações do outro produto
6. Webhooks bidirecionais entregam eventos em tempo real

Arquitetura

ByClinic                          ChatDigi / Agenda
────────                          ─────────────────
                API Key
Settings ─────────────────────► POST /integrations/connect
                                    ↓ valida key
                                    ↓ retorna features[]
              features[]
         ◄─────────────────────

Evento acontece no ByClinic:
patient.created ───────────────► POST /integrations/webhook (ChatDigi)
                                    ↓ processa evento
                                    ↓ cria contato se não existe

Evento acontece no ChatDigi:
              message.received
         ◄─────────────────────  POST /integrations/webhook (ByClinic)
                                    ↓ log na ficha do paciente

O que o ByClinic precisa implementar

1. Gerar API Keys

O ByClinic precisa ter um sistema de API keys para que outros produtos se conectem.

Endpoint:

POST /api/v1/integrations/api-keys
Authorization: Bearer <admin_jwt>

Response:
{
  "api_key": "bc_live_xxxxxxxxxxxxxxxxxxxxxx",
  "created_at": "2026-04-16T12:00:00Z"
}

Requisitos: - Prefixo identificador: bc_live_ (produção) / bc_test_ (sandbox) - Vinculada à clinic (tenant) - Admin pode revogar - Rate limit: 100 req/min por key

2. Validar API Keys de outros produtos

Quando o admin cola uma key do ChatDigi ou Agenda no ByClinic:

POST /api/v1/integrations/connect
Authorization: Bearer <admin_jwt>

Body:
{
  "product": "chatdigi",         // ou "agenda"
  "api_key": "cd_live_xxxxx",   // key gerada no outro produto
  "api_url": "https://api.chatdigi.digitalface.dev.br",
  "webhook_url": "https://api.byclinic.xxx/api/v1/integrations/webhook"
}

O que fazer: 1. Chamar GET {api_url}/integrations/status com a key no header 2. Validar resposta (produto correto, key válida) 3. Salvar integração no banco 4. Registrar webhook_url no produto remoto via POST {api_url}/integrations/webhook/register

3. Endpoint de status (pra outros produtos validarem)

GET /api/v1/integrations/status
Header: X-Integration-Key: bc_live_xxxxx

Response:
{
  "product": "byclinic",
  "version": "1.0.0",
  "clinic_id": 42,
  "clinic_name": "Clínica Exemplo",
  "features": [
    "patient.search",
    "patient.read",
    "record.read",
    "appointment.read",
    "payment.read",
    "message.send"
  ],
  "status": "active"
}

4. Receber webhooks

POST /api/v1/integrations/webhook
Header: X-Integration-Key: bc_live_xxxxx
Header: X-Webhook-Signature: sha256=xxxxxxx

Body:
{
  "id": "evt_xxxxxxxxxxxxx",
  "product": "chatdigi",
  "event_type": "message.received",
  "timestamp": "2026-04-16T12:00:00Z",
  "correlation_id": "corr_xxxxx",
  "data": {
    "contact_phone": "+5582999999999",
    "contact_name": "João Silva",
    "message_body": "Quero remarcar minha consulta",
    "ticket_id": 1234
  }
}

Validação do webhook:

import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), payload, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Eventos que ByClinic vai RECEBER:

Origem Evento Quando Dados
ChatDigi message.received Msg WhatsApp recebida de contato vinculado phone, name, body, ticket_id
ChatDigi message.sent Msg enviada pra contato vinculado phone, body, ticket_id
ChatDigi ticket.created Novo ticket de contato vinculado phone, name, ticket_id, queue
ChatDigi ticket.closed Ticket fechado ticket_id, resolution
ChatDigi contact.created Novo contato criado phone, name, email
Agenda appointment.created Agendamento criado client_phone, service, professional, datetime
Agenda appointment.cancelled Agendamento cancelado appointment_id, reason
Agenda appointment.reminded Lembrete enviado appointment_id, client_phone
Agenda appointment.noshow No-show registrado appointment_id, client_phone

5. Enviar webhooks

Eventos que ByClinic vai ENVIAR:

Evento Quando Dados
patient.created Novo paciente cadastrado phone, name, email, cpf
patient.updated Paciente atualizado patient_id, changed_fields
record.created Novo prontuário patient_id, record_type, summary
payment.received Pagamento recebido patient_id, amount, description
payment.overdue Pagamento em atraso patient_id, amount, due_date

Implementação:

import httpx
import hmac
import hashlib
import json

async def send_webhook(integration, event_type: str, data: dict):
    payload = json.dumps({
        "id": f"evt_{uuid4().hex[:16]}",
        "product": "byclinic",
        "event_type": event_type,
        "timestamp": datetime.utcnow().isoformat() + "Z",
        "data": data
    })

    signature = "sha256=" + hmac.new(
        integration.webhook_secret.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()

    async with httpx.AsyncClient() as client:
        response = await client.post(
            integration.webhook_url,
            content=payload,
            headers={
                "Content-Type": "application/json",
                "X-Integration-Key": integration.api_key,
                "X-Webhook-Signature": signature,
            },
            timeout=10.0,
        )

    # Log delivery
    # Se falhar: retry 3x com backoff (1s, 5s, 25s)

6. Search API (pra outros produtos consultarem)

Endpoints que ByClinic expõe para ChatDigi/Agenda buscarem dados:

# Buscar paciente por telefone
GET /api/v1/integrations/search/patients?phone=+5582999999999
Header: X-Integration-Key: bc_live_xxxxx

Response:
{
  "found": true,
  "patient": {
    "id": 42,
    "name": "João Silva",
    "phone": "+5582999999999",
    "email": "joao@email.com",
    "cpf": "***.***.***-00",  // mascarado
    "birth_date": "1990-05-15",
    "last_appointment": "2026-04-10T14:00:00Z",
    "next_appointment": "2026-04-20T14:00:00Z",
    "balance_due": 150.00,
    "status": "active"
  }
}
# Buscar prontuário resumido
GET /api/v1/integrations/search/records?patient_id=42&limit=5
Header: X-Integration-Key: bc_live_xxxxx

Response:
{
  "records": [
    {
      "id": 100,
      "date": "2026-04-10",
      "type": "consultation",
      "professional": "Dra. Maria",
      "summary": "Retorno - paciente estável",
      "url": "https://byclinic.xxx/patients/42/records/100"  // link direto
    }
  ]
}
# Buscar agendamentos do paciente
GET /api/v1/integrations/search/appointments?patient_id=42&status=scheduled
Header: X-Integration-Key: bc_live_xxxxx

Response:
{
  "appointments": [
    {
      "id": 200,
      "datetime": "2026-04-20T14:00:00Z",
      "service": "Consulta retorno",
      "professional": "Dra. Maria",
      "status": "confirmed",
      "url": "https://byclinic.xxx/agenda/200"
    }
  ]
}

7. Action API (pra outros produtos executarem ações)

# ChatDigi pede pra ByClinic registrar interação no prontuário
POST /api/v1/integrations/action/log-interaction
Header: X-Integration-Key: bc_live_xxxxx

Body:
{
  "patient_phone": "+5582999999999",
  "interaction_type": "whatsapp_message",
  "summary": "Paciente confirmou consulta dia 20/04",
  "source": "chatdigi",
  "source_id": "ticket_1234"
}

Modelo de dados sugerido

# models/integration.py

class Integration(Base):
    __tablename__ = "integrations"

    id: int                          # PK
    clinic_id: int                   # FK → Clinic (tenant)
    product: str                     # "chatdigi" | "agenda"
    api_key_local: str               # Key que ByClinic gerou pro outro produto usar
    api_key_remote: str              # Key do outro produto que ByClinic usa
    api_url: str                     # URL base do outro produto
    webhook_url: str                 # URL onde ByClinic recebe webhooks
    webhook_secret: str              # HMAC secret
    features: list[str]              # Features descobertas do outro produto
    status: str                      # "active" | "inactive" | "error"
    last_health_check: datetime      # Último status check
    created_at: datetime
    updated_at: datetime


class IntegrationWebhookLog(Base):
    __tablename__ = "integration_webhook_logs"

    id: int
    integration_id: int              # FK → Integration
    direction: str                   # "inbound" | "outbound"
    event_type: str
    payload: dict                    # JSON
    status_code: int                 # HTTP response code
    response_body: str
    delivered: bool
    retries: int
    created_at: datetime

Regras de segurança

  1. API keys nunca no frontend — só backend-to-backend
  2. HMAC em todo webhook — rejeitar se assinatura inválida
  3. Rate limit — 100 req/min por integration
  4. Dados mascarados — CPF, dados médicos sensíveis nunca expostos em full
  5. Audit log — toda chamada de integração logada
  6. LGPD — se paciente pede exclusão no ByClinic, webhook patient.deleted pro ChatDigi/Agenda apagar dados correlatos
  7. Timeout — 10s pra chamadas, não bloquear fluxo principal se outro produto offline

Checklist de implementação pro dev ByClinic

  • Model Integration + migration
  • Model IntegrationWebhookLog + migration
  • API key generation (bc_live_xxx)
  • POST /integrations/connect (validar key remota)
  • GET /integrations/status (expor features)
  • POST /integrations/webhook (receber + validar HMAC)
  • Webhook sender (enviar eventos + retry 3x)
  • GET /integrations/search/patients?phone=X
  • GET /integrations/search/records?patient_id=X
  • GET /integrations/search/appointments?patient_id=X
  • POST /integrations/action/log-interaction
  • UI: /settings → aba Integrações (colar key, testar, ver status)
  • UI: painel no paciente → conversas ChatDigi + agendamentos Agenda
  • Rate limiting middleware
  • Webhook signature validation
  • Audit log de chamadas

Estimativa: ~3-4 sessões de dev.


Contato

Dúvidas técnicas: Gabriel Mowses — gabrielmowses@gmail.com