Skip to main content

Visão Geral

Os eventos de webhook de transações permitem que você receba notificações em tempo real quando transações são criadas ou atualizadas em sua organização. Gu1 envia automaticamente solicitações HTTP POST para seu endpoint de webhook configurado, permitindo que você automatize fluxos de trabalho de monitoramento de transações, detecção de fraude e conformidade regulatória.

Por Que Usar Webhooks de Transações?

Monitoramento em Tempo Real

Receba notificações instantâneas sobre transações novas ou atualizadas

Detecção de Fraude

Implemente verificações de segurança adicionais em tempo real

Automação de Workflows

Acione processos automáticos baseados em atividade transacional

Auditoria e Conformidade

Mantenha registros de auditoria sincronizados em todos os seus sistemas

Eventos Disponíveis

Gu1 envia webhooks para os seguintes eventos de transações:
Tipo de EventoDescriçãoQuando Acionado
transaction.createdTransação criadaQuando uma nova transação é registrada no sistema
transaction.updatedTransação atualizadaQuando o status ou informações de uma transação são atualizados
Os eventos transaction.created e transaction.updated estão atualmente em desenvolvimento e serão ativados em breve. A documentação está disponível para preparar sua integração.

Estrutura do Payload do Evento

Todos os eventos de webhook de transações seguem esta estrutura padrão:
{
  "event": "transaction.created",
  "timestamp": "2025-01-29T15:30:00Z",
  "organizationId": "org-123",
  "payload": {
    "transactionId": "550e8400-e29b-41d4-a716-446655440000",
    "externalId": "txn_abc123",
    "type": "payment",
    "status": "CREATED",
    "amount": 5000.00,
    "currency": "USD"
    // ... campos específicos do evento
  }
}

Campos Comuns do Payload

event
string
O tipo de evento (por exemplo, transaction.created)
timestamp
string
Timestamp ISO 8601 quando o evento ocorreu
organizationId
string
Seu ID de organização
payload.transactionId
string
O ID UUID da transação no Gu1
payload.externalId
string
Seu ID externo para a transação
payload.type
string
Tipo de transação: payment, transfer, withdrawal, etc.
payload.status
string
Status atual da transação: CREATED, PROCESSING, SUSPENDED, SENT, SUCCESSFUL, DECLINED, REFUNDED, EXPIRED
payload.amount
number
Valor da transação na moeda original
payload.currency
string
Código de moeda ISO 4217 (por exemplo, USD, EUR, BRL)

Payloads Específicos de Eventos

transaction.created

Enviado quando uma nova transação é registrada no sistema.
{
  "event": "transaction.created",
  "timestamp": "2025-01-29T15:30:00Z",
  "organizationId": "org-123",
  "payload": {
    "transactionId": "550e8400-e29b-41d4-a716-446655440000",
    "externalId": "txn_abc123",
    "type": "payment",
    "status": "CREATED",
    "amount": 5000.00,
    "currency": "USD",
    "amountInUsd": 5000.00,
    "origin": {
      "entityId": "123e4567-e89b-12d3-a456-426614174001",
      "externalId": "customer_john",
      "name": "John Doe",
      "country": "US"
    },
    "destination": {
      "entityId": "123e4567-e89b-12d3-a456-426614174002",
      "externalId": "merchant_acme",
      "name": "ACME Corp",
      "country": "US"
    },
    "transactedAt": "2025-01-29T15:30:00Z",
    "createdAt": "2025-01-29T15:30:00Z"
  }
}
Caso de uso: Acione verificações de fraude adicionais, atualize saldos de conta em tempo real, ou inicie processos de conformidade.

transaction.updated

Enviado quando uma transação existente é atualizada (por exemplo, mudança de status).
{
  "event": "transaction.updated",
  "timestamp": "2025-01-29T15:35:00Z",
  "organizationId": "org-123",
  "payload": {
    "transactionId": "550e8400-e29b-41d4-a716-446655440000",
    "externalId": "txn_abc123",
    "type": "payment",
    "status": "SUCCESSFUL",
    "amount": 5000.00,
    "currency": "USD",
    "amountInUsd": 5000.00,
    "origin": {
      "entityId": "123e4567-e89b-12d3-a456-426614174001",
      "externalId": "customer_john",
      "name": "John Doe",
      "country": "US"
    },
    "destination": {
      "entityId": "123e4567-e89b-12d3-a456-426614174002",
      "externalId": "merchant_acme",
      "name": "ACME Corp",
      "country": "US"
    },
    "previousStatus": "PROCESSING",
    "newStatus": "SUCCESSFUL",
    "updatedAt": "2025-01-29T15:35:00Z"
  }
}
Caso de uso: Notifique clientes sobre o status de sua transação, atualize dashboards em tempo real, ou acione fluxos de trabalho pós-transação.

Exemplos de Código

Node.js - Lidando com Eventos de Transações

const express = require('express');
const crypto = require('crypto');

const app = express();

app.use(express.json({
  verify: (req, res, buf) => {
    req.rawBody = buf.toString('utf8');
  }
}));

app.post('/webhooks/transactions', async (req, res) => {
  try {
    // Verificar assinatura de webhook (veja guia de segurança)
    const signature = req.headers['x-webhook-signature'];
    const webhookSecret = process.env.GU1_WEBHOOK_SECRET;

    if (!verifySignature(req.rawBody, signature, webhookSecret)) {
      console.error('Invalid webhook signature');
      return res.status(401).json({ error: 'Invalid signature' });
    }

    // Extrair dados do webhook
    const { event, timestamp, organizationId, payload } = req.body;

    console.log('Received transaction webhook:', {
      event,
      transactionId: payload.transactionId,
      status: payload.status
    });

    // Processar o webhook baseado no tipo de evento
    await handleTransactionWebhook(event, payload);

    // Retornar 200 para confirmar recebimento
    res.status(200).json({
      success: true,
      message: 'Webhook received'
    });
  } catch (error) {
    console.error('Webhook error:', error);
    res.status(500).json({
      error: error.message
    });
  }
});

async function handleTransactionWebhook(event, data) {
  const { transactionId, externalId, status, amount, currency } = data;

  // Atualizar seu banco de dados com a transação do Gu1
  await db.updateTransaction(externalId, {
    gu1TransactionId: transactionId,
    status: status,
    lastUpdated: new Date()
  });

  // Realizar ações baseadas no tipo de evento
  switch (event) {
    case 'transaction.created':
      console.log('New transaction created:', externalId);

      // Verificações de fraude adicionais
      if (amount > 10000) {
        await triggerHighValueReview(transactionId);
      }

      // Notificar cliente
      await notifyCustomer(data.origin.externalId, 'transaction-created', {
        amount,
        currency,
        recipient: data.destination.name
      });
      break;

    case 'transaction.updated':
      console.log('Transaction status changed:', {
        externalId,
        from: data.previousStatus,
        to: data.newStatus
      });

      // Atualizar status no seu sistema
      await db.updateTransaction(externalId, {
        status: data.newStatus,
        statusChangedAt: new Date()
      });

      // Notificar sobre transação completada
      if (data.newStatus === 'SUCCESSFUL') {
        await notifyCustomer(data.origin.externalId, 'transaction-completed', {
          amount,
          currency,
          recipient: data.destination.name
        });
      }

      // Lidar com transações recusadas
      if (data.newStatus === 'DECLINED') {
        await notifyCustomer(data.origin.externalId, 'transaction-declined', {
          amount,
          currency
        });
        await logDeclinedTransaction(transactionId, externalId);
      }
      break;
  }
}

function verifySignature(rawBody, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  return signature === expectedSignature;
}

app.listen(3000);

Python - Lidando com Eventos de Transações

from flask import Flask, request, jsonify
import hmac
import hashlib
from datetime import datetime

app = Flask(__name__)

@app.route('/webhooks/transactions', methods=['POST'])
def handle_transaction_webhook():
    try:
        # Verificar assinatura de webhook
        signature = request.headers.get('X-Webhook-Signature')
        webhook_secret = os.getenv('GU1_WEBHOOK_SECRET')

        if not verify_signature(request.data, signature, webhook_secret):
            return jsonify({'error': 'Invalid signature'}), 401

        # Processar webhook
        data = request.json
        event = data['event']
        payload = data['payload']

        print(f'Received transaction webhook: {event}')

        # Lidar com evento
        handle_transaction_event(event, payload)

        return jsonify({
            'success': True,
            'message': 'Webhook received'
        }), 200

    except Exception as e:
        print(f'Webhook error: {str(e)}')
        return jsonify({'error': str(e)}), 500

def handle_transaction_event(event, data):
    transaction_id = data['transactionId']
    external_id = data['externalId']

    # Atualizar banco de dados
    db.update_transaction(
        external_id=external_id,
        gu1_transaction_id=transaction_id,
        status=data['status'],
        last_updated=datetime.now()
    )

    # Lidar com diferentes eventos
    if event == 'transaction.created':
        # Verificações de fraude
        if data['amount'] > 10000:
            trigger_high_value_review(transaction_id)

        # Notificar cliente
        notify_customer(
            data['origin']['externalId'],
            'transaction-created',
            data
        )

    elif event == 'transaction.updated':
        # Registrar mudança de status
        log_status_change(
            external_id,
            data.get('previousStatus'),
            data['status']
        )

        # Notificar sobre completada
        if data['status'] == 'SUCCESSFUL':
            notify_customer(
                data['origin']['externalId'],
                'transaction-completed',
                data
            )

        # Lidar com recusadas
        elif data['status'] == 'DECLINED':
            notify_customer(
                data['origin']['externalId'],
                'transaction-declined',
                data
            )

def verify_signature(raw_body, signature, secret):
    expected = hmac.new(
        secret.encode('utf-8'),
        raw_body,
        hashlib.sha256
    ).hexdigest()
    return signature == expected

if __name__ == '__main__':
    app.run(port=3000)

Melhores Práticas

O webhook inclui externalId que é o ID que você forneceu ao criar a transação. Use-o para buscar a transação no seu banco de dados.
const transaction = await db.findTransaction({
  externalId: data.externalId
});
Salve o transactionId do Gu1 no seu banco de dados. Isso permite que você consulte detalhes da transação mais tarde se necessário.
await db.updateTransaction(transaction.id, {
  gu1TransactionId: data.transactionId,
  status: data.status
});
Você pode receber o mesmo webhook múltiplas vezes. Use o transactionId e o event para garantir que você processe cada evento apenas uma vez.
async function handleWebhook(webhook) {
  const alreadyProcessed = await db.checkWebhookProcessed(
    webhook.payload.transactionId,
    webhook.event
  );

  if (alreadyProcessed) {
    return; // Pular duplicado
  }

  // Processar webhook
  await processTransaction(webhook.payload);

  // Marcar como processado
  await db.markWebhookProcessed(
    webhook.payload.transactionId,
    webhook.event
  );
}
Sempre retorne um código de status 200 o mais rápido possível para confirmar o recebimento. Processe o webhook assincronamente se necessário.
app.post('/webhooks/transactions', async (req, res) => {
  // Confirmar imediatamente
  res.status(200).send('OK');

  // Processar assincronamente
  processWebhook(req.body).catch(console.error);
});
Sempre verifique o header X-Webhook-Signature para garantir que o webhook seja autêntico. Veja o guia de segurança para detalhes.
const signature = req.headers['x-webhook-signature'];
if (!verifySignature(req.rawBody, signature, secret)) {
  return res.status(401).json({ error: 'Invalid signature' });
}

Solução de Problemas

Verificar estes itens:
  • URL do webhook é publicamente acessível via HTTPS
  • Webhook está configurado e habilitado no dashboard
  • Inscrito nos tipos de eventos corretos
  • Endpoint retorna código de status 200 dentro de 30 segundos
  • Verificar logs do servidor para solicitações recebidas
  • Os eventos de transações estão atualmente em desenvolvimento - confirme que estão ativados para sua organização
Causas comuns:
  • Usar secret errado (verificar dashboard para secret atual)
  • Verificar assinatura em JSON analisado em vez de corpo raw
  • Secret não salvo corretamente após criação do webhook
  • Problemas de codificação (garantir UTF-8)
Veja o guia de segurança para implementação adequada.
Este é um comportamento normal. Webhooks podem ser enviados múltiplas vezes devido a problemas de rede, timeouts ou tentativas.Sempre implemente idempotência usando o transactionId e tipo de event do webhook.

Próximos Passos