集成指南
Webhook 重发
概述
Webhook 重发端点允许您请求手动重新发送特定交易的通知。这在以下场景中很有用:
- 原始 webhook 发送时您的服务器不可用
- 您需要重新处理特定交易
- 您想临时使用不同的 URL 测试集成
此端点不会更改您账户的 webhook 配置。提供的 URL 仅用于本次特定重发。
工作原理
交易标识
端点接受三种类型的标识符:
| 类型 | 描述 | 范围 |
|---|---|---|
| 数字 ID | 内部交易 ID(webhooks 中的 transactionId 字段) | 全局 |
| 外部 ID | 您在创建时提供的标识符(externalId 字段) | 每个账户唯一 |
| End-to-End ID | BACEN 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.ntxpay.com/api/resend-webhook/external-teste-001 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json"2. 使用临时 URL 重发
要使用不同的 URL 测试或重发到备用端点:
curl -X POST https://api.ntxpay.com/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.NTXPAY_TOKEN}`,
'Content-Type': 'application/json'
}
};
const body = overrideUrl ? { url: overrideUrl } : {};
try {
const response = await axios.post(
`https://api.ntxpay.com/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 URLimport requests
import os
def resend_webhook(transaction_id: str, override_url: str = None):
headers = {
'Authorization': f'Bearer {os.environ["NTXPAY_TOKEN"]}',
'Content-Type': 'application/json'
}
body = {'url': override_url} if override_url else {}
response = requests.post(
f'https://api.ntxpay.com/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 NtxPayClient
{
private readonly HttpClient _client;
private readonly string _token;
public NtxPayClient(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.ntxpay.com/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);
}
}