Node.js TypeScript API Tutorial Webhooks
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.
E
Equipe Tech Infi Pulse · · 7 min de leitura 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 @beinfi/pulse-sdk
# ou
yarn add @beinfi/pulse-sdk
2. Configurar chaves de API
import { Pulse } from '@beinfi/pulse-sdk'
const pulse = new Pulse(process.env.PULSE_API_KEY!) // sk_live_xxx ou sk_test_xxx
Pro tip: Use sk_test_ keys em desenvolvimento. PIX simulados, zero custo.
Criando seu Primeiro Pagamento
Exemplo Básico
const payment = await pulse.paymentLinks.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['x-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.paymentLinks.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.paymentLinks.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(tenant.pulseApiKey))
}
return this.pulseClients.get(tenantId)
}
async createPayment(tenantId: string, data: PaymentData) {
const pulse = this.getPulseClient(tenantId)
return await pulse.paymentLinks.create(data)
}
}
Idempotência: Evitando Cobranças Duplicadas
import { v4 as uuidv4 } from 'uuid'
const payment = await pulse.paymentLinks.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
import {
PulseApiError,
PulseAuthenticationError,
PulseRateLimitError,
} from '@beinfi/pulse-sdk'
try {
const link = await pulse.paymentLinks.create({ title: 'Test', amount: '100.00' })
} catch (error) {
if (error instanceof PulseAuthenticationError) {
// 401 — API key inválida ou expirada
console.error('Erro de autenticação:', error.message)
} else if (error instanceof PulseRateLimitError) {
// 429 — limite de rate ultrapassado
console.log(`Rate limit. Retry em ${error.retryAfter} segundos`)
await new Promise((r) => setTimeout(r, error.retryAfter * 1000))
} else if (error instanceof PulseApiError) {
// Outros erros da API (400, 404, 500, etc.)
console.error(`Erro ${error.status}: [${error.errorCode}] ${error.message}`)
}
}
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(process.env.PULSE_TEST_KEY!) // sk_test_xxx
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 { Pulse, PulseApiError } from '@beinfi/pulse-sdk'
import { logger } from './logger'
const pulse = new Pulse(process.env.PULSE_API_KEY!)
// Wrap chamadas com logging
async function createPaymentLink(params: CreatePaymentLinkParams) {
const start = Date.now()
try {
const link = await pulse.paymentLinks.create(params)
logger.info('Pulse API Request', {
method: 'POST',
resource: 'paymentLinks.create',
duration: Date.now() - start,
})
return link
} catch (error) {
if (error instanceof PulseApiError) {
logger.error('Pulse API Error', {
status: error.status,
errorCode: error.errorCode,
message: error.message,
duration: Date.now() - start,
})
}
throw error
}
}
TypeScript: Tipos Completos
import { Pulse, type CreatePaymentLinkParams, type PaymentLink } from '@beinfi/pulse-sdk'
const createLink = async (
params: CreatePaymentLinkParams
): Promise<PaymentLink> => {
const link = await pulse.paymentLinks.create(params)
return link
}
// Autocomplete completo no VS Code
link.amount // string (decimal)
link.status // 'active' | 'inactive'
link.slug // URL-friendly slug
link.currency // 'USD' | 'BRL'
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 @beinfi/pulse-sdk
// 2. Criar pagamento
const payment = await pulse.paymentLinks.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 🚀
lang: “pt-BR”
Dúvidas? Entre no nosso Discord: discord.gg/pulse-dev
Código completo: github.com/pulse/examples/nodejs
Pronto para transformar seus dados?
A infi ajuda você a tomar decisões mais inteligentes com dados em tempo real.
Começar grátis