# newwhats.clube67.com — Contrato de integração Motor ↔ Satélite > O **motor** (newwhats) expõe a plataforma WhatsApp + Secretária IA; cada > **satélite** (ex.: mercado.clube67.com / "Alemão Conveniências", plugin > `newwhats` v2.1.0) consome o motor e fornece dados do seu negócio. > Fonte da verdade do contrato (auditado em 28/jun/2026). ## ⚠️ Regra de registro bidirecional - **Cada plugin satélite é ÚNICO do projeto onde está instalado** — o `newwhats` do `mercado.clube67.com` pode divergir do de outro projeto. Não copiar cego. - **Toda mudança no plugin** que toque o contrato deve ser registrada **no motor** e nesta doc; **toda mudança no motor** que afete o contrato deve ser refletida no doc do plugin (`INTEGRACAO-MOTOR.md`, dentro de cada plugin). - O plugin é um **braço inteligente do motor**: consome, alimenta e configura — não duplica lógica do motor. ## Satélites conhecidos - **mercado.clube67.com** ("Alemão Conveniências") — plugin CommonJS no PluginManager. Domínio: clubes/planos/sorteio/vagas/promoções. - **scoreodonto.com** (28/jun/2026) — clonado e **adaptado ao odonto**. Módulo **ESM** em `backend/newwhats/` (sem PluginManager; `registerNewwhats(app, pool)` no `server.js`), config por ENV. `/nw/*` e `sync-knowledge` usam clínica/especialidades/dentistas/procedimentos/planos (multi-tenant por `clinica_id`). Removidos os recursos só-mercado e o `media-transcribe`. Em branch `feat/newwhats-satelite` (sem deploy); falta parear com o motor (apiKey + agente) e preencher as ENV. Ver `backend/newwhats/INTEGRACAO-MOTOR.md`. ## Docs relacionadas - [tarefas.md](tarefas.md) — checklist mestre de pendências. - [wasabi-midias.md](wasabi-midias.md) — storage, index e delete em lote. - [ativacao-whatsapp.md](ativacao-whatsapp.md) — trajeto inteligente de ativação. - `INTEGRACAO-MOTOR.md` — dentro de cada plugin satélite (lado do satélite). ## Config do satélite (plugin_configs, manifest `newwhats`) `newwhats_url` (URL do motor) · `integration_key` (x-nw-key, rotas `/nw/*`) · `api_token` (Bearer, envio de mensagens) · `webhook_secret` (HMAC do webhook). ## Contrato A — Satélite → Motor (ext-api `/api/ext/v1/*`) | Satélite chama | Motor (ext-api) | Status | |---|---|---| | `inbox`, `inbox/:chatId/messages`, `inbox/:chatId/send` | idem | ✅ | | `media/:messageId` | `media/:messageId` | ✅ | | `stream` (WS) | `stream` | ✅ | | `secretaria/ask` | `secretaria/ask` (routes.ts) | ✅ | | `secretaria/numbers` | **alias adicionado** → `sec_numbers` | ✅ (corrigido) | | `secretaria/*` interno (`sync-knowledge`) | `/api/secretaria/*` (plugin) | ✅ | > Demais dados da Secretária no ext-api ficam sob `/sec/*` (`sec/agent`, > `sec/nodes`, `sec/slots`, `sec/conversations`, `sec/keys`, `sec/handoff`). ## Contrato B — Motor → Satélite | Mecanismo | Satélite | Auth | |---|---|---| | Webhook `POST /api/webhook/newwhats` (`message.new`, `session.status`) | `webhook-receiver.js` | HMAC `webhook_secret` | | Secretária consulta `/nw/*` (`/cliente`, `/clube`, `/parceiros`, `/promocoes`, `/sorteio`, `/vagas`, `/ping`) | `routes.js` | `integration_key` (timingSafeEqual) | ## O que o satélite já faz (e poderia migrar ao motor) - `media-transcribe.js`: transcrição de áudio + descrição de imagem via Gemini (cache Redis, fallback Whisper). **Hoje só no satélite** → candidato a ir ao motor. - `sync-knowledge.js`: monta o nó de conhecimento com dados reais e envia ao motor. - `smart-router.js` (roteamento sem LLM), `personas.js`, `follow-up-detector.js`, `context-builder.js` (contexto local do negócio). ## Estado da sincronização (faseado) 1. ✅ **Contrato documentado** (este arquivo). 2. ✅ **Compatibilidade de API**: alias `GET /secretaria/numbers` no ext-api do motor (retrocompatível) — fecha o gap do `webhook-receiver`. (commit motor) 3. ✅ **Config/conexão** (auditado 28/jun/2026, satélite `mercado`@VPS3 ↔ motor dev `newwhats_dev`). Resultado: - **Satélite → Motor (ext-api/proxy/WS)** ✅ — `proxy.js` envia `x-nw-key` = `integration_key` do satélite; o ext-api valida contra a tabela `apiKey`. A chave do satélite (`nw_t…_001`, len 34) **é igual** à `apiKey` ativa do motor. **Teste vivo:** `GET /api/ext/v1/sessions` com a chave → **200**; sem chave / chave inválida → **401** (correto). - **Webhook Motor → Satélite (HMAC)** ✅ — `ext_webhooks` do motor: url `http://127.0.0.1:4001/api/webhook/newwhats`, eventos `[message.new, session.status]`, ativo, `secret` (len 64) **igual** ao `webhook_secret` do satélite. Assinatura `x-nw-signature: sha256=HMAC` (`webhook-dispatcher.ts`). - **Topologia co-locada** (`127.0.0.1`): satélite espera motor em `:8008`; motor espera satélite em `:4001`. Para teste vivo ponta-a-ponta o **satélite precisa rodar co-locado com o motor dev** (hoje não está rodando na VPS4). - ⚠️ **`/nw/*` (Motor → Satélite, Secretária)**: o satélite valida o `x-nw-key` entrante contra `plugin_configs.integration_key` (`nw_t…_001`); o `PluginPair` do motor usa outra chave (`nwk_…1039`, `lastSeenAt=null`). Se esse sentido for usado, **reconciliar a chave** (não afeta a Fase 4, que é Satélite → Motor). - ⚠️ `api_token` não existe em `plugin_configs` do satélite — não é necessário: o ext-api autentica por `x-nw-key` (= `integration_key`), não por Bearer separado. 4. ✅ **Conhecimento**: `sync-knowledge` rodado end-to-end (28/jun/2026). Driver executou o `buildKnowledgeText` real do satélite (DB `mercado`@VPS3: 2 clubes, 4 planos, 6 promoções → 1895 chars) e publicou no motor dev via `/api/secretaria` (nginx-dev :8022 → backend, rotas internas sem auth). Nó `knowledge` **atualizado**. **RAG indexou**: `sec_knowledge_chunks` = 4 chunks do nó, todos com embedding Gemini (768d). ✅ pipeline ok. - ⚠️ A **geração final** do LLM (`gemini-2.0-flash:generateContent`) retorna **429 quota** (free tier) — billing da chave Gemini, não defeito do pipeline. - Corrigido de quebra: `/secretaria/ask` filtrava `prisma.chat` por `remoteJid` (inexistente) → 500; agora usa `jid`. 5. **Mover recursos para o motor** (genéricos a todos os satélites): - ✅ **Transcrição** (áudio→texto, imagem→descrição) já no motor via Gemini (`messages.transcription`). O `media-transcribe.js` do satélite vira redundante. - ⏳ memória (a secretária já tem memória por contato no motor; falta o satélite deixar de duplicar). Satélite passa a só enviar contexto. ## Inconsistência anotada A transcrição no satélite usa `process.env.GEMINI_API_KEY`; o RAG/memória do motor usa `cfg.gemini_key` (config do plugin). Unificar a fonte da chave ao migrar.