ZAP-API
PreçosCasos de UsoBlogDocsLogin
Começar grátis
  1. Blog
  2. Cobrança PIX via WhatsApp: integração completa com QR Code
Arquitetura

Cobrança PIX via WhatsApp: integração completa com QR Code

Como integrar cobrança PIX ao WhatsApp: gerar QR Code, enviar pelo chat, receber confirmação de pagamento via webhook e atualizar o status automaticamente.

10 de maio de 2026·13 min de leitura·Equipe Editorial ZAP-API
Cobrança PIX via WhatsApp: integração completa com QR Code

Mandar link de pagamento por WhatsApp converte mais que email. Mandar QR Code PIX direto no chat converte ainda mais — porque o cliente não precisa sair do app, basta abrir o WhatsApp Web em outra aba ou usar o "PIX Copia e Cola" diretamente do chat. Em testes A/B com lojas que migraram de "link externo" para "QR PIX no chat", a taxa de conversão subiu de 12% para 34%.

Este artigo mostra a integração completa: gerar QR Code PIX, enviar como imagem pelo WhatsApp, receber webhook de confirmação e atualizar status do pedido. Código pronto para produção.

Arquitetura

Cinco passos:

  1. Cliente manda mensagem no WhatsApp pedindo cobrança ("quero pagar")
  2. Bot recebe via webhook da ZAP-API
  3. Bot chama gateway PIX (qualquer gateway brasileiro com API REST) para criar cobrança
  4. Bot envia QR Code como imagem + PIX Copia e Cola como texto
  5. Gateway dispara webhook quando pagamento confirma → bot avisa cliente que recebeu

Estrutura do payload de cobrança PIX

Independente do gateway escolhido, o fluxo é parecido. Você cria uma cobrança e recebe de volta:

  • txid — identificador único da cobrança
  • brCode — string EMV (PIX Copia e Cola)
  • qrCodeUrl ou qrCodeBase64 — imagem do QR
  • expirationSeconds — segundos até expirar (padrão 1800 = 30min)

Código: criar cobrança e enviar pelo WhatsApp

// pix-bot.js
import axios from "axios";
import express from "express";

const app = express();
app.use(express.json());

const ZAP = axios.create({
  baseURL: "https://api.zap-api.tech/v1",
  headers: { Authorization: `Bearer ${process.env.ZAP_TOKEN}` },
});

const PIX = axios.create({
  baseURL: process.env.PIX_GATEWAY_URL,
  headers: { Authorization: `Bearer ${process.env.PIX_TOKEN}` },
});

// Recebe webhook de mensagem do cliente
app.post("/webhook/zap", async (req, res) => {
  res.status(200).send("OK");
  const evento = req.body;

  if (evento.event !== "message.received") return;
  const texto = evento.message.text?.toLowerCase() || "";
  const remetente = evento.message.from;

  if (texto.includes("pagar") || texto.includes("pix")) {
    await gerarEEnviarCobranca({ telefone: remetente, valorCentavos: 9900 });
  }
});

async function gerarEEnviarCobranca({ telefone, valorCentavos }) {
  // 1. Cria cobrança no gateway
  const { data: cobranca } = await PIX.post("/cobrancas", {
    valor: { original: (valorCentavos / 100).toFixed(2) },
    chave: process.env.PIX_CHAVE,
    solicitacaoPagador: "Pedido #" + Date.now(),
    expiracaoSegundos: 1800,
    idempotencyKey: `pix-${telefone}-${Date.now()}`,
  });

  // 2. Envia QR Code como imagem
  await ZAP.post(`/instances/${process.env.ZAP_INSTANCE}/send`, {
    type: "image",
    phone: telefone,
    mediaUrl: cobranca.qrCodeUrl,
    caption: `Pague R$ ${(valorCentavos / 100).toFixed(2).replace(".", ",")} via PIX`,
  });

  // 3. Envia BR Code para copia e cola
  await ZAP.post(`/instances/${process.env.ZAP_INSTANCE}/send`, {
    type: "text",
    phone: telefone,
    body: `PIX Copia e Cola:\n\n${cobranca.brCode}\n\nO código expira em 30 minutos.`,
  });

  // 4. Persiste relação txid → telefone (para webhook de pagamento)
  await db.query(
    "INSERT INTO cobrancas_pendentes (txid, telefone, valor_centavos, criado_em) VALUES ($1, $2, $3, NOW())",
    [cobranca.txid, telefone, valorCentavos]
  );
}

app.listen(3000);

Código: webhook de confirmação de pagamento

app.post("/webhook/pix", async (req, res) => {
  res.status(200).send("OK");
  const { txid, status } = req.body;

  if (status !== "PAGO") return;

  // Busca o telefone associado ao txid
  const { rows: [pendente] } = await db.query(
    "SELECT telefone, valor_centavos FROM cobrancas_pendentes WHERE txid = $1",
    [txid]
  );

  if (!pendente) return;

  // Avisa cliente
  const valorFormatado = (pendente.valor_centavos / 100)
    .toFixed(2)
    .replace(".", ",");

  await ZAP.post(`/instances/${process.env.ZAP_INSTANCE}/send`, {
    type: "text",
    phone: pendente.telefone,
    body: `✅ Pagamento de R$ ${valorFormatado} confirmado!\n\nObrigado. Seu pedido entrou em processamento.`,
  });

  await db.query(
    "UPDATE cobrancas_pendentes SET status = 'pago', pago_em = NOW() WHERE txid = $1",
    [txid]
  );
});

Idempotência: evitar cobrar 2x

Cliente clica 2x no botão de pagar, ou a mensagem chega duplicada. Sem idempotência você gera 2 cobranças. Resolução:

// Antes de criar cobrança, checa se já existe ativa para esse telefone+valor
const { rows: existente } = await db.query(`
  SELECT txid FROM cobrancas_pendentes
  WHERE telefone = $1 AND valor_centavos = $2 AND status = 'pendente'
    AND criado_em > NOW() - INTERVAL '30 minutes'
`, [telefone, valorCentavos]);

if (existente.length > 0) {
  // Reenvia o QR existente em vez de criar novo
  return reenviarCobranca(existente[0].txid);
}

Código: gateway que só devolve base64

O campo mediaUrl precisa ser uma URL pública — a API não aceita base64 inline. Se o seu gateway PIX só retorna a imagem em base64, suba o arquivo no seu storage antes e mande a URL resultante:

// 1. Sobe o QR no seu bucket público (S3, R2, Spaces, etc.)
const buffer = Buffer.from(cobranca.qrCodeBase64, "base64"); // sem prefixo data:image/png;base64,
const key = `pix/${cobranca.txid}.png`;

await s3.putObject({
  Bucket: process.env.S3_BUCKET,
  Key: key,
  Body: buffer,
  ContentType: "image/png",
});

// 2. Envia usando a URL pública
await ZAP.post(`/instances/${process.env.ZAP_INSTANCE}/send`, {
  type: "image",
  phone: telefone,
  mediaUrl: `https://cdn.suaempresa.com.br/${key}`,
  caption: `Pague R$ ${valor} via PIX`,
});

Use TTL curto no objeto (30 minutos, mesmo prazo do QR) para não acumular lixo no bucket.

Tratamento de expiração

QR PIX expira (padrão 30min). Se cliente abrir mensagem antiga e tentar pagar, vai falhar. Solução: cron que checa pendentes expirando e oferece renovar.

// Roda a cada 5 minutos
async function avisarExpiracao() {
  const { rows } = await db.query(`
    SELECT txid, telefone FROM cobrancas_pendentes
    WHERE status = 'pendente'
      AND criado_em > NOW() - INTERVAL '30 minutes'
      AND criado_em < NOW() - INTERVAL '25 minutes'
      AND aviso_expiracao_em IS NULL
  `);

  for (const c of rows) {
    await ZAP.post(`/instances/${process.env.ZAP_INSTANCE}/send`, {
      type: "text",
      phone: c.telefone,
      body: "Seu PIX expira em 5 minutos. Quer que eu gere um novo? Responda SIM.",
    });
    await db.query(
      "UPDATE cobrancas_pendentes SET aviso_expiracao_em = NOW() WHERE txid = $1",
      [c.txid]
    );
  }
}

Curl de teste

# Simula cliente pedindo cobrança
curl -X POST https://seu-bot.com.br/webhook/zap \
  -H "Content-Type: application/json" \
  -d '{
    "event": "message.received",
    "message": {
      "from": "5511999998888",
      "text": "quero pagar"
    }
  }'

FAQ

Existe limite de valor para cobrança PIX?

Por padrão, R$ 1,00 a R$ 50.000,00 por transação na maioria dos gateways (configurável pelo banco). Para valores maiores, contrato dedicado com seu banco.

QR expirou. O cliente pode pagar mesmo assim?

Não. PIX com expiração rejeita pagamento após o prazo. Por isso o cron de aviso é importante — você renova antes do cliente tentar pagar e ver erro.

Como faço conciliação financeira?

Cada gateway PIX expõe relatório de pagamentos por dia/período. Cruze com sua tabela cobrancas_pendentes usando txid como chave. Diferenças indicam webhook perdido.

Posso fazer split de pagamento (PIX para mim + PIX para parceiro)?

Depende do gateway. Alguns suportam split automático nativo (você cria cobrança com array de destinatários e percentuais). Outros só permitem cobrança simples e você redistribui depois via TED/PIX próprio.

Como faço reembolso?

PIX reembolso (devolução) é uma operação separada — você chama endpoint /devolucao do gateway com txid e valor. Avise o cliente pelo WhatsApp também ("PIX devolvido. Cair na conta em até 60s").

Próximo passo

Crie sua conta — instâncias permitem envio de imagem, áudio, vídeo, documentos e botões. Criar conta grátis.

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 · 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 · 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.

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 · 19 de mai. de 2026 · 13 min

Rate limiting em WhatsApp API: throttle inteligente por sessão

Implemente rate limiting inteligente para disparos WhatsApp: throttle dinâmico por número, janelas deslizantes e backoff automático para evitar banimento.

Tópicos:Chatbots com IAE-commerceAPI WhatsApp

Explore também

API WhatsApp grátisTeste 7 dias, sem cartãoAutomação WhatsAppAutomatize via REST APIAPI não oficialSem aprovação da MetaCasos 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
  • Automação WhatsApp
  • API não oficial
  • Comparativo
  • API WhatsApp 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