docs
Guías de Integración

Reenvío de Webhook

Descripción General

El endpoint de Reenvío de Webhook le permite solicitar el reenvío manual de notificaciones de transacciones específicas. Esto es útil en escenarios donde:

  • Su servidor no estaba disponible cuando se envió el webhook original
  • Necesita reprocesar una transacción específica
  • Desea probar la integración con una URL diferente temporalmente

POST /api/resend-webhook/:transactionIdentifier

Requiere el token Bearer de la cuenta en el header Authorization.

Este endpoint no modifica la configuración de webhook de su cuenta. La URL proporcionada se usa solo para ese reenvío específico.

El reenvío aplica a los eventos de transacción (CashIn, CashOut, CashInReversal y CashOutReversal). El evento se elige automáticamente a partir del tipo de la transacción. Los eventos MED no se reenvían por este endpoint.


Funcionamiento

Identificación de la Transacción

El endpoint acepta tres tipos de identificadores:

TipoDescripciónAlcance
ID NuméricoID interno de la transacción (campo transactionId en los webhooks)Global
ID ExternoIdentificador proporcionado por usted al crearla (campo externalId)Único por cuenta
End-to-End IDIdentificador PIX del BACEN (campo endToEndId, formato: E/D + 32 caracteres)Único por transacción

El sistema busca simultáneamente por todos los tipos de identificador en su cuenta. En la práctica no hay ambigüedad: el ID numérico es solo dígitos; el e2eId comienza con 'E' o 'D' seguido de 32 caracteres alfanuméricos; el externalId es cualquier string proporcionado por usted.

¿Qué identificador usar? Use el transactionId numérico devuelto por FyPay, el externalId que proporcionó al crear la transacción, o el endToEndId del PIX recibido en los webhooks. Todos son igualmente válidos.

Procesamiento Síncrono

El reenvío de webhook se procesa de forma síncrona. Esto significa que:

  • La solicitud espera a que se complete el envío del webhook
  • El resultado se comunica mediante el código de estado HTTP (200, 502, 504)
  • El tiempo de respuesta depende de la latencia de su servidor (timeout de 10 s por URL)
flowchart TD
    A[Solicitud de Reenvío] --> B{¿URL proporcionada?}
    B -->|Sí| C[Usa URL temporal]
    B -->|No| D{¿Webhook configurado?}
    D -->|Sí| E[Usa las URLs configuradas]
    D -->|No| F[Error 400: Sin URL]
    C --> G[Envía Webhook HTTP]
    E --> G
    G --> H{Respuesta del servidor}
    H -->|2xx| I[HTTP 200: Éxito]
    H -->|4xx/5xx| J[HTTP 502: Bad Gateway]
    H -->|Timeout| K[HTTP 504: Gateway Timeout]
    I --> L[Registra log de auditoría]
    J --> L
    K --> L
    L --> M[Devuelve resultado]

A diferencia de los webhooks automáticos (que usan colas con reintentos), el reenvío manual se ejecuta inmediatamente y devuelve el resultado en la misma solicitud.

El reenvío pasa por el mismo pipeline de envío del webhook original: el payload se reconstruye a partir del estado actual de la transacción y se firma con la clave HMAC actual de la cuenta en el header X-Avista-Signature. Las cuentas que todavía no generaron la clave en el panel reciben el reenvío sin ese header, igual que en los webhooks automáticos.


Casos de Uso

1. Reenvío a la(s) URL(s) Configurada(s)

Si ya tiene un webhook configurado en su cuenta, basta con llamar al endpoint sin body:

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

2. Reenvío con URL Temporal

Para probar con una URL diferente o reenviar a un endpoint de contingencia:

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

La URL temporal no se persiste. El próximo webhook automático se enviará a la(s) URL(s) configurada(s) en la cuenta. La URL temporal debe ser pública (http o https); las direcciones privadas o internas se rechazan con 400.

Sin url en el body, el reenvío se envía a todas las URLs activas configuradas para el evento, cada una con sus propios headers personalizados y versión de payload. Con url informada, el reenvío usa los headers personalizados y la versión de payload de la primera URL activa configurada para el evento.


Respuesta

Éxito (200)

Webhook enviado con éxito a todas las URLs de destino. Cuando hay más de una URL, el mensaje informa la cantidad (por ejemplo, "Webhook resent successfully to 2 URLs") y los demás campos se refieren a la primera URL.

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

Error: Sin 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"
}

El estado 400 también se devuelve cuando url no es una URL válida o apunta a una dirección privada. Un token ausente o inválido devuelve 401.

Error: Transacción No Encontrada (404)

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

Error: El Destino Devolvió Error (502)

El servidor de destino devolvió un estado fuera del rango 2xx o hubo una falla de conexión. Con más de una URL, basta con que una falle para que la respuesta sea 502; los campos se refieren a la primera URL que falló.

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

Incluso en caso de error, el webhook queda registrado en el log de auditoría. Use el webhookLogId para el seguimiento.

Error: Timeout (504)

El servidor de destino no respondió dentro del tiempo límite (10 segundos).

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

Si recibe timeouts frecuentes, verifique que su servidor responda en menos de 10 segundos.


Rate Limiting

Este endpoint tiene un rate limiting de 60 solicitudes por minuto por cuenta para evitar abusos.

Si se excede el límite, recibirá un error 429 Too Many Requests. Espere el tiempo indicado en el header Retry-After antes de intentarlo de nuevo.

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

Auditoría

Todos los reenvíos manuales se registran para fines de auditoría y trazabilidad:

InformaciónDescripción
Tipo de envíoMarcado como reenvío manual
URL utilizadaRegistra si se usó una URL temporal o configurada
ResultadoEstado HTTP y tiempo de respuesta
IdentificadorID único del log para seguimiento

Use el webhookLogId devuelto en la respuesta para correlacionar con los logs de soporte si es necesario.


Ejemplos de Integración

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('Error al reenviar webhook:', error.response?.data);
    throw error;
  }
}

// Uso
resendWebhook('external-teste-001');
resendWebhook('external-teste-001', 'https://backup.misitio.com/webhook'); // Con URL temporal
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}")

# Con URL temporal
result = resend_webhook('external-teste-001', 'https://backup.misitio.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 Pasos

En esta página