API de pagamentos: como integrar PIX, cartão e boleto no seu sistema
Visão prática de uma integração com API REST: autenticação JWT, idempotência, paginação, sandbox e exemplos prontos em cURL, Node e PHP.
Integrar pagamentos via API parece intimidador na primeira leitura — autenticação, idempotência, webhooks, sandbox, retries, paginação. Mas, na prática, uma integração bem feita cabe em menos de 200 linhas de código e leva 1 a 2 dias de trabalho. O segredo está em começar pelos conceitos certos, não pelo código.
Neste guia vamos cobrir os fundamentos de uma API REST de pagamentos moderna usando como referência a API ApexPy v1, com exemplos prontos em cURL, Node.js e PHP. Você pode aplicar os mesmos princípios em qualquer gateway compatível com REST.
O que sua API precisa fazer
Antes de qualquer linha de código, mapeie os 4 casos de uso mínimos:
- Criar uma cobrança (PIX, cartão ou boleto);
- Consultar status de uma cobrança;
- Receber webhook de eventos (pagamento confirmado, recusado, estornado);
- Listar transações para conciliar com seu sistema.
Tudo o mais (split, payout, recurrence) vem depois. Comece pelos quatro.
Autenticação: JWT Bearer Token
APIs sérias usam Authorization: Bearer <token> em todas as requisições. Você gera o token uma vez no painel do gateway e guarda em variável de ambiente — nunca no código.
curl https://api.apexpy.com.br/v1/charges \
-H "Authorization: Bearer $APEXPY_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "amount": 24790, "payment_method": "pix" }'
Toda chamada à API deve ser feita do seu servidor, nunca do JavaScript no browser. Se o token vazar, qualquer pessoa pode criar cobranças e mexer nos saques em sua conta.
Criando uma cobrança PIX
O exemplo mínimo em três linguagens:
cURL
curl https://api.apexpy.com.br/v1/charges \
-H "Authorization: Bearer $APEXPY_TOKEN" \
-H "Idempotency-Key: order_91a8f2" \
-H "Content-Type: application/json" \
-d '{
"amount": 24790,
"currency": "BRL",
"payment_method": "pix",
"customer": {
"name": "Maria Silva",
"email": "[email protected]",
"document": "12345678909"
},
"pix": { "expires_in_minutes": 30 },
"webhook_url": "https://sualoja.com/webhook"
}'
Node.js
import Apexpy from '@apexpy/sdk';
const apx = new Apexpy(process.env.APEXPY_TOKEN);
const charge = await apx.charges.create({
amount: 24790,
currency: 'BRL',
payment_method: 'pix',
customer: { name: 'Maria Silva', email: '[email protected]', document: '12345678909' },
pix: { expires_in_minutes: 30 },
webhook_url: 'https://sualoja.com/webhook',
}, { idempotencyKey: 'order_91a8f2' });
console.log(charge.pix.qr_code);
PHP
$apx = new Apexpy\Client(getenv('APEXPY_TOKEN'));
$charge = $apx->charges->create([
'amount' => 24790,
'currency' => 'BRL',
'payment_method' => 'pix',
'customer' => ['name' => 'Maria Silva', 'email' => '[email protected]', 'document' => '12345678909'],
'pix' => ['expires_in_minutes' => 30],
'webhook_url' => 'https://sualoja.com/webhook',
], ['idempotency_key' => 'order_91a8f2']);
O retorno traz charge.pix.qr_code (imagem base64) e charge.pix.qr_code_text (PIX Copia e Cola). Exibe no seu checkout e está pronto.
Idempotência: a feature que te salva
Imagine: cliente clica em "Pagar", a request demora 6 segundos, ele clica de novo. Você criou 2 cobranças para o mesmo pedido — desastre.
O header Idempotency-Key resolve isso. Você gera um identificador único (seu número de pedido, por exemplo) e envia em todas as tentativas. A API garante que apenas uma cobrança será criada — as tentativas seguintes retornam o mesmo objeto.
// Mesma chave, mesmo resultado, mesmo objeto
const charge1 = await apx.charges.create({...}, { idempotencyKey: 'order_91a8f2' });
const charge2 = await apx.charges.create({...}, { idempotencyKey: 'order_91a8f2' });
// charge1.id === charge2.id
Use sempre. É a defesa mais barata contra duplicidade.
Webhooks: o coração da automação
Em vez de ficar fazendo polling ("já pagou? já pagou? já pagou?"), o gateway dispara um POST na sua URL quando o status muda. Implementação mínima em Express:
app.post('/webhook/apexpy', (req, res) => {
const event = req.body;
switch (event.event) {
case 'charge.paid':
liberarAcesso(event.data.id);
enviarEmail(event.data.customer.email, 'Pagamento confirmado!');
break;
case 'charge.failed':
notificarFalha(event.data.id);
break;
case 'charge.refunded':
reverterPedido(event.data.id);
break;
}
res.status(200).send('ok');
});
Sempre responda 200 OK rapidamente (em menos de 5 segundos). Coloque o processamento pesado em fila — webhooks que demoram muito são re-disparados, gerando duplicação no seu sistema.
Verificação de assinatura HMAC
Como saber que o webhook é mesmo do gateway e não de alguém tentando fraudar? Toda requisição vem com um header X-Apexpy-Signature contendo um HMAC-SHA256 do corpo, assinado com seu segredo:
const crypto = require('crypto');
const SECRET = process.env.APEXPY_WEBHOOK_SECRET;
function verifySignature(req) {
const signature = req.headers['x-apexpy-signature'];
const expected = crypto
.createHmac('sha256', SECRET)
.update(JSON.stringify(req.body))
.digest('hex');
return signature === `sha256=${expected}`;
}
app.post('/webhook/apexpy', (req, res) => {
if (!verifySignature(req)) return res.status(401).send('invalid');
// processa...
});
Sem isso, qualquer um que descubra sua URL pode disparar "pagamento confirmado" falso. Não negocie esse passo.
Sandbox primeiro, produção depois
Toda API séria tem ambiente de teste isolado. Na ApexPy, basta usar tokens prefixados com sk_test_ em vez de sk_live_ — o resto da API é idêntico. No sandbox você pode simular:
- Pagamento aprovado instantâneo (PIX com
amountterminando em00); - Pagamento recusado (terminando em
01); - Demora de aprovação (terminando em
99); - Webhook de chargeback;
- Estorno parcial.
Faça todo o desenvolvimento no sandbox. Só quando a integração estiver 100% você troca o token para produção.
Paginação correta
Para listar transações, NUNCA peça "todas". Use cursor-based pagination:
GET /v1/transactions?limit=100&starting_after=tx_abc123
// Resposta:
{
"data": [...100 itens...],
"has_more": true,
"next_cursor": "tx_xyz789"
}
É mais eficiente que offset/page (que fica lento quando o dataset cresce) e mais estável (não pula registros se novas entradas chegam durante a iteração).
Rate limiting: respeite a API
Toda API tem limite de requests por segundo. Na ApexPy é 5.000 RPS por chave. Se você ultrapassar, recebe um 429 Too Many Requests com o header Retry-After.
Sua implementação precisa de backoff exponencial: 1s, 2s, 4s, 8s, 16s. Bibliotecas como axios-retry em Node já fazem isso por padrão.
Tratamento de erros
Erros chegam em formato consistente:
{
"error": {
"type": "invalid_request_error",
"code": "missing_field",
"message": "O campo 'customer.email' é obrigatório.",
"field": "customer.email"
}
}
Sempre logue type + code + message e nunca exiba a message bruta para o cliente final. Mapeie códigos comuns para mensagens humanas no seu sistema.
Comece a integrar agora
Acesse a documentação completa, gere seu token de sandbox e teste uma cobrança em 5 minutos.
Checklist de integração production-ready
- Token guardado em variável de ambiente (nunca commit);
- Idempotency-Key em todas as criações de cobrança;
- Webhook com verificação de assinatura HMAC;
- Webhook respondendo em <5s (processamento em fila se for pesado);
- Retry com backoff exponencial em erros 5xx e 429;
- Logs estruturados com
charge_idem todas as operações; - Sandbox testado para todos os fluxos antes de subir para produção;
- Alertas para taxa de erro acima de 1% em qualquer endpoint;
- Conciliação diária comparando seu banco de pedidos com o relatório do gateway;
- Documentação interna do que cada evento de webhook dispara.
Conclusão
Uma API REST bem desenhada é prazerosa de usar. Você cria uma cobrança em uma chamada, recebe webhook em segundos, e seu sistema fica reativo sem precisar fazer polling.
Os 10 itens do checklist acima cobrem 95% do que você precisa para uma integração robusta. Os 5% restantes são features avançadas (split, recurrence, payout) que você pode adicionar depois, quando precisar.
O melhor jeito de aprender é colocando a mão. Crie sua conta na ApexPy, pegue o token de sandbox e faça sua primeira cobrança ainda hoje.
Última atualização: 18 de maio de 2026