Fire Bankingdocs
集成指南

Webhook 重发

概述

Webhook 重发端点允许您请求手动重新发送特定交易的通知。这在以下场景中很有用:

  • 原始 webhook 发送时您的服务器不可用
  • 您需要重新处理特定交易
  • 您想临时使用不同的 URL 测试集成

此端点不会更改您账户的 webhook 配置。提供的 URL 仅用于本次特定重发。


工作原理

交易标识

端点接受三种类型的标识符:

类型描述范围
数字 ID内部交易 ID(webhooks 中的 transactionId 字段)全局
外部 ID您在创建时提供的标识符(externalId 字段)每个账户唯一
End-to-End IDBACEN PIX 标识符(endToEndId 字段,格式:E/D + 32 个字符)每笔交易唯一

系统在您的账户中同时搜索所有标识符类型。实际上不存在歧义:数字 id 为纯数字;e2eId 以 'E' 或 'D' 开头后跟 32 个字母数字字符;externalId 为您提供的任意字符串。

使用哪个标识符? 使用 Avista 返回的数字 transactionId、您在创建交易时提供的 externalId,或 webhooks 中收到的 PIX endToEndId。三者同样有效。

同步处理

Webhook 重发是同步处理的。这意味着:

  • 请求等待 webhook 交付完成
  • 结果通过 HTTP 状态码返回(200、502、504)
  • 响应时间取决于您服务器的延迟(超时:10 秒)
flowchart TD
    A[Resend Request] --> B{URL provided?}
    B -->|Yes| C[Use temporary URL]
    B -->|No| D{Webhook configured?}
    D -->|Yes| E[Use configured URL]
    D -->|No| F[Error 400: No URL]
    C --> G[Send Webhook HTTP]
    E --> G
    G --> H{Server response}
    H -->|2xx| I[HTTP 200: Success]
    H -->|4xx/5xx| J[HTTP 502: Bad Gateway]
    H -->|Timeout| K[HTTP 504: Gateway Timeout]
    I --> L[Record audit log]
    J --> L
    K --> L
    L --> M[Return result]

与自动 webhooks(使用带重试的队列)不同,手动重发是立即执行的,并在同一请求中返回结果。


使用场景

1. 重发到已配置的 URL

如果您的账户已配置 webhook,只需调用端点,无需请求体:

curl -X POST https://api.public.firebanking.com.br/api/resend-webhook/external-teste-001 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json"

2. 使用临时 URL 重发

要使用不同的 URL 测试或重发到备用端点:

curl -X POST https://api.public.firebanking.com.br/api/resend-webhook/external-teste-001 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://my-backup-server.com/webhooks/avista"
  }'

临时 URL 不会被持久化。下一次自动 webhook 将发送到账户配置的 URL。


响应

成功 (200)

Webhook 已成功发送到目标 URL。

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

错误:未配置 URL (400)

{
  "statusCode": 400,
  "message": "No webhook configured and no override URL provided",
  "error": "Bad Request"
}

错误:交易未找到 (404)

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

错误:目标返回错误 (502)

目标服务器返回错误(4xx 或 5xx)或连接失败。

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

即使在错误情况下,webhook 也会记录在审计日志中。使用 webhookLogId 进行追踪。

错误:超时 (504)

目标服务器未在时限内响应(10 秒)。

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

如果频繁遇到超时,请检查您的服务器是否能在 10 秒内响应。


速率限制

此端点每个账户的速率限制为每分钟 60 次请求,以防止滥用。

如果超出限制,您将收到 429 Too Many Requests 错误:

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

审计

所有手动重发都会被记录以用于审计和追溯:

信息描述
发送类型标记为手动重发
使用的 URL记录是临时 URL 还是已配置的 URL
结果HTTP 状态和响应时间
标识符用于追踪的唯一日志 ID

使用响应中返回的 webhookLogId 与支持日志进行关联(如需要)。


集成示例

const axios = require('axios');

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

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

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

    console.log('Webhook resent:', response.data);
    return response.data;
  } catch (error) {
    console.error('Error resending webhook:', error.response?.data);
    throw error;
  }
}

// Usage
resendWebhook('external-teste-001');
resendWebhook('external-teste-001', 'https://backup.mysite.com/webhook'); // With temporary URL
import requests
import os

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

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

    response = requests.post(
        f'https://api.public.firebanking.com.br/api/resend-webhook/{transaction_id}',
        json=body,
        headers=headers
    )

    response.raise_for_status()
    return response.json()

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

# With temporary URL
result = resend_webhook('external-teste-001', 'https://backup.mysite.com/webhook')
using System.Net.Http;
using System.Text;
using System.Text.Json;

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

    public FireBankingClient(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.public.firebanking.com.br/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);
    }
}

后续步骤

本页目录