支付即积分方案如何判定有效交易并防范场外交易风险?
明确结论
“支付即积分”不能简单理解为”只要发生支付就发积分”,也不宜仅凭位置信息判断交易是否有效。
一般来说,交易需要符合业务规则才能获得积分,包括商户在活动范围内、使用指定支付渠道、订单真实有效且没有退款等。这里的”圈内交易”可能是指指定商户、指定用户群、指定区域或指定支付渠道,具体含义需要在方案规则中写清楚。
位置信息可以辅助风控,但不能作为唯一判断依据。场外交易、虚假交易、自买自卖和商户套现都可能被用来套取积分,因此还要结合交易闭环、限额、关联关系识别、异常行为检测和积分延迟结算等机制。
有效交易应如何判定
有效交易可以定义为同时满足以下条件:
- 支付通过平台认可的渠道完成,并且能够取得可信的支付流水号。
- 收款商户已经加入积分活动,交易发生时资格仍然有效。
- 订单金额、支付金额和结算金额可以相互核对。
- 支付状态为成功,交易没有被撤销、退款或拒付。
- 交易类型在积分适用范围内。充值、转账、提现等非消费行为通常需要排除。
- 用户、商户和设备均未命中高风险规则。
- 交易没有超过单笔、每日、每月或整个活动周期的积分上限。
因此,“只有圈内交易才能获得积分”是否成立,要看”圈内”如何定义。如果它指签约商户,可以通过 merchant_id 或商户活动资格来判断;如果它指地理商圈,则需要交叉核验门店、订单和位置等信息。
位置信息应该怎样使用
位置判断更适合用来发现异常,不宜直接决定是否发放积分。
在线下到店消费场景中,可以比较用户支付位置与门店位置的距离:
[ d = 2R\arcsin\left(\sqrt{\sin^2\left(\frac{\Delta\varphi}{2}\right)+\cos(\varphi_1)\cos(\varphi_2)\sin^2\left(\frac{\Delta\lambda}{2}\right)}\right) ]
其中,(R) 为地球半径,(d) 为用户与门店之间的估算距离。
距离超过阈值不一定说明交易虚假。用户可能关闭了定位,也可能使用代理付款;商场内还可能出现定位漂移,订单也可能属于外卖、预约或代付。因此,更稳妥的处理方式是:
- 距离正常时,增加交易可信度。
- 距离异常时,提高风险分,但不要立即拒绝。
- 用户没有授权定位时,结合支付流水、设备和历史行为判断。
- 线上订单、外卖或代付交易不应套用线下到店距离规则。
客户端上传的经纬度可能被篡改。在高风险场景中,可以结合定位时间、定位精度、设备完整性、IP 地址、门店终端和支付受理环境进行校验。
场外交易有哪些常见风险
场外交易风险并不只是”人在商圈外完成支付”。更常见的情况是交易没有真实的消费背景,却通过形式上的支付套取积分,例如:
- 用户与商户协商虚构消费,积分到账后再私下退款。
- 用户通过自己控制的商户账户自买自卖。
- 多个账号集中向同一商户支付小额订单。
- 同一设备批量登录多个账号并重复支付。
- 高频生成整数金额或固定金额的订单。
- 支付后频繁退款,或通过现金、转账等方式在场外返还资金。
- 商户拆分订单,绕过单笔积分上限。
- 用户、商户、收款账户、设备或网络环境之间存在隐蔽关联。
只限制地理位置无法识别这些问题。即使用户和商户都在同一门店内,虚假交易仍然可能发生。
推荐的识别与防范步骤
1. 建立可信的交易闭环
积分系统应以支付服务端的成功通知和主动查询结果为准,不能信任客户端提交的”支付成功”状态。
至少要保存以下关联关系:
order_id -> payment_id -> merchant_id -> user_id -> refund_id
同一个 payment_id 只能计算一次积分,避免支付回调重放或重复发放。
2. 采用”基础资格 + 风险评分”模型
先检查交易是否具备积分资格,再判断风险:
有效交易
= 支付成功
∩ 商户符合活动规则
∩ 交易类型合规
∩ 未重复计分
∩ 未退款或撤销
∩ 风险评分低于阈值
积分可以按以下方式计算:
[ points=\min(\lfloor eligibleAmount \times rate \rfloor,\ limit) ]
其中:
eligibleAmount是允许计分的实际支付金额;rate是积分倍率;limit是对应周期的积分上限。
具体倍率、取整方式和限额应以实际业务规则为准。
3. 识别用户、商户和设备之间的关联
可以分析以下关系:
- 用户是否为商户经营者、员工或关联人员。
- 支付账户与商户结算账户之间是否存在关联。
- 多个用户是否长期共用设备、IP 地址或支付工具。
- 新注册账号是否集中向少数商户交易。
- 商户的交易金额、交易时间和退款模式是否明显偏离同类商户。
这些关联只能作为风险信号。共用网络等弱证据不足以直接认定作弊。
4. 设置限额和冷却机制
可以设置以下限制:
- 单笔可计积分金额上限。
- 用户每日、每月积分上限。
- 商户每日发放积分上限。
- 同一用户与同一商户之间的交易频次限制。
- 新用户、新商户或高风险账户的积分冷却期。
限额既能降低损失,也能为人工审核留出时间。
5. 延迟结算并处理退款
高风险业务不宜在支付成功后立即让积分进入可兑换状态。积分可以先进入 pending 状态,等退款观察期结束后再转为 available。
发生退款时,应按原订单冲回积分。如果积分已经使用,则要按照业务规则形成负积分、冻结权益或转入人工处理流程。部分退款需要按实际退款金额等比例冲回,避免按整单处理造成误差。
规则实现示例
下面的 TypeScript 示例展示了简化的资格判断和风险评分流程。示例中的阈值只用于说明结构,不能直接用作生产参数。
type Transaction = {
orderId: string;
paymentId: string;
userId: string;
merchantId: string;
amount: number;
paymentStatus: "SUCCESS" | "FAILED" | "CLOSED";
transactionType: "PURCHASE" | "TRANSFER" | "TOP_UP";
merchantEligible: boolean;
alreadyRewarded: boolean;
refundedAmount: number;
distanceToStoreMeters?: number;
locationAccuracyMeters?: number;
transactionsWithMerchantToday: number;
deviceAccountCount: number;
};
type Evaluation = {
eligible: boolean;
riskScore: number;
action: "REJECT" | "REVIEW" | "PENDING" | "APPROVE";
reasons: string[];
};
function evaluateTransaction(tx: Transaction): Evaluation {
const reasons: string[] = [];
if (tx.paymentStatus !== "SUCCESS") {
return {
eligible: false,
riskScore: 0,
action: "REJECT",
reasons: ["PAYMENT_NOT_SUCCESSFUL"],
};
}
if (!tx.merchantEligible) {
return {
eligible: false,
riskScore: 0,
action: "REJECT",
reasons: ["MERCHANT_NOT_ELIGIBLE"],
};
}
if (tx.transactionType !== "PURCHASE") {
return {
eligible: false,
riskScore: 0,
action: "REJECT",
reasons: ["TRANSACTION_TYPE_NOT_ELIGIBLE"],
};
}
if (tx.alreadyRewarded) {
return {
eligible: false,
riskScore: 0,
action: "REJECT",
reasons: ["DUPLICATE_REWARD"],
};
}
if (tx.refundedAmount >= tx.amount) {
return {
eligible: false,
riskScore: 0,
action: "REJECT",
reasons: ["FULLY_REFUNDED"],
};
}
let riskScore = 0;
if (
tx.distanceToStoreMeters !== undefined &&
tx.locationAccuracyMeters !== undefined &&
tx.locationAccuracyMeters <= 100 &&
tx.distanceToStoreMeters > 3000
) {
riskScore += 20;
reasons.push("LOCATION_DISTANCE_ANOMALY");
}
if (tx.transactionsWithMerchantToday > 10) {
riskScore += 30;
reasons.push("HIGH_FREQUENCY_WITH_SAME_MERCHANT");
}
if (tx.deviceAccountCount > 5) {
riskScore += 40;
reasons.push("MULTIPLE_ACCOUNTS_ON_DEVICE");
}
if (riskScore >= 60) {
return {
eligible: true,
riskScore,
action: "REVIEW",
reasons,
};
}
if (riskScore >= 20) {
return {
eligible: true,
riskScore,
action: "PENDING",
reasons,
};
}
return {
eligible: true,
riskScore,
action: "APPROVE",
reasons,
};
}
生产环境还需要通过数据库唯一约束保证幂等性,例如:
CREATE UNIQUE INDEX uk_points_payment
ON points_ledger (payment_id, points_rule_id);
不能只依赖应用层的”是否已经发放”查询,因为并发回调仍可能造成积分重复发放。
注意事项
位置信息属于敏感个人信息。采集前需要说明用途、范围和保存期限,并按照适用法律和隐私政策取得授权。用户没有授予定位权限时,应提供合理的替代校验方式,不能直接将拒绝授权视为作弊。
风控规则还需要注意以下事项:
- 不要公开完整的阈值和规则权重,以免被反向测试。
- 不要只依赖 IP、GPS 或设备指纹等单一信号。
- 为误判交易提供申诉和人工复核入口。
- 保存规则版本、命中原因和处理记录,以便审计。
- 定期分析退款率、积分成本和误报率,并据此调整阈值。
- 高风险交易可以暂缓发放积分,但证据不足时不能直接认定用户或商户存在欺诈。
整体上,可以用商户资格和可信支付流水判断交易能否参与积分活动,再结合位置、频次、设备和关联关系识别可疑交易,最后通过延迟结算、退款冲回和人工复核控制实际损失。
备注:内容仅供参考。
