K
Kodama Vault
knowledge hub
Vault
HomeBoardMap of ContentChatConversasAuditoria
Agentes
AgentsIssuesTerminalPreviews
Sistema
MCPSetup MCPSettings
Brain
Global agent instructions
Análise custos migração — evitar senha no payloadLevantamento fluxo registro + duplicados StripeRelatório segurança + pentes finos (Cláudio)Revisão security concerns e race conditionsMagic link / esqueceu senha via SupabaseCorrigir erros pós-upgrade TypeScriptTestar PRs do agente Vault para mergeAnálise de 3 issues para iniciarErro no terminal do VSCodePR #173 — aguardando aprovação do LeoTestar fluxo ponta a ponta — criação de clients no StripePR #172 — testar e subir correção de funções deprecatedPitch de vendas SaaS — agendar call de conversãoOrganizar issues e bugs rápidos para a semanaMerge PR cadastro-novo — funcionalidades e correçõesCorrigir bugs PR #173 e #172 — image domainsPR mesosóico — página de acesso mobile + segurança OTPRefatoração de códigos — PR #202Ajustes em PRs abertos de ontemEstudo de jornada de compra e técnicas de fechamentoDefinir preço e entregável do produtoProspecção de reuniões para esta semanaAgente anti AI slop — centralização de conhecimento ConnfitPR #179 — resolver conflitos e erros de teste CLIAlinhamento de preços e usos da ConffitFix adicional para PR #183 — perfil do usuárioCorrigir estilização da Connfit para identidade visualSubir modificações no copy da ConnfitCriação de 4 campanhas no Meta AdsRevisão de PRs do GilinesExploração do Roblox EditorRelatório João — devolutiva TikTok ShopReunião presencial Zassi Uniformes — diagnóstico automaçõesCriar repositório de diagnósticos e relatórios de entrevistasDiagnóstico da ZassiGeração de relatórios para reuniões de fechamentoProposta Zassi — apresentação amanhãProspecção — Clínica Odontológica Dr. But
VPS Hermes — acesso e estrutura
Always Commit Push DeployHermes Voice GeminiHermes VPSKodama Prospects TrackerMEMORYObsidian VaultRoblox Mining Sim
OpenSpec -- Spec-Driven Development no VaultPlano de Teste — OpenSpec Vault Persistence
CaumzitoNyxzZanini
vek1 — arquiteturavek1 — autenticaçãovek1 — contextovek1 — regras de copy e marketingvek1 — modelo de dadosvek1 — decisões técnicasvek1 — domínio e modelo de negóciovek1 — featuresvek1 — gaps e riscosvek1 — gotchasvek1 — integrações externasvek1 — pricing design (Stripe sub + topup)vek1 — atividade recentevek1 — roteiro de vendas (SDR → fechamento)vek1 — estado e maturidadevek1 — Migração Evolution API → WhatsApp Cloud API (Meta oficial)
Claude Code — Setup MCP VaultClaude Desktop — Setup MCP Vault (remote)VS Code + Copilot — Setup MCP Vault
Skill — Carousel Designer (Paper Style)
Standup 2026-05-14Standup 2026-05-15Standup 2026-05-16Standup 2026-05-17Standup 2026-05-18Standup 2026-05-19Standup 2026-05-20Standup 2026-05-21Standup 2026-05-22Standup 2026-05-25Standup 2026-05-26Standup 2026-05-27Standup 2026-05-28Standup 2026-05-29Standup 2026-06-01Standup 2026-06-02Standup 2026-06-03Standup 2026-06-05Standup 2026-06-11Standup 2026-06-15Standup 2026-06-16Standup 2026-06-17Standups
MOCWelcome
v0.3
K
Kodama Vault
brain / projects / vek1

vek1 — Migração Evolution API → WhatsApp Cloud API (Meta oficial)

Migração Evolution → WhatsApp Cloud API (Meta oficial)

Spec de migração do canal WhatsApp do vek1 de Evolution API (Baileys, não-oficial) para a WhatsApp Cloud API da Meta (oficial).
Estado atual da integração: vek1/integrations linha "Evolution API".

TL;DR — direção tomada (2026-05-27)

  • Arquitetura multi-tenant desde dia 1: cada agent vek1 conecta um número de lojista, não um número da Kodama. Embedded Signup obrigatório.
  • Destino: Solution Partner (vek1 toma payment ownership das WABAs dos lojistas → cobra conversation cost no plano com margem).
  • Gate: Tech Provider — Meta exige operar como Tech Provider antes de aprovar Solution Partner. Cronograma realista: lança em Tech Provider em ~1 mês, aplica Solution Partner em paralelo, aprovação em meses.
  • Trilha dupla na Fase 0: Trilha A (técnica/Meta) + Trilha B (prep Solution Partner: financeiro/legal/business).
  • Código é o mesmo nos 2 modelos: muda só wa_payment_ownership flag por agent + chamada API take_payment_ownership quando aprovado.

1. Motivação

  • Evolution API é Baileys-based (engenharia reversa do WhatsApp Web) → risco constante de ban do número, bloqueio de novos features, dependência de um container self-hosted no VPS Hermes (evolution.kodama.solutions).
  • Cloud API da Meta é o canal oficial e suportado, com SLA, escala automática, e features nativas (templates, interactive messages, flows, click-to-chat ads).
  • Pré-requisito pra crescer fora de tier pequeno: lojistas que escalam não toleram número banido.
  • Trade-off: custo per-conversation (não mais "grátis"), janela 24h, templates aprovados pra mensagens proativas.

2. Estado atual (a substituir)

Arquivos envolvidos hoje (referência rápida):

Camada Arquivo
Client HTTP src/lib/evolution-api.ts
Instance management (criar/QR/delete) src/lib/evolution-instance.ts
Webhook receiver src/app/api/webhooks/evolution/route.ts
Message handler (lead/order/chat orchestration) src/lib/whatsapp-handler.ts
Provisioning route (gera QR pro agent) src/app/api/agents/[id]/instance/route.ts
UI conexão src/components/agents/agent-settings-client.tsx, src/components/agents/whatsapp-tester.tsx
Schema (agents table) src/lib/db/schema.ts linhas 109-116 (evolution_instance_id, whatsapp_enabled, whatsapp_phone_number)
Outbound notifications src/lib/order-notifications.ts (notificações de pedido — provavelmente fora da janela 24h)
Proof attachment (PIX) src/lib/order-proofs.ts (download base64 via Evolution getBase64FromMediaMessage)

Container Evolution: evolution.kodama.solutions no VPS Hermes (v2.3.x).


3. Modelo: Solution Partner (destino) via Tech Provider (gate)

Multi-tenant desde dia 1. Cada agent vek1 conecta um número do lojista, não da Kodama.
Solution Partner é destino estratégico, mas Meta exige operar como Tech Provider primeiro.

3.1 — Os 3 níveis Meta (2026)

Nível Como entra Quem paga Meta Aprovação
Tech Provider Self-service, app review Lojista direto (cartão dele na WABA dele) 5-14 dias (app review)
Solution Partner Aplicação formal Meta vek1 (payment ownership das WABAs dos lojistas) Semanas a meses, Meta pode rejeitar
BSP legado Descontinuado — Não aceita novos

3.2 — Por que Solution Partner é o destino

  • vek1 cobra plano único do lojista (software + cota de conversations + overage com margem)
  • Lojista vê 1 fatura só (Kodama) — não 2 (Kodama + Meta direto)
  • vek1 capta margem em conversations (revenue share natural do modelo SaaS)
  • Acesso a features Solution Partner-only (BSP Hub, programmatic onboarding APIs, melhor suporte Meta)
  • Branding e onboarding mais limpos (lojista não precisa criar conta Meta business completa)

3.3 — Por que Tech Provider é o gate

  • Meta não aprova Solution Partner sem app já funcionando + tração demonstrável
  • Tech Provider é self-service e sai em dias; Solution Partner application leva meses
  • Mesma arquitetura técnica nos 2: embedded signup, schema, webhook. Solution Partner adiciona só take_payment_ownership na hora de conectar lojista
  • Migrar Tech Provider → Solution Partner é incremental, não rip-and-replace

3.4 — Trilha A: Pré-requisitos Meta técnicos (Tech Provider)

Começar imediatamente.

  1. Meta Business Manager — criar a conta business da Kodama
  2. Business Verification (KYC) Kodama — CNPJ, comprovante endereço, doc de domínio. Pode ser rejeitado, prepara pra reenviar. Aprovação obrigatória pra Solution Partner depois
  3. App no Meta for Developers (único pro vek1 todo)
    • Tipo: Business, vinculado ao Business Kodama
    • Produto WhatsApp adicionado
    • Anotar: app_id, app_secret
  4. System User Kodama com role Admin + assets (app + WABA Kodama opcional)
    • Permanent Access Token salvo seguro — usado pra operações app-level (subscribe webhooks, refresh tokens, app config)
  5. Embedded Signup Configuration no app
    • Settings → WhatsApp → Embedded Signup → cria config
    • Anotar config_id — usado no FB.login do frontend
  6. App Review submetido com permissões:
    • whatsapp_business_management
    • whatsapp_business_messaging
    • business_management
    • Requer: screencast do fluxo, política de privacidade publicada, termos de uso publicados, descrição clara de cada permissão
  7. Verify token — string arbitrária (openssl rand -hex 32), salva no env como WA_VERIFY_TOKEN. Configurada no webhook Meta + no env vek1
  8. WABA Kodama (opcional, só pra testes) — número de teste interno antes de ter lojista real

IMPORTANTE: WABAs/Phone Numbers/Tokens dos lojistas não são criados em Fase 0 — são criados em runtime via embedded signup quando o lojista conecta o agent.

3.5 — Trilha B: Prep Solution Partner (paralelo à Trilha A)

Não bloqueia lançamento técnico. Coleta material em paralelo pra aplicar quando Trilha A estiver no ar.

B.1 — Financeiro

  • Cartão corporativo CNPJ Kodama com limite alto (R$10-50k inicial). Meta vai cobrar conversations de todos os lojistas em vek1 após payment ownership
  • Conta bancária PJ ativa, extrato 3 meses
  • DRE/balanço últimos 12m (se houver — Meta às vezes pede)
  • Linha de crédito Meta — Meta concede limite após aprovação. Antes disso, cartão é o método

B.2 — Legal

  • Termos de uso publicados em vek1.com/terms
  • Política de privacidade em vek1.com/privacy
  • Acordo de processamento de dados (LGPD/GDPR) — modelo Meta
  • Acceptable Use Policy (AUP) pros lojistas — anti-spam, anti-marketing abusivo, conformidade WhatsApp Commerce Policy
  • Compliance program interno documentado: como vek1 fiscaliza lojistas, processo de suspensão, reporting Meta

B.3 — Negócio

  • Business plan / pitch deck: mercado, projeção 12-24m de lojistas e volume de conversations
  • Customer commitment letters: 3-10 lojistas (atuais ou pipeline) em papel timbrado dizendo que querem contratar vek1 como Solution Partner se aprovado
  • Casos de uso: prints/vídeos do produto, fluxos típicos, métricas (tempo de resposta, taxa de fechamento, etc.)
  • Capacidade técnica: diagrama de arquitetura (reusa vek1/architecture), equipe, SLA interno, plano de suporte

B.4 — Aplicação formal

  • Portal: https://business.facebook.com/business/help/solution-partner
  • Submete B.1, B.2, B.3
  • Meta entrevista (call em inglês com solutions engineer)
  • Decisão: semanas a meses

3.6 — Risco operacional Solution Partner

Estes são os trade-offs que payment ownership traz — internalizar antes de aplicar:

  • Inadimplência do lojista vira problema da vek1. Lojista usa 10k conversations, não paga plano vek1; Meta cobra vek1 do mesmo jeito. Precisa controle de crédito interno: monitor de uso, suspensão automática em atraso, cap de conversations no plano
  • Compliance violation do lojista pode banir WABA inteira. Se um lojista manda spam pesado, Meta pode penalizar todos os lojistas no app vek1. Precisa auto-suspend agent quando Meta sinalizar violação (webhook account_alerts)
  • Volume mínimo no Solution Partner Agreement pode existir. Se vek1 não atingir, multa ou downgrade
  • Responsabilidade legal por dados dos lojistas sobe — vek1 vira processor formal de dados Meta

4. Mudanças de código

4.1 Schema (src/lib/db/schema.ts)

Acrescentar (sem remover os antigos durante transição):

// agents table
waProvider: text('wa_provider').default('evolution').notNull(),         // 'evolution' | 'meta'
waPhoneNumberId: text('wa_phone_number_id'),                             // Meta phone_number_id (do lojista)
waWabaId: text('wa_waba_id'),                                            // Meta WABA id (do lojista)
waAccessToken: text('wa_access_token'),                                  // token do lojista — CRIPTOGRAFADO
waTokenRefreshedAt: timestamp('wa_token_refreshed_at'),                  // tokens long-lived precisam refresh ocasional
waPaymentOwnership: text('wa_payment_ownership').default('customer').notNull(), // 'customer' | 'vek1'
waBusinessVerificationStatus: text('wa_business_verification_status'),   // status KYC do lojista pra mensagens out-of-window
waConnectedAt: timestamp('wa_connected_at'),

Nova tabela wa_templates (templates aprovados Meta, por agent):

{
  id, agentId (fk), wabaId, name, language, category,
  status, // 'PENDING' | 'APPROVED' | 'REJECTED' | 'PAUSED'
  componentsSchema (jsonb), // validar params no envio
  createdAt, lastStatusUpdateAt
}

Nova tabela wa_message_statuses (delivery/read/failed tracking):

{
  id, messageId (fk → messages_history), waMessageId, // wamid.XXX
  status, // 'sent' | 'delivered' | 'read' | 'failed'
  errorCode, errorTitle, errorDetails (jsonb),
  recipientId, timestamp
}

Manter evolution_instance_id, whatsapp_phone_number, whatsapp_enabled durante a migração. Remover só depois que todos os agents migrarem.

Lembrete schema-migrator: db:push --force dropa indexes hnsw — re-aplicar init/01-init.sql do vek1-api depois.

4.1.1 Payment Ownership flip

Quando Solution Partner aprovado e cada lojista aceita migrar:

// pseudo
async function takePaymentOwnership(agentId) {
  const agent = await getAgent(agentId);
  const res = await fetch(
    `https://graph.facebook.com/v21.0/${agent.waWabaId}/take_payment_ownership`,
    { method: 'POST', headers: { Authorization: `Bearer ${SYSTEM_USER_TOKEN}` } }
  );
  // ... handle response
  await updateAgent(agentId, { waPaymentOwnership: 'vek1' });
}

Pricing implication: quando waPaymentOwnership='vek1', vek1 captura cost no token_usage (extender pra conversation_usage) e cobra no plano. Detalhar em vek1/pricing-design.

Lembrete schema-migrator: db:push --force dropa indexes hnsw — re-aplicar init/01-init.sql do vek1-api depois (vide vek1-api/gotchas).

4.2 Novo client (src/lib/whatsapp-cloud.ts)

Substitui evolution-api.ts + evolution-instance.ts. Endpoints base:

Operação HTTP
Send text POST /v21.0/{phone_number_id}/messages body { messaging_product:"whatsapp", to, type:"text", text:{body} }
Send image (URL) POST /v21.0/{phone_number_id}/messages body { ..., type:"image", image:{link, caption} }
Send image (media id) image:{id, caption}
Send template type:"template", template:{name, language:{code}, components:[...]}
Download media GET /v21.0/{media_id} → resposta tem URL temp (5min); GET na URL com Authorization: Bearer {token}
Get media metadata GET /v21.0/{media_id}
Mark as read POST /v21.0/{phone_number_id}/messages body { status:"read", message_id }

Auth header: Authorization: Bearer {access_token}. Sem apikey: como Evolution.

Base URL: https://graph.facebook.com/v21.0 (versão fixar em env, atualizar trimestralmente).

4.3 Webhook receiver (src/app/api/webhooks/whatsapp/route.ts)

Novo endpoint paralelo (sem matar /api/webhooks/evolution).

GET (verification handshake)

const mode = searchParams.get('hub.mode');
const token = searchParams.get('hub.verify_token');
const challenge = searchParams.get('hub.challenge');
if (mode === 'subscribe' && token === process.env.WA_VERIFY_TOKEN) {
  return new Response(challenge, { status: 200 });
}
return new Response('forbidden', { status: 403 });

POST

  • Validar X-Hub-Signature-256: HMAC-SHA256 do raw body com app_secret. Sem isso qualquer um manda payload e dispara mensagens.
  • Payload shape:
    {
      "object": "whatsapp_business_account",
      "entry": [{
        "id": "<waba_id>",
        "changes": [{
          "field": "messages",
          "value": {
            "messaging_product": "whatsapp",
            "metadata": { "phone_number_id": "...", "display_phone_number": "..." },
            "contacts": [{ "profile": { "name": "..." }, "wa_id": "5511999..." }],
            "messages": [{
              "from": "5511999...",
              "id": "wamid....",
              "timestamp": "1716808800",
              "type": "text",
              "text": { "body": "oi" }
              // ou type:"image", image:{id, mime_type, sha256, caption?}
              // ou type:"document", document:{id, mime_type, filename, caption?}
              // ou type:"audio", "video", "sticker", "location", "contacts", "interactive"
            }],
            "statuses": [{ "id":"wamid...", "status":"sent|delivered|read|failed", "timestamp":"...", "recipient_id":"...", "errors":[...] }]
          }
        }]
      }]
    }
    
  • Lookup do agent: por wa_phone_number_id = value.metadata.phone_number_id (substitui findByEvolutionInstance)
  • from é phone direto E.164 sem + — joga fora toda lógica de JID/LID (whatsapp-handler.ts linhas 243-258)
  • Statuses (delivered/read/failed) — armazenar em messages.metadata ou nova tabela wa_message_statuses. Failed tem errors[] com code e title.
  • Retornar 200 sempre (mesma regra do Evolution: Meta retenta com backoff agressivo)

4.4 Handler (src/lib/whatsapp-handler.ts)

Adapta EvolutionWebhookMessage para shape novo (manter interface, normalizar no webhook):

  • Remove senderPn, isLid — Cloud API não tem
  • instanceId → phoneNumberId (renomear o conceito; mantém shape pra reaproveitar o handler durante transição)
  • Media: media.rawMessage deixa de ser envelope Baileys, vira { media_id }. Download via Cloud API antes de chamar attachWhatsAppProofToOrder:
    const meta = await getMediaMetadata(media_id);
    const buf = await downloadMedia(meta.url);
    await attachWhatsAppProofToOrder(orderId, { buffer: buf, mimeType: meta.mime_type, ... });
    
  • sendWhatsappText / sendWhatsappImage: dispatch por agent.wa_provider:
    if (agent.waProvider === 'meta') return whatsappCloud.sendText(...);
    return evolutionSendText(...);
    

4.5 Provisioning route (/api/agents/[id]/wa-connect)

QR code não existe na Cloud API. Embedded Signup obrigatório (sem fallback de "form admin" — modelo é multi-tenant).

Fluxo end-to-end (lojista clica "Conectar WhatsApp" em /agents/[id]/settings):

  1. Frontend dispara FB.login com { config_id: <EMBEDDED_SIGNUP_CONFIG_ID>, response_type: 'code', override_default_response_type: true, extras: { setup: { ... } } }
  2. Popup Meta abre. Lojista logga FB pessoal, cria Business + WABA + adiciona número, confirma SMS — tudo dentro do popup
  3. Popup fecha. Callback recebe code + (via message channel) phone_number_id + waba_id
  4. Frontend POST /api/agents/[id]/wa-connect com payload
  5. Backend:
    • Troca code por access token long-lived do lojista: GET /v21.0/oauth/access_token?client_id={app_id}&client_secret={app_secret}&code={code}
    • Subscribe webhook na WABA do lojista: POST /v21.0/{waba_id}/subscribed_apps (auth: token do lojista)
    • Registra número (necessário 1x): POST /v21.0/{phone_number_id}/register body { messaging_product:'whatsapp', pin:'<PIN>' } (PIN vem do lojista no signup)
    • Solution Partner only (quando aprovado): POST /{waba_id}/take_payment_ownership (auth: System User token vek1)
    • Cria templates iniciais na WABA do lojista (vide 4.7)
    • Grava no agent: waProvider='meta', waPhoneNumberId, waWabaId, waAccessToken (criptografado), waPaymentOwnership ('customer' ou 'vek1'), waConnectedAt

Token refresh:

  • Token de embedded signup é long-lived (60 dias). Refresh com GET /v21.0/oauth/access_token?grant_type=fb_exchange_token&fb_exchange_token={current} antes de expirar
  • Cron diário ou on-demand quando call falha com 401: refresh + update waTokenRefreshedAt

4.6 UI (agent-settings-client.tsx + whatsapp-tester.tsx)

  • Remove tela de QR
  • Substitui por botão "Conectar WhatsApp" que dispara FB.login (embedded signup)
  • Mostra status connected | disconnected | pending_verification | suspended
  • Mostra número conectado + perfil + status de templates pendentes/aprovados
  • Botão "Desconectar" → DELETE /v21.0/{waba_id}/subscribed_apps
  • Quando Solution Partner ativo: badge mostrando billing (Você paga via plano vek1 vs Cobrado direto pela Meta)

4.7 Templates (por WABA do lojista)

Janela de 24h: free-form messages só dentro de 24h da última mensagem do user. Fora disso → precisa template aprovado pela Meta.

Templates são por WABA — vek1 precisa criar os templates em cada WABA de lojista quando ele conecta. Não tem "template global vek1".

Identificar fluxos que mandam mensagem fora da janela e converter pra template:

Fluxo Arquivo Dentro/Fora janela Ação
Resposta do chat IA whatsapp-handler.ts linha 366 Dentro (sempre é resposta a msg do user) OK, free-form
Ack comprovante PIX whatsapp-handler.ts linhas 305-307 Dentro OK, free-form
Notificação status pedido order-notifications.ts Fora (lojista marca shipped/delivered horas depois) Template order_status_update (UTILITY)
Lembrete pagamento order-notifications.ts Fora Template payment_reminder (UTILITY)
Reengajamento lead frio TBD Fora Template lead_reengagement (MARKETING)

Auto-criação no /api/agents/[id]/wa-connect:

const STANDARD_TEMPLATES = [
  { name: 'order_status_update', category: 'UTILITY', ... },
  { name: 'payment_reminder', category: 'UTILITY', ... },
  { name: 'lead_reengagement', category: 'MARKETING', ... },
];
for (const tpl of STANDARD_TEMPLATES) {
  await createTemplate(wabaId, lojistaToken, tpl);
}
// Aprovação Meta: 1-48h. Webhook 'message_template_status_update' notifica.
// Notificar lojista por email quando todos aprovarem.

Categorias: MARKETING (mais caro), UTILITY (atualização de transação, mais barato), AUTHENTICATION (OTP, não usamos), SERVICE (free dentro de janela aberta).

Webhook message_template_status_update atualiza wa_templates.status por agent.


5. Plano de migração (2 trilhas em paralelo)

Trilha A — Técnica (Tech Provider → Solution Partner code-ready)

Fase A0 — Setup Meta (semana 1-2)

  • Business Manager Kodama criado
  • Business Verification (KYC) submetida — começa imediatamente (1-3 semanas)
  • App "vek1 WhatsApp" criado no Meta for Developers
  • System User + Permanent Access Token salvo seguro (1Password/Bitwarden)
  • Embedded Signup Configuration criada no app → anotar config_id
  • Verify token gerado (openssl rand -hex 32) + env WA_VERIFY_TOKEN
  • Número de teste interno (chip pré-pago ou VoIP) registrado em WABA Kodama pra smoke tests

Fase A1 — Schema + dual provider (semana 2)

  • Schema migration: wa_provider, wa_phone_number_id, wa_waba_id, wa_access_token, wa_token_refreshed_at, wa_payment_ownership, wa_business_verification_status, wa_connected_at
  • Tabelas novas: wa_templates, wa_message_statuses
  • Default wa_provider = 'evolution' em agents existentes
  • Smoke test: Evolution continua funcionando 100%

Fase A2 — Novo client + webhook (semanas 2-3)

  • lib/whatsapp-cloud.ts — send text/image/template + download media + template CRUD
  • lib/wa-token-encryption.ts — encrypt/decrypt tokens (mesmo pattern AbacatePay)
  • /api/webhooks/whatsapp/route.ts com signature verification (X-Hub-Signature-256)
  • Adapter no whatsapp-handler.ts (dispatch por agent.waProvider)
  • Handler de message_template_status_update → atualiza wa_templates
  • Handler de account_alerts → suspende agent automaticamente
  • Tests unitários: dispatch, signature verification, encryption

Fase A3 — App Review submission (semana 3)

  • Política de privacidade publicada em vek1.com/privacy
  • Termos de uso publicados em vek1.com/terms
  • Screencast embedded signup + envio de mensagem (5min)
  • Descrições de uso de cada permissão Meta
  • Submeter App Review → aguardar 5-14 dias

Fase A4 — Embedded Signup + onboarding UI (semanas 3-4, paralelo ao app review)

  • Facebook JS SDK integrado em agent-settings-client.tsx
  • Botão "Conectar WhatsApp" dispara FB.login com config_id
  • /api/agents/[id]/wa-connect — code→token exchange, subscribe webhook, register number, criar templates iniciais
  • UI mostra status + perfil + templates pendentes
  • Endpoint /api/agents/[id]/wa-disconnect

Fase A5 — Templates aprovados (paralelo desde A2)

  • Catálogo standard de templates definido (order_status_update, payment_reminder, lead_reengagement)
  • Templates criados via API na WABA Kodama de teste → aprovados → validados
  • order-notifications.ts adaptado pra usar template quando provider=meta
  • Cron de notificação por email pro lojista quando todos templates aprovam

Fase A6 — Piloto interno (semana 5, depois App Review aprovado)

  • Conectar 1 agent interno via embedded signup (número de teste Kodama)
  • Validar end-to-end: receive → chat backend → reply → templates → statuses
  • Monitorar 1 semana

Fase A7 — Rollout lojistas Tech Provider (semanas 6-8)

  • Comunicar lojistas existentes sobre migração (e-mail + in-app banner)
  • Lojista executa: deslogar Evolution → deletar conta WhatsApp celular → aguardar 24h → conectar via embedded signup
  • Migrar 1 lojista por dia, monitorar
  • Quando todos migrarem: derruba container Evolution, deleta evolution_instance_id, remove lib/evolution-*.ts e /api/webhooks/evolution

Fase A8 — Solution Partner activation (quando Trilha B aprovar)

  • Para cada agent ativo: chamar POST /{waba_id}/take_payment_ownership
  • Atualizar wa_payment_ownership = 'vek1'
  • Estender token_usage → conversation_usage capturando custo por conversation
  • Atualizar vek1/pricing-design e billing pra incluir cota de conversations + overage
  • Comunicar lojistas: agora pagam tudo via plano vek1 (1 fatura só)

Trilha B — Solution Partner application (paralelo, leva meses)

Fase B0 — Material base (semanas 1-3, paralelo a A0-A3)

  • Cartão corporativo CNPJ com limite alto (R$10-50k)
  • Conta bancária PJ confirmada + extrato 3m
  • Termos de uso, política de privacidade, AUP publicados (mesmos da Trilha A3)
  • Acordo de processamento de dados LGPD/GDPR redigido
  • Compliance program interno documentado (em vek1/compliance-program nova nota)

Fase B1 — Business case + letters (semanas 2-6, conforme tração)

  • Pitch deck: mercado, projeção 12-24m, métricas vek1
  • 3-10 customer commitment letters em papel timbrado
  • Casos de uso: screencasts, métricas, depoimentos
  • Diagrama de arquitetura (reusa vek1/architecture)
  • Plano de suporte + SLA documentado

Fase B2 — Aplicação (mês 2-3, depois Tech Provider rodando)

  • Submeter no portal Solution Partner Meta
  • Entrevista solutions engineer Meta (call em inglês)
  • Responder follow-ups Meta

Fase B3 — Aprovação (mês 3-8, sem prazo garantido)

  • Solution Partner Agreement assinado
  • Linha de crédito Meta concedida
  • Dispara Fase A8 (Solution Partner activation)

6. Gotchas / riscos

Técnicos

  • Número não pode estar em 2 lugares: número em Evolution (Baileys) precisa deslogar + remover do WhatsApp antes de registrar via Cloud API. Janela de downtime por lojista durante migração — comunica antecedência.
  • Custo per-conversation (não per-message): janela 24h = 1 conversation. Brasil aprox (preços mudam): utility ~$0.008, marketing ~$0.0625, service grátis em janela aberta. Modelar em vek1/pricing-design — pode comer margem se lojista manda muito broadcast.
  • Rate limit Meta: tier 1 começa em 250 conversations/24h, escala automático conforme uso saudável.
  • 9º dígito brasileiro: wa_id às vezes vem sem o 9 que o lead tem cadastrado com. Normalizar antes de comparar com leads.external_id (ver lógica em whatsapp-handler.ts:243-258 — adaptar, não copiar).
  • Sem fromMe automático: webhook só recebe inbound. Statuses (sent/delivered/read/failed) vêm em value.statuses[] separado. Atualmente o handler ignora fromMe (vide linha 210) — manter ignorando.
  • Media URL expira em 5 min: baixar imediatamente no webhook, não armazenar URL.
  • Template params: variáveis em templates são posicionais ({{1}}, {{2}}). Validar contra components_schema antes de enviar pra evitar 400.
  • message_template_status_update: Meta avisa quando aprovar/rejeitar template — também passa no webhook. Handler obrigatório.
  • App in Live Mode: app fica em dev mode até passar review da Meta. Em dev mode, só números de teste recebem. Submeter pra app review antes de produção.
  • Encrypted token at rest: tokens long-lived por lojista — nunca logar wa_access_token. Usar mesma estratégia de vek1/decisions sobre tokens AbacatePay.
  • Token refresh: tokens long-lived (60 dias) precisam refresh. Cron diário verificando waTokenRefreshedAt < now - 50 dias chama refresh.

Solution Partner-específicos

  • Inadimplência lojista vira problema vek1: lojista usa 10k conversations, não paga plano vek1, Meta cobra vek1 mesmo assim. Controle de crédito: monitor de uso real-time, auto-suspend agent em atraso, cap de conversations no plano.
  • Compliance violation de 1 lojista pode banir WABA inteira: spam pesado de 1 lojista penaliza o app vek1 inteiro. Auto-suspend agent quando webhook account_alerts chega + revisão manual + processo de unbanning Meta documentado.
  • Volume mínimo Solution Partner Agreement: pode ter mínimos contratuais. Se não atingir, multa ou downgrade. Negociar antes de assinar.
  • Responsabilidade legal de dados: vek1 vira data processor formal Meta. LGPD compliance reforçado, audit log obrigatório (já tem audit_log).
  • Onboarding KYC do lojista: lojista ainda precisa fazer business verification própria pra mensagens marketing fora de janela (MARKETING templates). SERVICE/UTILITY rodam sem verification do lojista.

7. Decisões tomadas vs em aberto

Tomadas (2026-05-27)

  • ✅ Destino: Solution Partner (vek1 com payment ownership, cobra plano único)
  • ✅ Gate: Tech Provider (Meta exige histórico antes de aprovar Solution Partner)
  • ✅ Onboarding: Embedded Signup obrigatório (multi-tenant desde dia 1, sem form admin)
  • ✅ Templates: por WABA do lojista (auto-criados no /wa-connect)
  • ✅ Schema: wa_templates e wa_message_statuses tabelas próprias (vide §4.1)

Em aberto

  • Lidar com lojistas legados que não querem migrar: manter Evolution indefinidamente ou forçar deadline?
  • Pricing pass-through enquanto Tech Provider: lojista paga Meta direto (Opção 1). Quando Solution Partner: vek1 absorve no plano (Opção 2). Detalhar tiers em vek1/pricing-design
  • Fallback se Cloud API cai: provavelmente não (mesmo número não roda nos 2), mas alarmar via Sentry/monitor + comunicação ao lojista
  • Quem dispara take_payment_ownership: opt-in do lojista (botão na UI) ou bulk migration automático quando Solution Partner aprovar?
  • Como tratar lojistas que não querem que vek1 tome payment ownership (lojista grande, prefere fatura Meta separada): manter wa_payment_ownership='customer' indefinidamente como tier alternativo? Provavelmente sim — dois tiers de plano.
  • Onboarding: precisa criar Business da Kodama pro próprio uso ou já tem? (verificar)

8. Referências

Docs Meta

  • Cloud API overview: https://developers.facebook.com/docs/whatsapp/cloud-api
  • Embedded Signup: https://developers.facebook.com/docs/whatsapp/embedded-signup
  • Webhook signature: https://developers.facebook.com/docs/messenger-platform/webhooks#payload-verification
  • Pricing: https://developers.facebook.com/docs/whatsapp/pricing
  • Tech Provider: https://developers.facebook.com/docs/whatsapp/embedded-signup/tech-providers
  • Solution Partner (programa): https://business.facebook.com/business/help/solution-partner
  • Payment ownership API: https://developers.facebook.com/docs/whatsapp/business-management-api/payment-management
  • App Review: https://developers.facebook.com/docs/app-review
  • Business Verification: https://www.facebook.com/business/help/2058515294227817

Notas vek1

  • Estado atual integração: vek1/integrations
  • Gotchas vek1: vek1/gotchas
  • Decisões arquiteturais: vek1/decisions
  • Pricing design (atualizar pós-Solution Partner): vek1/pricing-design
  • Arquitetura (input pro pitch deck Trilha B): vek1/architecture
  • Compliance program (criar): vek1/compliance-program
  • Gap correspondente: vek1/gaps GAP-23
notas relacionadas
carregando…