Integrando Pagamentos Cripto em Node.js: Guia Completo
Aprenda a integrar pagamentos em USDT na sua aplicação Node.js em menos de 10 minutos. TypeScript, webhooks e exemplos práticos.
Equipe Tech Infi Pulse
Autor
Se você é developer e quer começar a aceitar pagamentos em cripto sem mergulhar no complexo mundo das blockchains, este guia é para você.
Por que aceitar pagamentos em cripto?
3 razões técnicas:
- Settlement instantâneo: Sem esperar 30 dias do Stripe
- Taxas previsíveis: 3.2% fixo vs 5-10% cartão internacional
- Global por padrão: Clientes do mundo todo sem burocracia
Setup Inicial (< 2 minutos)
1. Instalar SDK
npm install @infi/sdk
# ou
yarn add @infi/sdk
2. Configurar chaves de API
import { Pulse } from '@infi/sdk'
const pulse = new Pulse({
apiKey: process.env.PULSE_API_KEY, // test_xxx ou live_xxx
environment: 'test' // 'test' ou 'production'
})
Pro tip: Use test_ keys em desenvolvimento. PIX simulados, zero custo.
Criando seu Primeiro Pagamento
Exemplo Básico
const payment = await pulse.payments.create({
amount: 100, // R$ 100
currency: 'BRL',
description: 'Consultoria técnica - 1h',
metadata: {
userId: '123',
serviceId: 'consulting-1h'
}
})
console.log(payment.paymentUrl) // Link de pagamento
console.log(payment.qrCode) // QR Code PIX
Output:
{
"id": "pay_abc123",
"amount": 100,
"currency": "BRL",
"status": "pending",
"paymentUrl": "https://pay.pulse.infinitum.com/pay_abc123",
"qrCode": "00020126580014br.gov.bcb.pix...",
"expiresAt": "2025-01-13T15:30:00Z"
}
Enviando para Cliente
// Opção 1: Redirecionar para página de pagamento
res.redirect(payment.paymentUrl)
// Opção 2: Exibir QR Code na sua UI
res.json({
qrCode: payment.qrCode,
amount: payment.amount
})
// Opção 3: Enviar por email/WhatsApp
await sendEmail({
to: customer.email,
subject: 'Link de Pagamento',
body: `Pague aqui: ${payment.paymentUrl}`
})
Webhooks: Recebendo Confirmações
1. Configurar Endpoint
import express from 'express'
import crypto from 'crypto'
const app = express()
app.post('/webhooks/pulse', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['pulse-signature']
const payload = req.body
// Validar assinatura HMAC
const expectedSignature = crypto
.createHmac('sha256', process.env.PULSE_WEBHOOK_SECRET)
.update(payload)
.digest('hex')
if (signature !== expectedSignature) {
return res.status(401).send('Invalid signature')
}
const event = JSON.parse(payload)
// Processar evento
handleWebhook(event)
res.status(200).send('OK')
})
2. Processar Eventos
async function handleWebhook(event) {
switch (event.type) {
case 'payment.created':
console.log('Pagamento criado:', event.data.id)
break
case 'payment.processing':
// PIX recebido, aguardando conversão
await updateOrderStatus(event.data.metadata.orderId, 'processing')
break
case 'payment.completed':
// USDT depositado na wallet
await updateOrderStatus(event.data.metadata.orderId, 'paid')
await fulfillOrder(event.data.metadata.orderId)
await sendConfirmationEmail(event.data.metadata.userId)
break
case 'payment.failed':
await handleFailedPayment(event.data.id, event.data.failureReason)
break
}
}
3. Registrar Webhook no Dashboard
# Via dashboard: Settings > Webhooks > Add Endpoint
URL: https://seu-app.com/webhooks/pulse
Events: payment.created, payment.processing, payment.completed, payment.failed
Casos de Uso Avançados
Pagamentos Recorrentes (Assinaturas)
// Criar pagamento mensal
async function chargeSubscription(userId: string) {
const user = await db.users.findById(userId)
const payment = await pulse.payments.create({
amount: 99.90,
currency: 'BRL',
description: `Assinatura Pro - ${new Date().toLocaleDateString('pt-BR', {month: 'long'})}`,
metadata: {
userId,
subscriptionId: user.subscriptionId,
type: 'recurring'
}
})
// Enviar link por email
await sendEmail({
to: user.email,
subject: 'Renovação da Assinatura Pro',
template: 'subscription-renewal',
data: { paymentUrl: payment.paymentUrl }
})
}
// Agendar com cron
import cron from 'node-cron'
// Todo dia 1 às 9h
cron.schedule('0 9 1 * *', async () => {
const activeSubscriptions = await db.subscriptions.findActive()
for (const sub of activeSubscriptions) {
await chargeSubscription(sub.userId)
}
})
E-commerce Integration
import Stripe from 'stripe' // Comparação
// Antes (Stripe)
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [{ price: 'price_xxx', quantity: 1 }],
mode: 'payment',
success_url: 'https://...',
cancel_url: 'https://...'
})
// Agora (Pulse)
const payment = await pulse.payments.create({
amount: 299.90,
currency: 'BRL',
description: 'Curso Full Stack Development',
metadata: {
productId: 'course-fullstack',
customerId: user.id
},
successUrl: 'https://seu-site.com/success',
cancelUrl: 'https://seu-site.com/cart'
})
// Bonus: Cliente paga em BRL via PIX, você recebe em USDT
// = proteção automática contra inflação
Multi-tenant SaaS
// Cada tenant tem sua própria conta Pulse
class PaymentService {
private pulseClients = new Map()
getPulseClient(tenantId: string) {
if (!this.pulseClients.has(tenantId)) {
const tenant = await db.tenants.findById(tenantId)
this.pulseClients.set(tenantId, new Pulse({
apiKey: tenant.pulseApiKey,
environment: 'production'
}))
}
return this.pulseClients.get(tenantId)
}
async createPayment(tenantId: string, data: PaymentData) {
const pulse = this.getPulseClient(tenantId)
return await pulse.payments.create(data)
}
}
Idempotência: Evitando Cobranças Duplicadas
import { v4 as uuidv4 } from 'uuid'
const payment = await pulse.payments.create({
amount: 100,
currency: 'BRL',
description: 'Order #12345'
}, {
idempotencyKey: `order-12345-${Date.now()}` // Chave única
})
// Se requisição falhar e você retentar, não cria pagamento duplicado
Error Handling
try {
const payment = await pulse.payments.create({ ... })
} catch (error) {
if (error.type === 'invalid_request_error') {
// Dados inválidos
console.error('Erro nos dados:', error.message)
} else if (error.type === 'api_error') {
// Erro interno da API
console.error('Erro da API:', error.message)
// Retry com backoff exponencial
} else if (error.type === 'rate_limit_error') {
// Limite de rate ultrapassado
console.error('Rate limit atingido')
// Aguardar antes de retentar
}
}
Rate Limits
100 requisições/segundo por API key
Sem limite de pagamentos/mês
Tip: Use diferentes API keys para diferentes serviços se precisar de mais throughput.
Testando Localmente
1. Usar Sandbox
const pulse = new Pulse({
apiKey: process.env.PULSE_TEST_KEY, // test_xxx
environment: 'test'
})
2. Simular PIX no Dashboard
1. Vá para Dashboard > Sandbox
2. Copie o payment.id
3. Clique "Simulate PIX Payment"
4. Webhook é disparado automaticamente
3. Testar Webhooks Localmente com ngrok
# Terminal 1
npm run dev
# Terminal 2
ngrok http 3000
# Dashboard > Webhooks
# URL: https://abc123.ngrok.io/webhooks/pulse
Monitoramento e Logs
import { logger } from './logger'
pulse.on('request', (req) => {
logger.info('Pulse API Request', {
method: req.method,
url: req.url,
duration: req.duration
})
})
pulse.on('response', (res) => {
if (res.statusCode >= 400) {
logger.error('Pulse API Error', {
statusCode: res.statusCode,
body: res.body
})
}
})
TypeScript: Tipos Completos
import { Pulse, Payment, PaymentCreateParams, WebhookEvent } from '@infi/sdk'
const createPayment = async (
params: PaymentCreateParams
): Promise<Payment> => {
const payment = await pulse.payments.create(params)
return payment
}
// Autocomplete completo no VS Code
payment.amount // number
payment.status // 'pending' | 'processing' | 'completed' | 'failed'
payment.metadata // { [key: string]: string }
Próximos Passos
Agora que você sabe o básico:
- Leia a doc completa: docs.pulse.infinitum.com
- Explore SDKs: Python, Go, PHP disponíveis
- Teste no sandbox: 100% grátis, dados fake
- Deploy e aceite seu primeiro pagamento
Comparação: Stripe vs Pulse
| Feature | Stripe | Pulse | |---------|--------|-------| | Setup | 15-30 min | < 10 min | | Taxa | 4.99% + R$ 0.99 | 3.2% + R$ 0.99 | | Settlement | 30 dias | 2-5 minutos | | Moeda recebida | BRL (inflação) | USDT (dólar) | | PIX nativo | ❌ | ✅ | | Global | ✅ | ✅ | | Webhooks | ✅ | ✅ | | SDKs oficiais | ✅ | ✅ |
TL;DR
// 1. Instalar
npm install @infi/sdk
// 2. Criar pagamento
const payment = await pulse.payments.create({
amount: 100,
currency: 'BRL',
description: 'Meu produto'
})
// 3. Enviar link
res.json({ paymentUrl: payment.paymentUrl })
// 4. Receber webhook
app.post('/webhooks/pulse', (req, res) => {
if (event.type === 'payment.completed') {
fulfillOrder(event.data.metadata.orderId)
}
})
// 5. Profit em USDT 🚀
Dúvidas? Entre no nosso Discord: discord.gg/pulse-dev
Código completo: github.com/pulse/examples/nodejs