Node.jsTypeScriptAPITutorialWebhooks

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

13 de janeiro de 2025
6 min read
Integrando Pagamentos Cripto em Node.js: Guia Completo

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:

  1. Settlement instantâneo: Sem esperar 30 dias do Stripe
  2. Taxas previsíveis: 3.2% fixo vs 5-10% cartão internacional
  3. 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:

  1. Leia a doc completa: docs.pulse.infinitum.com
  2. Explore SDKs: Python, Go, PHP disponíveis
  3. Teste no sandbox: 100% grátis, dados fake
  4. 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