Integrar pagamentos e uma das tarefas mais criticas no desenvolvimento de aplicacoes. Neste guia pratico, voce aprende a criar um gateway de pagamento com Node.js que suporta cartao de credito (via Stripe), PIX e boleto (via Mercado Pago). Cobrimos desde a arquitetura ate o deploy seguro.
Arquitetura do gateway
Um gateway de pagamento bem estruturado tem estas camadas: API REST (Express.js) que recebe requisicoes do frontend, camada de servico que abstrai a logica de cada provedor, adaptadores para cada provedor de pagamento (Stripe, Mercado Pago), banco de dados para registrar transacoes e status, fila de webhooks para processar confirmacoes de forma assincrona.
A abstracao e fundamental: o frontend nao precisa saber qual provedor esta sendo usado. Ele envia o metodo de pagamento desejado e a API escolhe o provedor correto.
Setup do projeto
mkdir gateway-pagamento && cd gateway-pagamento
npm init -y
npm install express stripe mercadopago dotenv helmet cors
npm install -D typescript @types/express @types/node
Estrutura de pastas: src/routes/ (rotas da API), src/services/ (logica de negocio), src/adapters/ (integracao com provedores), src/models/ (modelos de dados), src/webhooks/ (processamento de webhooks).
Adaptador Stripe (cartao de credito internacional)
Stripe e o padrao global para pagamentos com cartao. O fluxo: frontend coleta dados do cartao via Stripe Elements (nunca toca seus servidores), cria um PaymentIntent no backend, confirma o pagamento no frontend, webhook confirma a transacao.
// src/adapters/stripe.adapter.js
const Stripe = require(“stripe”);
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
async function criarPagamentoCartao(valor, moeda, descricao, metadata) {
const paymentIntent = await stripe.paymentIntents.create({
amount: Math.round(valor * 100), // Stripe usa centavos
currency: moeda,
description: descricao,
metadata: metadata,
automatic_payment_methods: { enabled: true },
});
return {
id: paymentIntent.id,
client_secret: paymentIntent.client_secret,
status: paymentIntent.status,
};
}
Adaptador Mercado Pago (PIX e boleto)
Para pagamentos brasileiros, Mercado Pago oferece PIX, boleto, cartao de credito nacional e Mercado Credito:
// src/adapters/mercadopago.adapter.js
const mercadopago = require(“mercadopago”);
mercadopago.configurations.setAccessToken(process.env.MP_ACCESS_TOKEN);
async function criarPagamentoPIX(valor, descricao, emailPagador) {
const pagamento = await mercadopago.payment.create({
transaction_amount: valor,
description: descricao,
payment_method_id: “pix”,
payer: { email: emailPagador },
});
return {
id: pagamento.body.id,
qr_code: pagamento.body.point_of_interaction.transaction_data.qr_code,
qr_code_base64: pagamento.body.point_of_interaction.transaction_data.qr_code_base64,
status: pagamento.body.status,
};
}
async function criarPagamentoBoleto(valor, descricao, pagador) {
const pagamento = await mercadopago.payment.create({
transaction_amount: valor,
description: descricao,
payment_method_id: “bolbradesco”,
payer: {
email: pagador.email,
first_name: pagador.nome,
last_name: pagador.sobrenome,
identification: { type: “CPF”, number: pagador.cpf },
},
});
return {
id: pagamento.body.id,
boleto_url: pagamento.body.transaction_details.external_resource_url,
barcode: pagamento.body.barcode.content,
status: pagamento.body.status,
};
}
Rota unificada de pagamento
// src/routes/payment.routes.js
const express = require(“express”);
const router = express.Router();
const stripeAdapter = require(“../adapters/stripe.adapter”);
const mpAdapter = require(“../adapters/mercadopago.adapter”);
router.post(“/criar”, async (req, res) => {
const { metodo, valor, descricao, pagador } = req.body;
try {
let resultado;
switch (metodo) {
case “cartao_internacional”:
resultado = await stripeAdapter.criarPagamentoCartao(valor, “brl”, descricao, { email: pagador.email });
break;
case “pix”:
resultado = await mpAdapter.criarPagamentoPIX(valor, descricao, pagador.email);
break;
case “boleto”:
resultado = await mpAdapter.criarPagamentoBoleto(valor, descricao, pagador);
break;
default:
return res.status(400).json({ erro: “Metodo de pagamento invalido” });
}
// Salvar transacao no banco
await salvarTransacao({ metodo, valor, resultado, pagador });
res.json({ sucesso: true, dados: resultado });
} catch (erro) {
console.error(“Erro no pagamento:”, erro);
res.status(500).json({ erro: “Falha ao processar pagamento” });
}
});
Processamento de webhooks
Webhooks sao a unica forma confiavel de saber o status final de um pagamento. Nunca confie apenas no retorno da criacao — o pagamento pode levar segundos (PIX), minutos (cartao com 3DS) ou dias (boleto).
Boas praticas: use uma fila (Redis/SQS) para processar webhooks de forma assincrona, implemente idempotencia (use o ID do pagamento como chave), retorne 200 imediatamente e processe em background, armazene o payload do webhook para debugging.
Seguranca obrigatoria
PCI DSS: nunca receba dados de cartao no seu servidor. Use Stripe Elements ou iframes do provedor. HTTPS obrigatorio em todos os endpoints. Rate limiting para prevenir abuso. Validacao rigorosa de todos os inputs. Segredos em variaveis de ambiente, nunca no codigo. Logs de auditoria para todas as transacoes.
Tem um projeto em mente?
Somos especialistas em transformar ideias em produtos digitais. Apps, sites, automações e IA — vamos construir juntos.