Agência de marketing digital com 20 clientes ativos sem estrutura é um caos previsível. Um WhatsApp pessoal do dono atendendo o "TaylorBurguer" e a "Clínica DentalMax" e a "Imobiliária Ribeiro", todos no mesmo lugar. Mensagens cruzando, atendentes confusos, cliente reclamando que falta resposta. Pergunta de R$50k/mês: como organizar?
A resposta é multi-tenancy: uma instância WhatsApp por cliente, isolada, com billing e relatório próprio. Este artigo mostra a arquitetura completa que agências profissionais usam para escalar de 5 para 100+ clientes sem virar pesadelo operacional.
O caos sem estrutura
Sem multi-tenancy, sua agência tem:
- 1 ou 2 WhatsApps "operacionais" para tudo
- Atendente abrindo Trello/Notion para identificar de qual cliente é cada conversa
- Quando o cliente "TaylorBurguer" pede "qual o status das minhas campanhas?", você não tem dados separados — está tudo misturado
- Quando precisa cobrar o cliente, fatura sai bagunçada — "campanha + automação + relatório" virando uma linha só
- Quando o cliente cancela, você não sabe a margem real dele (custo da operação misturado com outros)
A arquitetura multi-tenant
Estrutura recomendada:
- Conta agência na ZAP-API com perfil reseller
- Sub-conta por cliente — cada cliente seu vira uma "company" filha
- Instância dedicada por cliente — número WhatsApp do próprio cliente conecta nessa instância
- Webhooks isolados por cliente, apontando para subdomínios dedicados (cliente1.dashboard.suaagencia.com)
- Billing centralizado — agência recebe 1 fatura mensal consolidada da ZAP-API, gera N faturas para os clientes
Diagrama de relacionamento
Agência X
├─ Cliente A (TaylorBurguer)
│ └─ Instância A1 (número 11999998888)
│ └─ Webhook: https://taylor.suaagencia.com/wh
├─ Cliente B (DentalMax)
│ └─ Instância B1 (número 11888887777)
│ └─ Webhook: https://dentalmax.suaagencia.com/wh
└─ Cliente C (Ribeiro Imóveis)
└─ Instância C1 (número 11777776666)
└─ Webhook: https://ribeiro.suaagencia.com/wh
Provisionamento via API
// onboard-cliente.ts
import axios from "axios";
// Chave server-to-server da agência (ak_...) — provisiona subcontas
const ZAP = axios.create({
baseURL: "https://api.zap-api.tech/v1",
headers: { Authorization: `Bearer ${process.env.ZAP_AGENCY_API_KEY}` },
});
async function onboardCliente({ nome, refInterno, planoMensal }) {
// 1. Cria subconta + instância dedicada numa chamada só.
// externalRef deixa a operação idempotente (reexecutar não duplica).
const { data: instancia } = await ZAP.post("/reseller/api/instances", {
displayName: `${nome} - Principal`,
externalRef: refInterno,
});
// 2. Configura o webhook do cliente.
// Atenção: webhook é configurado com o TOKEN DA INSTÂNCIA (tk_...),
// não com a chave da agência.
const subdominio = nome.toLowerCase().replace(/\s+/g, "");
await axios.put(
`https://api.zap-api.tech/v1/instances/${instancia.instanceId}/webhook`,
{
url: `https://${subdominio}.dashboard.suaagencia.com/webhooks/zap`,
events: ["message.received", "message.status", "instance.connected", "instance.disconnected"],
},
{ headers: { Authorization: `Bearer ${instancia.token}` } },
);
// 3. Salva no banco da agência para faturamento e dashboard.
// O token só aparece nesta resposta — guarde agora.
await db.query(`
INSERT INTO clientes_agencia (company_id, instance_id, instance_token, plano_mensal_centavos, status, onboarded_at)
VALUES ($1, $2, $3, $4, 'active', NOW())
`, [instancia.companyId, instancia.instanceId, instancia.token, planoMensal * 100]);
return {
portalUrl: `https://${subdominio}.dashboard.suaagencia.com`,
qrCodeUrl: `https://${subdominio}.dashboard.suaagencia.com/conectar`,
pairingEndpoint: `https://api.zap-api.tech/v1/instances/${instancia.instanceId}/pairing`,
};
}
Dashboard agregado da agência
O dono da agência precisa ver tudo de uma vez: quem está conectado, quantas instâncias cada cliente tem e como está a margem. São duas chamadas — uma lista as instâncias com o status de conexão, a outra agrupa por empresa cliente.
// agency-overview.ts
async function getAgencyOverview() {
// Instâncias com status de conexão (chave ak_ da agência)
const { data: { instances } } = await ZAP.get("/reseller/api/instances");
// Agrupamento por empresa cliente (JWT do painel)
const PAINEL = axios.create({
baseURL: "https://api.zap-api.tech/v1",
headers: { Authorization: `Bearer ${process.env.ZAP_JWT}` },
});
const { data: { clients } } = await PAINEL.get("/reseller/me/clients");
// Cruza com o seu banco: externalRef → cliente da agência
return clients.map(c => {
const doCliente = instances.filter(i => i.externalRef?.startsWith(`cliente-${c.companyId}`));
return {
cliente: c.name,
instancias: c.totalInstances,
ativas: c.activeInstances,
trial: c.trialInstances,
todasConectadas: doCliente.length > 0 && doCliente.every(i => i.connected),
};
});
}
// Margem consolidada da agência (bruto, custo de atacado e líquido)
async function getAgencyMrr() {
const { data } = await PAINEL.get("/reseller/me/stats");
return data.mrr; // { grossCents, wholesaleCostCents, netCents, ... }
}
Volume de mensagens não sai por aqui — o painel reseller reporta instâncias e receita, não tráfego. Para contar mensagens por cliente, consulte o log de cada instância com o token dela (próxima seção).
Modelo de billing
Você tem 2 grandes opções de cobrança do cliente final:
Opção 1: Por mensagem (uso variável)
- Cobre R$0,15 por mensagem enviada
- Cliente pequeno (1k msgs/mês) paga R$150/mês
- Cliente médio (10k msgs/mês) paga R$1.500/mês
- Cliente grande (50k msgs/mês) paga R$7.500/mês
Vantagem: precificação justa, cliente paga pelo que usa. Desvantagem: receita imprevisível.
Opção 2: Plano fixo por instância
- R$199/mês — até 2.000 mensagens, suporte email
- R$499/mês — até 10.000 mensagens, integrações, prioridade
- R$999/mês — ilimitado dentro do uso comercial razoável + setup assistido
Vantagem: receita previsível. Desvantagem: cliente que usa pouco se sente lesado.
Opção híbrida (recomendada)
Plano base fixo + cobrança extra acima do incluso. Ex.: R$299 inclui 5k msgs, R$0,08 por msg adicional. É o melhor dos dois mundos: você tem MRR estável e cobra extra dos clientes pesados.
Relatório individual por cliente
Toda última semana do mês, dispare relatório automático para cada cliente:
// monthly-report.ts
async function sendMonthlyReports() {
const clientes = await db.query("SELECT * FROM clientes_agencia WHERE status='active'");
for (const c of clientes.rows) {
// Log de mensagens da instância — autenticado com o token DELA (tk_...)
const { data } = await axios.get(
`https://api.zap-api.tech/v1/instances/${c.instance_id}/messages`,
{
params: { limit: 200 },
headers: { Authorization: `Bearer ${c.instance_token}` },
},
);
const enviadas = data.messages.filter(m => m.direction === "out").length;
const recebidas = data.messages.filter(m => m.direction === "in").length;
const lidas = data.messages.filter(m => m.status === "read").length;
const taxaLeitura = enviadas ? Math.round((lidas / enviadas) * 100) : 0;
const html = `
Relatório ${new Date().toLocaleString("pt-BR", { month: "long", year: "numeric" })}
- Mensagens enviadas: ${enviadas}
- Mensagens recebidas: ${recebidas}
- Taxa de leitura: ${taxaLeitura}%
- Total no período: ${data.total}
Continuamos otimizando suas campanhas.
`;
await sendEmail(c.email, `Seu relatório do WhatsApp — ${c.name}`, html);
}
}
O limit do log é no máximo 200 por página — para o mês inteiro, pagine com offset ou espelhe os eventos no seu banco via webhook, que é o que agências com volume acabam fazendo.
Casos práticos
Caso 1: Agência boutique (8 clientes)
Atende dentistas, advogados, arquitetos. Plano R$499/mês fixo. MRR R$3.992. Custo infraestrutura R$390 (8 × R$49). Margem bruta 90%. Dona consegue manter operação sozinha — atendimento concentrado nos clientes premium.
Caso 2: Agência média (35 clientes)
Mistura nichos. Plano híbrido R$299 + R$0,08/msg extra. MRR base R$10.465 + média R$3.500 em uso variável. 2 atendentes, 1 desenvolvedor. Dashboard interno mostra "alertas" — cliente sem atividade há 7 dias dispara aviso para o gerente de conta ligar.
Caso 3: Agência B2B (90 clientes industriais)
Atende indústrias com pós-venda complexo. Plano R$999/mês com SLA. Time de 6 pessoas, dashboard com filas dedicadas, cada cliente tem 2-3 instâncias (vendas/suporte/cobrança). MRR R$89k. Diferencial: implementação assistida que custa R$5k extra mas vira anchor para R$11k/ano em recorrente.
FAQ
Como precificar quando o cliente pergunta?
Não venda "WhatsApp" — venda resultado. "Vamos automatizar seu atendimento e gerar 30% mais conversão" vale R$499. "Te dou uma instância WhatsApp por R$199" é commodity. O preço sobe com o resultado entregue, não com a tecnologia.
Preciso de contrato com cada cliente?
Sim. Contrato simples (1-2 páginas) deve cobrir: serviços inclusos, valor mensal, prazo (mínimo 6 meses), reajuste anual, multa de cancelamento, LGPD/sigilo. Modelo está em qualquer site jurídico — adapte e use.
Como organizo suporte tier-1?
Crie SLA por plano. Plano básico = email com 24h, plano profissional = WhatsApp com 4h, plano agência = telefone com 1h. Use ferramenta tipo Front, Help Scout ou Zendesk para centralizar tickets. Tier-1 (atendente) resolve 80%, escala para tier-2 (desenvolvedor) só quando precisa.
Como funciona o white-label?
No painel da ZAP-API, ative reseller, adicione logo, cor primária e domínio próprio. Seu cliente acessa painel.suaagencia.com e nunca vê referência a "ZAP-API". Detalhes profundos no nosso post sobre criar agência white-label.
Como reduzo churn?
Churn em agência de marketing é tipicamente 5-7% ao mês. Para baixar, foque em 2 coisas: (1) onboarding ativo nos primeiros 30 dias — cliente que vê valor cedo fica; (2) relatórios mensais com números — cliente que entende o que está pagando não cancela por achar que "não precisa mais".
Próximo passo
Configure conta reseller agência e provisione seu primeiro cliente em 15 minutos. Criar conta grátis e teste o painel multi-tenant por 7 dias.