状态概览
付款从创建到最终结算会经历多个阶段。每个阶段有三个状态——待处理、处理中和已完成——让您在整个流程的每个步骤都能获得精细的可见性。
状态流转
在**收款(Cash In)**阶段,FAILED 和 ERROR 是终态——未收集到任何资金,因此不会发起退款。对于所有后续阶段(KYT 出账、出款),FAILED 和 ERROR 是过渡状态:付款将转入退款流程(REFUND_PENDING → REFUND_PROCESSING → REFUNDED)。REJECTED 也会触发退款流程,因为它仅在收款阶段之后发生。
状态说明
| 状态 | 阶段 | 说明 | 建议提示语 |
|---|
CREATED | 初始 | 付款已接收并持久化,等待进入处理队列 | ”付款已提交” |
CASH_IN_PENDING | 收款 | 入账资金收集已入队 | ”正在处理付款” |
CASH_IN_PROCESSING | 收款 | 正在从预存余额收集资金 | ”正在收集资金” |
CASH_IN_COMPLETED | 收款 | 资金已成功收集 | ”资金已收集” |
KYT_OUT_PENDING | KYT 出账 | 出账交易已入队等待合规检查 | ”出账检查待处理” |
KYT_OUT_PROCESSING | KYT 出账 | 出账合规审查进行中 | ”出账检查进行中” |
KYT_OUT_COMPLETED | KYT 出账 | 出账合规检查通过 | ”准备转账” |
CASH_OUT_PENDING | 出款 | 向收款方的付款已入队 | ”转账已入队” |
CASH_OUT_PROCESSING | 出款 | 资金已提交至支付服务商 | ”转账处理中” |
CASH_OUT_COMPLETED | 出款 | 支付服务商已确认交付 | ”转账已交付” |
COMPLETED | 终态 | 付款已完全结算 | ”付款已送达!“ |
REVIEW_NEEDED | 审查 | 交易已标记为需要人工合规审查 | ”审查中——我们会通知您” |
FAILED | 错误状态 | 操作失败。收款阶段发生时为终态(未收集资金);后续阶段发生时转入退款流程。 | “转账失败——请检查收款方信息” |
REJECTED | 错误状态 | 付款因合规审查被拦截。始终触发退款流程,因为它仅在收款阶段之后发生。 | “转账被拒绝——合规问题” |
ERROR | 错误状态 | 内部系统错误。收款阶段发生时为终态(未收集资金);后续阶段发生时转入退款流程。 | “内部错误——请联系支持” |
REFUND_PENDING | 退款 | 退回预存余额的退款已入队 | ”退款已发起” |
REFUND_PROCESSING | 退款 | 退款进行中 | ”退款进行中” |
REFUNDED | 终态 | 资金已退回预存余额 | ”资金已退回余额” |
获取付款状态
const getPayoutStatus = async (payoutId) => {
const response = await fetch(
`https://sandbox.killb.app/api/v2/payouts/${payoutId}`,
{
headers: { 'Authorization': `Bearer ${token}` }
}
);
const payout = await response.json();
return payout.status;
};
轮询状态
当 webhooks 不可用时,使用轮询作为备选方案:
const waitForPayout = async (payoutId, timeoutMs = 300000) => {
const terminalStatuses = ['COMPLETED', 'FAILED', 'REJECTED', 'ERROR', 'REFUNDED'];
const start = Date.now();
while (Date.now() - start < timeoutMs) {
const response = await fetch(
`https://sandbox.killb.app/api/v2/payouts/${payoutId}`,
{ headers: { 'Authorization': `Bearer ${token}` } }
);
const payout = await response.json();
console.log('状态:', payout.status);
if (terminalStatuses.includes(payout.status)) {
return payout;
}
// 等待 15 秒后再次检查
await new Promise(resolve => setTimeout(resolve, 15000));
}
throw new Error(`付款 ${payoutId} 在超时时间内未完成结算`);
};
const result = await waitForPayout('payout-abc123');
if (result.status === 'COMPLETED') {
console.log('资金已成功交付');
} else {
console.error('付款以状态结束:', result.status);
}
优先使用 webhooks 作为主要通知方式。每 15–30 秒轮询一次适合作为备用方案。
通过 Webhooks 获取状态更新
订阅 PAYOUT 事件类型,在每次状态变更时实时收到通知:
// 订阅付款事件
await fetch('/api/v2/webhooks', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://your-app.com/webhooks/killb',
secret: 'your-webhook-secret',
events: ['PAYOUT'],
active: true
})
});
处理收到的付款 webhook 事件:
app.post('/webhooks/killb', (req, res) => {
const { event, data } = req.body;
switch (event) {
// 阶段进度事件——更新您界面中的状态指示器
case 'payout.cash_in_pending':
case 'payout.cash_in_processing':
case 'payout.cash_in_completed':
case 'payout.kyt_out_pending':
case 'payout.kyt_out_processing':
case 'payout.kyt_out_completed':
case 'payout.cash_out_pending':
case 'payout.cash_out_processing':
case 'payout.cash_out_completed':
case 'payout.refund_pending':
case 'payout.refund_processing': {
const status = event.replace('payout.', '').toUpperCase();
updatePayoutStatus(data.id, status);
break;
}
case 'payout.completed':
updatePayoutStatus(data.id, 'COMPLETED');
notifyRecipient(data);
break;
case 'payout.review_needed':
// 交易已标记为人工审查——无需操作,付款将在审查完成后自动恢复
updatePayoutStatus(data.id, 'REVIEW_NEEDED');
alertComplianceTeam(data);
break;
case 'payout.error':
// 内部系统错误——未进行任何付款
updatePayoutStatus(data.id, 'ERROR');
alertOpsTeam(data);
break;
case 'payout.failed':
// 收款方账户信息无效或不正确
updatePayoutStatus(data.id, 'FAILED');
notifyInvalidBeneficiary(data);
break;
case 'payout.rejected':
// 因合规审查被拦截
updatePayoutStatus(data.id, 'REJECTED');
escalateToCompliance(data);
break;
case 'payout.refunded':
// 资金已退回预存余额
updatePayoutStatus(data.id, 'REFUNDED');
reconcileBalance(data);
break;
}
res.status(200).json({ received: true });
});
最佳实践
始终为 PAYOUT 事件配置 webhook 端点。这可以即时获取状态更新,无需轮询开销,并减少不必要的 API 调用。
如果 webhook 交付失败,每 15–30 秒查询一次 GET /api/v2/payouts/{id}。设置合理的超时时间(例如 5 分钟),如果付款在任何处理状态停留时间超过预期,及时通知团队。
每种失败状态都有不同的原因。FAILED 或 ERROR 发生的阶段决定是否发起退款:
- 收款阶段的
FAILED / ERROR — 终态。未收集到任何资金,不会发起退款。ERROR 若持续出现请联系支持。
- 收款阶段之后的
FAILED / ERROR(KYT 出账、出款)— 过渡状态。由于资金已收集,付款自动转入 REFUND_PENDING → REFUND_PROCESSING → REFUNDED。
REJECTED — 因合规审查被拦截。不可自动重试,应在内部升级处理。由于资金已收集,始终会触发退款流程。
REVIEW_NEEDED — KYT 检查标记了该交易需要人工审查。审查完成后付款将自动恢复或转为 REJECTED,您无需采取任何行动。
通过 GET /api/v2/payouts 获取前一天的所有付款,并与内部账本核对。比较预期与实际的终态,及早发现差异。const { payouts } = await listPayouts({ limit: 100 });
const needsAttention = payouts.filter(p =>
['ERROR', 'FAILED', 'REJECTED'].includes(p.status)
);
if (needsAttention.length > 0) {
console.warn(`${needsAttention.length} 笔付款需要处理`, needsAttention);
}
下一步
配置 Webhooks
配置并保护 webhook 通知