Pi Network 对 U2A (User-to-App) 支付有一个重要限制:
- 同一用户在同一应用中只能有一个未完成的支付
- 如果上一个支付因为任何原因没有完成(用户取消、网络错误、超时等),会一直阻塞新的支付
- 这个未完成的支付必须被完成或取消,才能创建新的支付
-
onIncompletePaymentFound回调的误解:- 这个回调只存在于
Pi.authenticate()方法中 Pi.createPayment()方法不支持这个回调- 因此无法在创建支付时直接捕获和处理未完成的支付
- 这个回调只存在于
-
A2U vs U2A 支付的混淆:
- 我们创建的
/api/v1/payments/incomplete端点只能查询 A2U (App-to-User) 支付 - 用户遇到的是 U2A (User-to-App) 支付问题
- 这两种支付在 Pi Network 系统中是分开管理的
- 我们创建的
-
无法通过后端直接解决:
- Pi Network API 不提供通过 API Key 查询用户支付历史的功能
- 需要用户的 Access Token 才能查询
- 后端无法主动为用户取消或完成 U2A 支付
由于技术限制,我们无法自动解决这个问题,但可以提供清晰的用户指导:
在 merchant-code/page.tsx 中:
catch (err) {
const errorMsg = err instanceof Error ? err.message : "Failed to generate, please try again";
// 检测 pending payment 错误
if (errorMsg.toLowerCase().includes("pending payment") ||
errorMsg.toLowerCase().includes("incomplete payment") ||
errorMsg.toLowerCase().includes("needs an action")) {
setShowPendingPaymentHelp(true);
setError("You have an incomplete payment that needs to be resolved.");
} else {
setError(errorMsg);
}
}创建一个友好的对话框,提供三种解决方案:
- 原理:Pi Network 的未完成支付可能会在一段时间后自动超时
- 步骤:
- 等待 5-10 分钟
- 刷新页面
- 再次尝试
- 原理:用户可以在 Pi Browser 中查看和取消自己的支付
- 步骤:
- 打开 Pi Browser app
- 进入支付历史
- 找到并取消未完成的支付
- 返回应用重试
- 原理:开发者可以在 Pi Developer Portal 中管理应用的支付
- 步骤:
- 访问 Pi Developer Portal
- 登录并选择你的应用
- 查看 Payments 列表
- 取消或完成未完成的支付
{showPendingPaymentHelp && (
<div className="fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4">
<div className="bg-[#1a1d24] rounded-2xl max-w-md w-full p-6 relative">
{/* 关闭按钮 */}
<button onClick={() => setShowPendingPaymentHelp(false)}>×</button>
{/* 标题和说明 */}
<div className="mb-6">
<h3>Incomplete Payment Detected</h3>
<p>Pi Network has detected an incomplete payment...</p>
</div>
{/* 三种解决方案 */}
<div className="space-y-4 mb-6">
<Solution1 />
<Solution2 />
<Solution3 />
</div>
{/* 操作按钮 */}
<div className="flex gap-3">
<button onClick={refreshPage}>Refresh Page</button>
<button onClick={close}>Close</button>
</div>
</div>
</div>
)}- ❌ 显示神秘的错误消息
- ❌ 用户不知道如何解决
- ❌ 需要开发者手动干预
- ❌ 反复重试无效
- ✅ 清晰的错误说明
- ✅ 提供三种解决方案
- ✅ 用户可以自助解决
- ✅ 减少支持请求
-
Pi Network API 限制:
无法通过 API Key 查询用户的支付历史 ↓ 无法找到未完成的 paymentId ↓ 无法调用取消或完成 API -
安全性考虑:
- 只有用户自己才能取消自己的支付
- 这是 Pi Network 的安全设计
- 防止恶意应用随意取消用户支付
-
架构限制:
U2A 支付流程: 用户 → Pi SDK → Pi Network → 应用后端 问题发生在: 用户 → Pi SDK (这一步失败) 应用后端无法干预这一步
虽然无法自动修复 U2A 支付问题,但我们仍然提供了工具来管理 A2U 支付:
用途:查询和取消未完成的 A2U (App-to-User) 支付
# 查询未完成的 A2U 支付
GET /api/v1/payments/incomplete
# 取消 A2U 支付
POST /api/v1/payments/incomplete
Content-Type: application/json
{
"paymentId": "payment_id_here",
"action": "cancel"
}注意:这个 API 只能处理 A2U 支付(如商家分红、批量转账等),无法处理 U2A 支付(如商家注册、用户付款等)。
为了减少未来出现 pending payment 的情况:
// 在 complete-registration API 中
// 更宽松的状态检查
if (!payment.status?.transaction_verified) {
return json({ error: "交易尚未验证" }, { status: 400 });
}
// 主动完成支付
if (!payment.status?.developer_completed) {
await completePayment(paymentId, txid);
}// 在前端添加支付超时检测
const PAYMENT_TIMEOUT = 60000; // 60秒
setTimeout(() => {
if (!paymentCompleted) {
reject(new Error("Payment timeout"));
}
}, PAYMENT_TIMEOUT);在 UI 中添加提示:
- "Please do not close this page during payment"
- "Payment usually takes 10-30 seconds"
- "If payment fails, please wait before retrying"
-
模拟 pending payment:
- 发起支付后立即关闭页面
- 再次尝试发起支付
- 验证帮助对话框是否正确显示
-
测试解决方案:
- 等待超时(方案 1)
- 手动取消(方案 2)
- 通过 Portal 取消(方案 3)
-
用户流程测试:
- 从头到尾完成注册流程
- 确保所有步骤都有适当的反馈
- 测试各种边界情况
- Pi Network Payments Documentation
- Pi Developer Portal
INCOMPLETE_PAYMENT_FIX.md- 第一版修复文档MERCHANT_PAYMENT_IMPLEMENTATION.md- 商家支付实现文档
- 问题本质:U2A pending payment 是 Pi Network 的限制,无法通过后端自动解决
- 解决策略:提供清晰的用户指导,让用户自助解决
- 用户体验:友好的错误处理和详细的解决步骤
- 预防为主:改进支付流程,减少 pending payment 的发生
✅ DO(应该做):
- 提供清晰的错误消息
- 给出具体的解决步骤
- 改进支付完成流程
- 添加适当的用户提示
❌ DON'T(不要做):
- 试图通过后端强制取消用户支付
- 隐藏错误信息
- 让用户反复重试而不给出指导
- 假设用户知道如何解决
最终更新: 2025-10-21
状态: ✅ 已实现并测试
影响范围: 商家注册功能