ZAP-API
PreçosCasos de UsoBlogDocsLogin
Começar grátis
  1. Blog
  2. Como escalar WhatsApp para 100 mil mensagens/dia: arquitetura, fila e custo real
Arquitetura

Como escalar WhatsApp para 100 mil mensagens/dia: arquitetura, fila e custo real

Limites por instância, cálculo de quantas você precisa, outbox pattern, circuit breaker, warmup pool e 4 métricas vitais. Custo unitário de R$ 0,0009/msg.

30 de abril de 2026·14 min de leitura·Equipe Editorial ZAP API

Sair de 1 mil para 100 mil mensagens por dia no WhatsApp não é "comprar plano maior" — é arquitetura. Uma instância sozinha banhe antes de chegar lá; um sistema sem fila desconecta sob carga; sem circuit breaker, um pico de erro vira cascata.

Este guia mostra como escalar de forma segura: limites reais por instância, divisão entre múltiplas instâncias, fila com retry, circuit breaker, padrão de "warmup pool" e as 4 métricas que importam.

Limites reais por instância (em 2026)

Estado da instânciaVolume seguro/diaCuidados
Recém-pareada (dia 1–7)≤ 50Warmup obrigatório
Em warmup (dia 8–14)≤ 200Crescer gradual
Madura (15+ dias)1.000–2.000Cadência humana
Madura premium (60+ dias, baixa denúncia)3.000–5.000Limite efetivo da plataforma

Ou seja: 100k mensagens/dia exige 20–50 instâncias maduras, não uma só. Não há atalho.

Cálculo: quantas instâncias preciso?

volume_diario = 100.000
volume_por_instancia_madura = 2.500 (média conservadora)
margem_seguranca = 1.5x  // pra absorver picos

instancias_minimas = ceil(volume_diario / volume_por_instancia_madura * margem_seguranca)
                   = ceil(100.000 / 2.500 * 1.5)
                   = 60 instâncias

Cada instância na ZAP API custa R$ 49 (1ª e 2ª) e R$ 29 (3ª+). 60 instâncias = R$ 49+R$ 49 + 58×R$ 29 = R$ 1.780/mês. Soma 100k mensagens/dia ≈ 3M mensagens/mês — custo unitário de ~R$ 0,0006/mensagem. Compare com SMS (R$ 0,08–0,15) ou Push (R$ 0,001–0,005).

Arquitetura: outbox pattern + fila distribuída

┌─────────────────┐
│  Sua aplicação  │
└────────┬────────┘
         │ insere no banco
         ▼
┌─────────────────┐    ┌──────────────────┐
│  outbox_jobs    │◀───│ Lock distribuído │
│  (Postgres)     │    │ (Redis SETNX)    │
└────────┬────────┘    └──────────────────┘
         │ poll a cada 100ms
         ▼
┌─────────────────┐    ┌──────────────────┐
│ OutboxWorker x4 │───▶│ Circuit breaker  │
└────────┬────────┘    │ per instance     │
         │             └──────────────────┘
         ▼
┌─────────────────┐
│  ZAP API send   │
└─────────────────┘

Por que outbox e não enviar direto?

  • Atomicidade transacional: registrar mensagem + acionar envio na mesma transação. Se a aplicação cair entre os dois, mensagem fica na fila — não perdida.
  • Retry sem lógica espalhada: tudo vive no worker.
  • Backpressure natural: se ZAP API estiver lenta, a fila enche, mas o cliente que insere não fica bloqueado.

Schema da tabela outbox

CREATE TABLE outbox_jobs (
  id BIGSERIAL PRIMARY KEY,
  instance_id VARCHAR(64) NOT NULL,
  phone VARCHAR(32) NOT NULL,
  payload JSONB NOT NULL,
  status VARCHAR(16) DEFAULT 'pending',
  attempts INT DEFAULT 0,
  next_retry_at TIMESTAMP DEFAULT now(),
  last_error TEXT,
  created_at TIMESTAMP DEFAULT now(),
  sent_at TIMESTAMP
);

CREATE INDEX idx_outbox_pending
ON outbox_jobs (status, next_retry_at)
WHERE status = 'pending';

Worker (Node.js + BullMQ)

const { Worker } = require('bullmq');

new Worker('outbox', async (job) => {
  const { instanceId, phone, payload } = job.data;

  // Circuit breaker per-instance
  if (await breaker.isOpen(instanceId)) {
    throw new Error('CircuitOpen');
  }

  try {
    await zapApi.send({ instanceId, phone, ...payload });
    await db.outbox.update({ status: 'sent', sentAt: new Date() },
      { where: { id: job.data.id } });
    breaker.recordSuccess(instanceId);
  } catch (err) {
    breaker.recordFailure(instanceId, err);
    if (err.statusCode === 429) {
      // Rate limit — espera o Retry-After
      throw new Error('RateLimit:' + err.headers['retry-after']);
    }
    throw err;
  }
}, {
  connection: redis,
  concurrency: 4, // por worker
  limiter: { max: 60, duration: 60_000 } // 60/min por instância
});

Circuit breaker per-instance

Sem circuit breaker, uma instância com problema (banimento, gateway down, etc) faz seus 4 workers ficarem girando em retry e queimar todo o Redis/DB. Implementação:

class CircuitBreaker {
  constructor() {
    this.state = new Map(); // instanceId → state
  }

  async isOpen(instanceId) {
    const s = this.state.get(instanceId) || { failures: 0, openedAt: 0 };
    if (s.openedAt && Date.now() - s.openedAt < 30_000) return true;
    if (s.openedAt) this.state.set(instanceId, { failures: 0, openedAt: 0 }); // reabre
    return false;
  }

  recordFailure(instanceId, err) {
    const s = this.state.get(instanceId) || { failures: 0, openedAt: 0 };
    s.failures++;
    if (s.failures >= 3 && err.statusCode >= 500) {
      s.openedAt = Date.now();
      console.warn(`Circuit opened for ${instanceId}`);
    }
    this.state.set(instanceId, s);
  }

  recordSuccess(instanceId) {
    this.state.set(instanceId, { failures: 0, openedAt: 0 });
  }
}

Padrão "Warmup Pool"

Não pode ter todas as instâncias maduras desde o dia 1 — chip novo entra em warmup. Solução: dividir em 3 pools:

PoolOcupação típicaTipo de tráfego
Hot (maduras 60+ dias)70% das instânciasAlta volume, marketing, broadcast
Warm (maduras 15–60 dias)20%Volume médio, transacional
Cold/Warmup (0–14 dias)10%Apenas inbound + low-volume outbound

Roteador escolhe pool por critério:

function escolherInstancia(tipoMensagem) {
  if (tipoMensagem === 'broadcast') return poolHot.next();
  if (tipoMensagem === 'transactional') return poolWarm.next();
  return poolHot.next(); // default
}

A cada 15 dias, promova as 10% mais antigas do warm para hot, e adicione novas instâncias ao cold.

As 4 métricas que importam

  1. Throughput entregue (msg/min): deveria estar perto da capacidade nominal das instâncias hot. Queda repentina = investigar.
  2. Taxa de erro 4xx/5xx (%): > 2% = alerta. > 10% = pause envios e investigue.
  3. Tempo médio na fila (p95): idealmente < 30s. Se > 5min, falta capacidade — adicione instâncias.
  4. Disconnect streak por instância: conta de desconexões consecutivas. > 3 em 1h = remover do pool, investigar.

A ZAP API expõe tudo isso em /super-admin/instances com sparkline 24h/7d/30d e endpoint agregado GET /v1/super-admin/summary.

Custo real total para 100k/dia

60 instânciasR$ 1.780/mês
Chips pré-pagos (1x R$ 30 cada)R$ 1.800 (one-time)
Smartphones para celulares vinculados (15× R$ 700, 4 instâncias por device)R$ 10.500 (one-time)
Infra (Redis cluster + Postgres + workers)R$ 800/mês
Total mensal recorrenteR$ 2.580
Custo unitário por mensagem~R$ 0,0009

FAQ

  • Tem como pular o warmup?
    Não com risco aceitável. Pode comprar instâncias "envelhecidas" no mercado, mas é prática cinza e o ban também vem.
  • Posso vincular vários WhatsApp num único celular?
    Sim — até 4 sessões multidevice por celular vinculado. Acima disso, conflitos.
  • Vale a pena criar uma instância "VIP" para clientes pagantes?
    Sim — separe pool transacional (entrega rápida, baixa fila) do marketing (tolera fila maior).
  • O que faço se uma instância banir no meio da operação?
    Remove do pool no roteador. Volume é redistribuído entre as outras automaticamente. Esse é o motivo de margem 1.5x no cálculo.
  • Posso usar Cloud API oficial pra escalar?
    Pode, mas tem outros limites e custo por categoria de mensagem. Para escalar com previsibilidade técnica e financeira, multi-instância via API não-oficial costuma sair mais barato e com menos burocracia.

Criar conta para escalar (descontos a partir da 3ª instância) — trial 7 dias.

Experimente a ZAP API gratuitamente

7 dias de trial sem precisar de cartão. A partir de R$29/mês*.

Criar instância grátis
EE
Equipe Editorial ZAP APIRevisão técnica

Desenvolvedores e especialistas em integrações WhatsApp. Todo conteúdo passa por revisão técnica para garantir precisão e aplicabilidade.

Ver perfil completoDocumentaçãoTrial grátis

Leia também

Arquitetura · 26 de mai. de 2026 · 14 min

Multi-instância WhatsApp: arquitetura para escalar sem banimento

Como distribuir envios entre múltiplas instâncias WhatsApp para escalar volume, isolar clientes e proteger números críticos de banimento por sobrecarga.

Arquitetura · 15 de mai. de 2026 · 13 min

Circuit breaker em WhatsApp API: proteja sua instância de sobrecarga

Implemente circuit breaker para sua integração WhatsApp: evite cascata de falhas, proteja sua instância de rate limiting e garanta degradação graciosa.

Arquitetura · 05 de jun. de 2026 · 14 min

Pipeline editorial IA multi-agente em produção: 5 agentes, ~85% menos custo

Como rodamos um pipeline editorial multi-agente em produção: 5 agentes Claude especializados, paralelização, prompt caching e background job. Arquitetura replicável.

Arquitetura · 30 de mai. de 2026 · 13 min

Mensagem idempotente no WhatsApp: nunca envie a mesma mensagem duas vezes

Como implementar idempotência em disparos WhatsApp para evitar mensagens duplicadas em retries, falhas de rede e race conditions em sistemas distribuídos.

Tópicos:Chatbots com IAE-commerceAPI WhatsApp

Explore também

Casos de usoWhatsApp API por segmentoComparativoZAP API vs alternativasPreçosPlanos e o que está inclusoGlossárioTermos técnicos de WhatsApp API
ZAP-API

API REST para WhatsApp com webhooks assinados, Meta Pixel/CAPI e compliance LGPD. Sem aprovação da Meta.

Status operacional🇧🇷 Feito no Brasil

Produto

  • Preços
  • Casos de uso
  • Comparativo
  • Trial grátis
  • Dashboard

Recursos

  • Documentação
  • Blog
  • Glossário
  • RSS Feed

Empresa

  • Sobre
  • Imprensa
  • Termos de uso
  • Privacidade
  • Criar conta
  • Login

Contato

  • [email protected]
  • [email protected]
  • Resposta em até 24h úteis
© 2026 ZAP-API — Todos os direitos reservados·CNPJ 42.130.949/0001-56·Termos·Privacidade

Desenvolvido por PreviusIA