Integração com Parceiros

Webhooks de Parceiros

Como configurar webhooks para parceiros via API

Webhooks de Parceiros

Os webhooks são notificações automáticas enviadas pela Nuvende para informar os parceiros sobre mudanças no status das solicitações de autorização. Este mecanismo permite que o parceiro seja notificado em tempo real sobre as decisões dos clientes.

Visão Geral

Os webhooks funcionam como um sistema de notificação push:

  1. Configuração: Parceiro define URL de webhook na solicitação
  2. Evento: Cliente aprova ou rejeita solicitação
  3. Notificação: Sistema envia POST para URL configurada
  4. Processamento: Parceiro processa a notificação

Tipos de Notificação

Solicitação Aprovada

Quando o cliente aprova uma solicitação, o webhook contém todas as informações necessárias para integração:

{
  "auth_request_id": "8e9a8f81-aa432-4608-b4a7-e223c3213231",
  "status": "approved",
  "scopes": [
    "cob.read",
    "cob.write",
    "pix.write"
  ],
  "client_id": "ffcfb2ed-d669-4e33-9c4d-e223c3213231",
  "client_secret": "nFNTATLHFp1hGAPZNU0JKJDGQFSCDAS",
  "account_id": "314eae12-19b7-4845-b115-e223c3213231",
  "account": "0000001",
  "account_vd": "1",
  "agency": "0001",
  "agency_vd": "9",
  "document": "04169999999",
  "dict_keys": [
    "22598a0a-b222-4329-8603-e223c3213231"
  ],
  "decision_at": "2025-01-15T14:01:39-03:00",
  "created_at": "2025-01-15T13:58:30-03:00",
  "updated_at": "2025-01-15T14:01:39-03:00"
}

Campos da Resposta de Aprovação

CampoTipoDescrição
auth_request_idstringID da solicitação de autorização
statusstringStatus da solicitação ("approved")
scopesarrayEscopos aprovados pelo cliente
client_idstringCredencial para integração
client_secretstringChave secreta para autenticação
account_idstringID da conta do cliente
accountstringNúmero da conta
account_vdstringDígito verificador da conta
agencystringNúmero da agência
agency_vdstringDígito verificador da agência
documentstringCPF/CNPJ do cliente
dict_keysarrayChaves de dicionário para Pix
decision_atstringData/hora da decisão
created_atstringData de criação da solicitação
updated_atstringData da última atualização

Solicitação Rejeitada

Quando o cliente rejeita uma solicitação:

{
  "auth_request_id": "4008bfa4-6373-4301-a5bb-e223c3213231",
  "response": "rejected",
  "message": "User has denied your request",
  "decision_at": "2025-01-15T14:24:14-03:00"
}

Campos da Resposta de Rejeição

CampoTipoDescrição
auth_request_idstringID da solicitação de autorização
responsestringResposta do cliente ("rejected")
messagestringMensagem explicativa
decision_atstringData/hora da decisão

Configuração do Webhook

URL de Webhook

A URL do webhook deve ser configurada ao criar a solicitação de autorização:

curl --location 'https://api-h.nuvende.com.br/api/v2/partners/requests' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {access_token}' \
--data '{
  "application_id": "abnks92-cb57-4ee3-a997-e223c3213231",
  "name": "João Silva",
  "document": "12345678901",
  "email": "[email protected]",
  "phone": "11999999999",
  "origin": "partner",
  "scopes": ["cob.read", "cob.write"],
  "webhook_url": "https://meusite.com/webhook/autorizacao",
  "metadata": ["Solicitação via app"]
}'

Requisitos da URL

  • HTTPS: URL deve usar protocolo seguro
  • Acessibilidade: Endpoint deve estar disponível publicamente
  • Resposta HTTP 200: Deve retornar status de sucesso
  • Timeout: Resposta deve ocorrer em até 30 segundos

Implementação do Endpoint

Exemplo em Node.js/Express

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

app.use(express.json());

// Endpoint para receber webhooks
app.post('/webhook/autorizacao', (req, res) => {
  try {
    const webhookData = req.body;
    
    console.log('Webhook recebido:', webhookData);
    
    // Processar baseado no status
    if (webhookData.status === 'approved') {
      handleApprovedRequest(webhookData);
    } else if (webhookData.response === 'rejected') {
      handleRejectedRequest(webhookData);
    }
    
    // Sempre retornar 200 para confirmar recebimento
    res.status(200).json({ received: true });
    
  } catch (error) {
    console.error('Erro ao processar webhook:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

const handleApprovedRequest = (data) => {
  console.log('Solicitação aprovada:', data.auth_request_id);
  
  // Salvar credenciais de forma segura
  const credentials = {
    client_id: data.client_id,
    client_secret: data.client_secret,
    account_id: data.account_id,
    scopes: data.scopes
  };
  
  // Implementar lógica de integração
  initializeIntegration(credentials);
};

const handleRejectedRequest = (data) => {
  console.log('Solicitação rejeitada:', data.auth_request_id);
  console.log('Motivo:', data.message);
  
  // Implementar lógica de notificação ao usuário
  notifyUserRejection(data);
};

app.listen(3000, () => {
  console.log('Servidor webhook rodando na porta 3000');
});

Exemplo em Python/Flask

from flask import Flask, request, jsonify
import json

app = Flask(__name__)

@app.route('/webhook/autorizacao', methods=['POST'])
def webhook_handler():
    try:
        webhook_data = request.get_json()
        
        print(f'Webhook recebido: {webhook_data}')
        
        # Processar baseado no status
        if webhook_data.get('status') == 'approved':
            handle_approved_request(webhook_data)
        elif webhook_data.get('response') == 'rejected':
            handle_rejected_request(webhook_data)
        
        # Sempre retornar 200 para confirmar recebimento
        return jsonify({'received': True}), 200
        
    except Exception as e:
        print(f'Erro ao processar webhook: {e}')
        return jsonify({'error': 'Internal server error'}), 500

def handle_approved_request(data):
    print(f'Solicitação aprovada: {data["auth_request_id"]}')
    
    # Salvar credenciais de forma segura
    credentials = {
        'client_id': data['client_id'],
        'client_secret': data['client_secret'],
        'account_id': data['account_id'],
        'scopes': data['scopes']
    }
    
    # Implementar lógica de integração
    initialize_integration(credentials)

def handle_rejected_request(data):
    print(f'Solicitação rejeitada: {data["auth_request_id"]}')
    print(f'Motivo: {data["message"]}')
    
    # Implementar lógica de notificação ao usuário
    notify_user_rejection(data)

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

Segurança

Validação de Webhook

Recomenda-se implementar validação de segurança:

const crypto = require('crypto');

const validateWebhook = (payload, signature, secret) => {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
};

// Uso no endpoint
app.post('/webhook/autorizacao', (req, res) => {
  const signature = req.headers['x-nuvende-signature'];
  const payload = JSON.stringify(req.body);
  
  if (!validateWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  // Processar webhook...
});

Boas Práticas

  • Idempotência: Processar webhooks de forma idempotente
  • Logs: Manter logs detalhados de todas as notificações
  • Retry: Implementar retry em caso de falha
  • Timeout: Configurar timeout adequado para processamento
  • Validação: Validar dados recebidos antes do processamento

Tratamento de Erros

Códigos de Resposta

CódigoDescriçãoAção do Sistema
200SucessoWebhook processado com sucesso
400Bad RequestDados inválidos
401UnauthorizedAssinatura inválida
500Server ErrorSistema tentará reenviar

Reenvio Automático

O sistema Nuvende implementa reenvio automático:

  • Primeira tentativa: Imediata
  • Segunda tentativa: Após 5 minutos
  • Terceira tentativa: Após 30 minutos
  • Quarta tentativa: Após 2 horas
  • Desistência: Após 4 tentativas

Monitoramento

Logs Recomendados

const logWebhook = (data, status) => {
  console.log({
    timestamp: new Date().toISOString(),
    auth_request_id: data.auth_request_id,
    status: status,
    client_ip: req.ip,
    user_agent: req.headers['user-agent']
  });
};

// Uso
app.post('/webhook/autorizacao', (req, res) => {
  const webhookData = req.body;
  
  try {
    // Processar webhook
    processWebhook(webhookData);
    
    logWebhook(webhookData, 'success');
    res.status(200).json({ received: true });
    
  } catch (error) {
    logWebhook(webhookData, 'error');
    res.status(500).json({ error: 'Processing failed' });
  }
});

Exemplo Completo

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

app.use(express.json());

// Middleware de validação
const validateWebhook = (req, res, next) => {
  const signature = req.headers['x-nuvende-signature'];
  const payload = JSON.stringify(req.body);
  
  if (!signature) {
    return res.status(401).json({ error: 'Missing signature' });
  }
  
  const expectedSignature = crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  
  if (!crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  )) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  next();
};

// Endpoint principal
app.post('/webhook/autorizacao', validateWebhook, (req, res) => {
  const webhookData = req.body;
  
  try {
    console.log('Webhook recebido:', {
      auth_request_id: webhookData.auth_request_id,
      status: webhookData.status || webhookData.response,
      timestamp: new Date().toISOString()
    });
    
    // Processar baseado no tipo
    if (webhookData.status === 'approved') {
      handleApprovedRequest(webhookData);
    } else if (webhookData.response === 'rejected') {
      handleRejectedRequest(webhookData);
    }
    
    res.status(200).json({ received: true });
    
  } catch (error) {
    console.error('Erro ao processar webhook:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

const handleApprovedRequest = async (data) => {
  try {
    // Salvar credenciais
    await saveCredentials({
      auth_request_id: data.auth_request_id,
      client_id: data.client_id,
      client_secret: data.client_secret,
      account_id: data.account_id,
      scopes: data.scopes,
      account_info: {
        account: data.account,
        account_vd: data.account_vd,
        agency: data.agency,
        agency_vd: data.agency_vd
      }
    });
    
    // Inicializar integração
    await initializeIntegration(data);
    
    console.log('Integração inicializada para:', data.auth_request_id);
    
  } catch (error) {
    console.error('Erro ao processar aprovação:', error);
    throw error;
  }
};

const handleRejectedRequest = (data) => {
  console.log('Solicitação rejeitada:', {
    auth_request_id: data.auth_request_id,
    message: data.message,
    decision_at: data.decision_at
  });
  
  // Notificar usuário sobre rejeição
  notifyUserRejection(data);
};

app.listen(3000, () => {
  console.log('Servidor webhook rodando na porta 3000');
});

Próximos Passos

Após configurar webhooks:

  1. Testar endpoint com ferramentas como ngrok ou webhook.site
  2. Implementar processamento das notificações
  3. Configurar monitoramento e logs
  4. Implementar integração com credenciais recebidas

2025 © Nuvende - CNPJ 38.297.374/0001-93