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

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}/messages`, {
    type: "image",
    to: telefone,
    url: 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}/messages`, {
    type: "text",
    to: telefone,
    text: `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}/messages`, {
    type: "text",
    to: pendente.telefone,
    text: `✅ 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: imagem em base64 (alternativa)

Se o gateway não retorna URL de imagem, mas sim base64:

await ZAP.post(`/instances/${process.env.ZAP_INSTANCE}/messages`, {
  type: "image",
  to: telefone,
  base64: cobranca.qrCodeBase64, // sem prefixo data:image/png;base64,
  mimetype: "image/png",
  caption: `Pague R$ ${valor} via PIX`,
});

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}/messages`, {
      type: "text",
      to: c.telefone,
      text: "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

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