Pular para o conteúdo principal

Visão Geral

Este guia apresenta o fluxo completo de integração PIX, cobrindo tanto recebimentos (PIX In) quanto transferências (PIX Out). O PIX oferece transações instantâneas 24/7, sendo o método de pagamento mais ágil do Brasil.

PIX In - Recebimentos

1

Criação de Cobrança PIX

Gerar QR Code e chave PIX para recebimento
2

Apresentação do QR Code

Mostrar QR Code e código copia-e-cola para o cliente
3

Aguardando Pagamento

Monitoramento em tempo real via polling ou webhooks
4

Confirmação de Pagamento

PIX recebido - Webhook PAID com movementType: CREDIT

PIX Out - Transferências

1

Iniciação de Transferência

Envio de PIX para terceiros usando chave PIX
2

Validação e Processamento

Sistema valida saldo, chave PIX e dados do destinatário
3

Confirmação de Transferência

PIX enviado - Webhook PAID com movementType: DEBIT

Fluxo PIX In (Recebimentos)

1. Criação de Cobrança PIX

Inicie o processo criando uma cobrança PIX:
curl --request POST \
  --url https://api-gateway.firebanking.com.br/pix/v2/payment \
  --header 'x-api-key: sua_chave_api' \
  --header 'Content-Type: application/json' \
  --data '{
    "businessTransactionId": "venda-54321",
    "description": "Pagamento produto XYZ",
    "value": 89.90,
    "buyer": {
      "name": "Maria Santos",
      "document": "98765432109",
      "email": "[email protected]"
    },
    "expiresIn": 3600
  }'
Resposta da API:
{
  "transactionId": "pix_abc123def456",
  "businessTransactionId": "venda-54321",
  "status": "WAITING_PAYMENT",
  "value": 89.90,
  "qrCode": "00020101021226580014br.gov.bcb.pix2536pix.firebanking.com.br/qr/v2/abc123def4565204000053039865404899.905802BR5913FIRE BANKING6009Sao Paulo62070503***6304C2A8",
  "qrCodeImage": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51...",
  "pixKey": "pix.firebanking.com.br/qr/v2/abc123def456",
  "expiresAt": "2025-04-07T16:23:45.678Z",
  "createdAt": "2025-04-07T15:23:45.678Z"
}

2. Apresentação do QR Code

Mostre o QR Code PIX para o cliente:
<div class="pix-payment">
  <div class="qr-section">
    <img src="{{qrCodeImage}}" alt="QR Code PIX" class="qr-code">
    <p class="qr-instruction">
      Escaneie o QR Code com seu app bancário ou Pix
    </p>
  </div>

  <div class="copy-paste-section">
    <label>Ou copie o código PIX:</label>
    <div class="code-input">
      <input type="text" value="{{qrCode}}" readonly id="pix-code">
      <button onclick="copyPixCode()">Copiar</button>
    </div>
  </div>

  <div class="payment-info">
    <p><strong>Valor:</strong> R$ {{value}}</p>
    <p><strong>Descrição:</strong> {{description}}</p>
    <p><strong>Expira em:</strong> <span id="countdown"></span></p>
  </div>
</div>
function copyPixCode() {
  const codeInput = document.getElementById('pix-code');
  codeInput.select();
  document.execCommand('copy');

  // Feedback visual
  const button = event.target;
  button.textContent = 'Copiado!';
  setTimeout(() => {
    button.textContent = 'Copiar';
  }, 2000);
}

// Countdown de expiração
function startCountdown(expiresAt) {
  const countdownElement = document.getElementById('countdown');

  const updateCountdown = () => {
    const now = new Date().getTime();
    const expiry = new Date(expiresAt).getTime();
    const timeLeft = expiry - now;

    if (timeLeft > 0) {
      const minutes = Math.floor(timeLeft / (1000 * 60));
      const seconds = Math.floor((timeLeft % (1000 * 60)) / 1000);
      countdownElement.textContent = `${minutes}m ${seconds}s`;
    } else {
      countdownElement.textContent = 'Expirado';
      handlePixExpired();
    }
  };

  updateCountdown();
  return setInterval(updateCountdown, 1000);
}

3. Aguardando Pagamento

Implemente polling ou WebSocket para verificar o status:
// Polling para verificar status
async function checkPaymentStatus(transactionId) {
  try {
    const response = await fetch(
      `https://api-gateway.firebanking.com.br/pix/v2/payment/${transactionId}`,
      {
        headers: {
          'x-api-key': 'sua_chave_api'
        }
      }
    );

    const payment = await response.json();

    if (payment.status === 'PAID') {
      handlePaymentSuccess(payment);
      return true;
    } else if (payment.status === 'EXPIRED') {
      handlePaymentExpired(payment);
      return true;
    }

    return false;
  } catch (error) {
    console.error('Erro verificando status:', error);
    return false;
  }
}

// Iniciar verificação periódica
function startPaymentMonitoring(transactionId) {
  const interval = setInterval(async () => {
    const completed = await checkPaymentStatus(transactionId);

    if (completed) {
      clearInterval(interval);
    }
  }, 3000); // Verifica a cada 3 segundos

  // Parar após 1 hora (tempo máximo)
  setTimeout(() => {
    clearInterval(interval);
    handlePaymentTimeout();
  }, 3600000);
}

4. Confirmação de Pagamento

Quando o PIX é pago, você recebe um webhook:
{
  "transactionId": "03cadd36-fddd-4091-9ffe-67b0483cbcf5",
  "businessTransactionId": "venda-54321",
  "status": "PAID",
  "value": 8990,
  "movementType": "CREDIT",
  "endToEndId": "E12345678202504071523456789012",
  "pixKey": "[email protected]",
  "createdDate": "2025-04-07T15:25:12.345Z",
  "ReceiverBankAccount": "567890",
  "ReceiverToBankAccountDigit": "1",
  "ReceiverBankBranch": "0001",
  "ReceiverBankCode": "077",
  "ReceiverDocumentNumber": "45438750000188",
  "ReceiverBankName": "BANCO INTER S.A.",
  "ReceiverBankISPB": "00416968",
  "ReceiverName": "MINHA EMPRESA LTDA",
  "PayerBankAccount": "12345",
  "PayerBankAccountDigit": "6",
  "PayerBankBranch": "0001",
  "PayerBankCode": "001",
  "PayerDocumentNumber": "98765432109",
  "PayerBankName": "BANCO DO BRASIL S.A.",
  "PayerBankISPB": "00000000",
  "PayerName": "MARIA SANTOS",
  "VoucherUrl": "https://voucher.firebanking.com/pix/03cadd36-fddd-4091-9ffe-67b0483cbcf5.pdf"
}

Fluxo PIX Out (Transferências)

1. Iniciação de Transferência

Para enviar PIX para terceiros:
curl --request POST \
  --url https://api-gateway.firebanking.com.br/pix/v2/payment/withdraw \
  --header 'x-api-key: sua_chave_api' \
  --header 'Content-Type: application/json' \
  --data '{
    "type": "PIX",
    "value": 1500,
    "details": {
      "key": "12345678901",
      "keyType": "DOCUMENT",
      "name": "João Fornecedor",
      "document": "12345678901"
    },
    "externalId": "transfer-98765"
  }'

2. Validação e Processamento

A transferência passa por validações antes do envio:
  • Saldo disponível: Verificação de fundos suficientes
  • 🔍 Validação da chave PIX: Consulta no BACEN
  • 👤 Dados do destinatário: Verificação de CPF/CNPJ
  • 🛡️ Limites operacionais: Validação de limites diários

3. Confirmação de Transferência

Webhook de confirmação da transferência enviada:
{
  "transactionId": "withdraw-abc123-def456-ghi789",
  "businessTransactionId": "transfer-98765",
  "status": "WITHDRAW_PAID",
  "value": 150000,
  "movementType": "DEBIT",
  "endToEndId": "E12345678202504071530987654321",
  "pixKey": "12345678901",
  "createdDate": "2025-04-07T15:30:45.123Z",
  "ReceiverBankAccount": "98765",
  "ReceiverToBankAccountDigit": "4",
  "ReceiverBankBranch": "0001",
  "ReceiverBankCode": "341",
  "ReceiverDocumentNumber": "12345678901",
  "ReceiverBankName": "BANCO ITAÚ UNIBANCO S.A.",
  "ReceiverBankISPB": "60701190",
  "ReceiverName": "JOAO FORNECEDOR",
  "PayerBankAccount": "567890",
  "PayerBankAccountDigit": "1",
  "PayerBankBranch": "0001",
  "PayerBankCode": "077",
  "PayerDocumentNumber": "45438750000188",
  "PayerBankName": "BANCO INTER S.A.",
  "PayerBankISPB": "00416968",
  "PayerName": "MINHA EMPRESA LTDA",
  "VoucherUrl": "https://voucher.firebanking.com/withdraw/withdraw-abc123-def456-ghi789.pdf"
}

Estados das Transações PIX

StatusDescriçãoAção Recomendada
WAITING_CONFIRMATIONAguardando confirmação inicialAguardar processamento
WAITING_PAYMENTAguardando pagamento (PIX In)Apresentar QR Code
WAITING_WITHDRAWAguardando execução de saqueAguardar processamento
WITHDRAW_REQUESTSolicitação de saque enviadaAguardar confirmação
WITHDRAW_PAIDSaque/transferência confirmadaConfirmar envio
PAIDPIX recebido com sucessoLiberar produto/serviço
REFUND_INEstorno PIX recebidoProcessar devolução
ERRORErro no processamentoInvestigar erro

Tipos de Chave PIX

TipoFormatoExemplo
DOCUMENTCPF (11 dígitos) ou CNPJ (14 dígitos)12345678901 ou 12345678000199
MAILEmail válido[email protected]
PHONE+55 + DDD + número+5511987654321
RANDOM_KEYChave aleatória123e4567-e12b-12d3-a456-426614174000

Webhook Handler Completo

app.post('/webhooks/pix', express.raw({type: 'application/json'}), (req, res) => {
  try {
    const payload = JSON.parse(req.body);

    // Verificar assinatura
    if (!verifyWebhookSignature(req.headers, req.body)) {
      return res.status(401).send('Unauthorized');
    }

    // Processar baseado no tipo de movimento
    if (payload.movementType === 'CREDIT') {
      // PIX recebido
      handlePixReceived(payload);
    } else if (payload.movementType === 'DEBIT') {
      // PIX enviado ou estorno
      if (payload.status === 'REFUND_IN') {
        handlePixRefundReceived(payload);
      } else {
        handlePixSent(payload);
      }
    }

    res.status(200).send('OK');
  } catch (error) {
    console.error('Webhook PIX error:', error);
    res.status(500).send('Internal Server Error');
  }
});

function handlePixReceived(payload) {
  // PIX In - pagamento recebido
  updatePaymentStatus(payload.businessTransactionId, 'paid');
  fulfillOrder(payload.businessTransactionId);
  notifyPaymentReceived(payload);
}

function handlePixSent(payload) {
  // PIX Out - transferência enviada
  updateTransferStatus(payload.businessTransactionId, 'completed');
  notifyTransferCompleted(payload);
}

function handlePixRefundReceived(payload) {
  // Estorno recebido
  processRefund(payload.businessTransactionId, payload.value);
  notifyRefundReceived(payload);
}

Interface de Pagamento PIX

Componente React Exemplo

import React, { useState, useEffect } from 'react';

const PixPayment = ({ amount, description, onSuccess, onError }) => {
  const [pixData, setPixData] = useState(null);
  const [status, setStatus] = useState('loading');
  const [timeLeft, setTimeLeft] = useState(0);

  useEffect(() => {
    createPixCharge();
  }, []);

  const createPixCharge = async () => {
    try {
      const response = await createPixCharge({
        amount,
        description,
        orderId: generateOrderId()
      });

      setPixData(response);
      setStatus('waiting');
      startCountdown(response.expiresAt);
      monitorPayment(response.transactionId);
    } catch (error) {
      setStatus('error');
      onError(error);
    }
  };

  const startCountdown = (expiresAt) => {
    const interval = setInterval(() => {
      const now = new Date().getTime();
      const expiry = new Date(expiresAt).getTime();
      const timeLeft = Math.max(0, expiry - now);

      setTimeLeft(timeLeft);

      if (timeLeft === 0) {
        clearInterval(interval);
        setStatus('expired');
      }
    }, 1000);
  };

  const monitorPayment = (transactionId) => {
    const interval = setInterval(async () => {
      try {
        const payment = await checkPaymentStatus(transactionId);

        if (payment.status === 'PAID') {
          clearInterval(interval);
          setStatus('paid');
          onSuccess(payment);
        }
      } catch (error) {
        console.error('Error monitoring payment:', error);
      }
    }, 3000);
  };

  const copyPixCode = () => {
    navigator.clipboard.writeText(pixData.qrCode);
    // Mostrar feedback de cópia
  };

  const formatTime = (ms) => {
    const minutes = Math.floor(ms / 60000);
    const seconds = Math.floor((ms % 60000) / 1000);
    return `${minutes}:${seconds.toString().padStart(2, '0')}`;
  };

  if (status === 'loading') {
    return <div>Gerando PIX...</div>;
  }

  if (status === 'waiting') {
    return (
      <div className="pix-payment">
        <div className="qr-section">
          <img src={pixData.qrCodeImage} alt="QR Code PIX" />
          <p>Escaneie com seu app bancário</p>
        </div>

        <div className="copy-section">
          <input value={pixData.qrCode} readOnly />
          <button onClick={copyPixCode}>Copiar código PIX</button>
        </div>

        <div className="info">
          <p>Valor: R$ {amount.toFixed(2)}</p>
          <p>Expira em: {formatTime(timeLeft)}</p>
        </div>
      </div>
    );
  }

  if (status === 'paid') {
    return <div className="success">Pagamento confirmado!</div>;
  }

  if (status === 'expired') {
    return (
      <div className="expired">
        <p>PIX expirou</p>
        <button onClick={createPixCharge}>Gerar novo PIX</button>
      </div>
    );
  }

  return <div className="error">Erro ao gerar PIX</div>;
};

Monitoramento e Analytics

Monitore métricas importantes do PIX:
  • 📊 Taxa de conversão: QR Codes pagos vs gerados
  • ⏱️ Tempo médio de pagamento: Do QR Code ao pagamento
  • 💰 Volume transacionado: Por período
  • 🔄 Taxa de expiração: PIX não pagos
  • 📱 Canal preferido: QR Code vs Copia e Cola

Próximos Passos