docs
Guias de Integração

Reenvio de Webhooks

Visão Geral

O endpoint de Reenvio de Webhook permite que você solicite o reenvio manual de notificações de transações específicas. Isso é útil em cenários onde:

  • Seu servidor estava indisponível quando o webhook original foi enviado
  • Você precisa reprocessar uma transação específica
  • Deseja testar a integração com uma URL diferente temporariamente

POST /api/resend-webhook/:transactionIdentifier

Requer o token Bearer da conta no header Authorization.

Este endpoint não altera a configuração de webhook da sua conta. A URL fornecida é usada apenas para o reenvio específico.

O reenvio vale para os eventos de transação (CashIn, CashOut, CashInReversal e CashOutReversal). O evento é escolhido automaticamente a partir do tipo da transação. Eventos MED não são reenviados por este endpoint.


Funcionamento

Identificação da Transação

O endpoint aceita três tipos de identificadores:

TipoDescriçãoEscopo
ID NuméricoID interno da transação (campo transactionId nos webhooks)Global
ID ExternoIdentificador fornecido por você na criação (campo externalId)Único por conta
End-to-End IDIdentificador PIX do BACEN (campo endToEndId, formato: E/D + 32 chars)Único por transação

O sistema busca simultaneamente por todos os tipos de identificador na sua conta. Na prática não há ambiguidade: id numérico é puramente dígitos; e2eId começa com 'E' ou 'D' seguido de 32 caracteres alfanuméricos; externalId é qualquer string fornecida por você.

Qual identificador usar? Use o transactionId numérico retornado pela FyPay, o externalId que você forneceu na criação da transação, ou o endToEndId do PIX recebido nos webhooks. Todos são igualmente válidos.

Processamento Síncrono

O reenvio de webhook é processado de forma síncrona. Isso significa que:

  • A requisição aguarda o envio do webhook ser concluído
  • O resultado é comunicado via HTTP status code (200, 502, 504)
  • O tempo de resposta depende da latência do seu servidor (timeout de 10 s por URL)
flowchart TD
    A[Requisição de Reenvio] --> B{URL fornecida?}
    B -->|Sim| C[Usa URL temporária]
    B -->|Não| D{Webhook configurado?}
    D -->|Sim| E[Usa as URLs configuradas]
    D -->|Não| F[Erro 400: Sem URL]
    C --> G[Envia Webhook HTTP]
    E --> G
    G --> H{Resposta do servidor}
    H -->|2xx| I[HTTP 200: Sucesso]
    H -->|4xx/5xx| J[HTTP 502: Bad Gateway]
    H -->|Timeout| K[HTTP 504: Gateway Timeout]
    I --> L[Registra log de auditoria]
    J --> L
    K --> L
    L --> M[Retorna resultado]

Diferentemente dos webhooks automáticos (que utilizam filas com retry), o reenvio manual é executado imediatamente e retorna o resultado na mesma requisição.

O reenvio passa pelo mesmo pipeline de envio do webhook original: o payload é reconstruído a partir do estado atual da transação e assinado com a chave HMAC atual da conta no header X-Avista-Signature. Contas que ainda não geraram a chave no painel recebem o reenvio sem esse header, assim como nos webhooks automáticos.


Casos de Uso

1. Reenvio para URL(s) Configurada(s)

Se você já tem um webhook configurado na sua conta, basta chamar o endpoint sem body:

curl -X POST https://api.fypay.me/api/resend-webhook/external-teste-001 \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "Content-Type: application/json"

2. Reenvio com URL Temporária

Para testar com uma URL diferente ou reenviar para um endpoint de contingência:

curl -X POST https://api.fypay.me/api/resend-webhook/external-teste-001 \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://meu-servidor-backup.com/webhooks/fypay"
  }'

A URL temporária não é persistida. O próximo webhook automático será enviado para a(s) URL(s) configurada(s) na conta. A URL temporária deve ser pública (http ou https); endereços privados ou internos são recusados com 400.

Sem url no body, o reenvio é enviado para todas as URLs ativas configuradas para o evento, cada uma com seus próprios headers customizados e versão de payload. Com url informada, o reenvio usa os headers customizados e a versão de payload da primeira URL ativa configurada para o evento.


Resposta

Sucesso (200)

Webhook enviado com sucesso para todas as URLs de destino. Quando há mais de uma URL, a mensagem informa a quantidade (por exemplo, "Webhook resent successfully to 2 URLs") e os demais campos se referem à primeira URL.

{
  "message": "Webhook resent successfully",
  "webhookLogId": 12345,
  "sentAt": "2024-01-15T10:30:00.000Z",
  "statusCode": 200
}

Erro: Sem URL Configurada (400)

{
  "statusCode": 400,
  "message": "No webhook URL available. Configure a webhook for this operation type or provide an override URL.",
  "error": "Bad Request"
}

O status 400 também é retornado quando url não é uma URL válida ou aponta para um endereço privado. Token ausente ou inválido retorna 401.

Erro: Transação Não Encontrada (404)

{
  "statusCode": 404,
  "message": "Transaction not found",
  "error": "Not Found"
}

Erro: Destino Retornou Erro (502)

O servidor de destino retornou um status fora da faixa 2xx ou houve falha de conexão. Com mais de uma URL, basta uma falhar para a resposta ser 502; os campos se referem à primeira URL que falhou.

{
  "statusCode": 502,
  "message": "Webhook failed with status 500",
  "webhookLogId": 12345,
  "sentAt": "2024-01-15T10:30:00.000Z"
}

Mesmo em caso de erro, o webhook é registrado no log de auditoria. Use o webhookLogId para rastreamento.

Erro: Timeout (504)

O servidor de destino não respondeu dentro do tempo limite (10 segundos).

{
  "statusCode": 504,
  "message": "Timeout after 10000ms",
  "webhookLogId": 12345,
  "sentAt": "2024-01-15T10:30:00.000Z"
}

Se você está recebendo timeouts frequentes, verifique se seu servidor está respondendo em menos de 10 segundos.


Rate Limiting

Este endpoint possui rate limiting de 60 requisições por minuto por conta para evitar abusos.

Se o limite for excedido, você receberá um erro 429 Too Many Requests. Aguarde o tempo indicado no header Retry-After antes de tentar novamente.

{
  "statusCode": 429,
  "message": "ThrottlerException: Too Many Requests"
}

Auditoria

Todos os reenvios manuais são registrados para fins de auditoria e rastreabilidade:

InformaçãoDescrição
Tipo de envioMarcado como reenvio manual
URL utilizadaRegistra se foi usada URL temporária ou configurada
ResultadoStatus HTTP e tempo de resposta
IdentificadorID único do log para rastreamento

Use o webhookLogId retornado na resposta para correlacionar com logs de suporte se necessário.


Exemplos de Integração

const axios = require('axios');

async function resendWebhook(transactionId, overrideUrl = null) {
  const config = {
    headers: {
      'Authorization': `Bearer ${process.env.FYPAY_TOKEN}`,
      'Content-Type': 'application/json'
    }
  };

  const body = overrideUrl ? { url: overrideUrl } : {};

  try {
    const response = await axios.post(
      `https://api.fypay.me/api/resend-webhook/${transactionId}`,
      body,
      config
    );

    console.log('Webhook reenviado:', response.data);
    return response.data;
  } catch (error) {
    console.error('Erro ao reenviar webhook:', error.response?.data);
    throw error;
  }
}

// Uso
resendWebhook('external-teste-001');
resendWebhook('external-teste-001', 'https://backup.meusite.com/webhook'); // Com URL temporária
import requests
import os

def resend_webhook(transaction_id: str, override_url: str = None):
    headers = {
        'Authorization': f'Bearer {os.environ["FYPAY_TOKEN"]}',
        'Content-Type': 'application/json'
    }

    body = {'url': override_url} if override_url else {}

    response = requests.post(
        f'https://api.fypay.me/api/resend-webhook/{transaction_id}',
        json=body,
        headers=headers
    )

    response.raise_for_status()
    return response.json()

# Uso
result = resend_webhook('external-teste-001')
print(f"Webhook reenviado: {result}")

# Com URL temporária
result = resend_webhook('external-teste-001', 'https://backup.meusite.com/webhook')
using System.Net.Http;
using System.Text;
using System.Text.Json;

public class FyPayClient
{
    private readonly HttpClient _client;
    private readonly string _token;

    public FyPayClient(string token)
    {
        _client = new HttpClient();
        _token = token;
        _client.DefaultRequestHeaders.Add("Authorization", $"Bearer {_token}");
    }

    public async Task<ResendWebhookResponse> ResendWebhookAsync(
        string transactionId,
        string overrideUrl = null)
    {
        var url = $"https://api.fypay.me/api/resend-webhook/{transactionId}";

        var body = overrideUrl != null
            ? JsonSerializer.Serialize(new { url = overrideUrl })
            : "{}";

        var content = new StringContent(body, Encoding.UTF8, "application/json");

        var response = await _client.PostAsync(url, content);
        response.EnsureSuccessStatusCode();

        var json = await response.Content.ReadAsStringAsync();
        return JsonSerializer.Deserialize<ResendWebhookResponse>(json);
    }
}

Próximos Passos

Nesta página