PAYATHON 2026

alipay.marketing.activity.voucher.create 参数冲突如何解决?

支付老李

结论

在当前调用场景中,voucher_use_rule_info.voucher_max_use_times 应完全省略,由支付宝服务端使用默认核销次数。

前后两次提示看似矛盾,通常与 AlipaySDKNet 对该字段的类型定义和序列化方式有关。如果字段使用非 nullable 数值类型,即使没有赋值,C# 也会将其初始化为 0。一旦 SDK 把这个默认值序列化并发送,服务端就会提示该值“必须大于或等于 1”。

将字段设为 1 后,参数值本身通过了校验,但接口还会检查当前业务场景是否允许商户传入该字段。如果不允许,就会返回“当前接口不支持的参数”。

所以,解决办法不是将值改成 1,而是确认最终提交的 biz_content 中没有 voucher_max_use_times。

为什么会出现两个看似冲突的错误

接口参数通常要经过多层校验:

  1. 字段值校验:收到 voucher_max_use_times=0 时,返回“必须大于或等于 1”。
  2. 接口或业务场景校验:收到 voucher_max_use_times=1 时,可能发现当前券类型、接口版本或业务模式不允许传入该字段,于是返回“当前接口不支持的参数”。

没有显式设置属性,不等于请求中一定没有这个字段。假设 SDK 模型中的属性定义如下:

public long VoucherMaxUseTimes { get; set; }

该属性未赋值时,默认值是 0。如果 SDK 序列化时不忽略数值类型的默认值,请求中仍可能包含:

{
  "voucher_use_rule_info": {
    "voucher_max_use_times": 0
  }
}

这可以解释第一次错误。

设置下面这行代码后:

voucherUseRuleInfo.VoucherMaxUseTimes = 1;

请求会明确传入该字段。服务端随后发现当前接口场景不接受它,因此出现第二次错误。

正确处理方式

1. 删除业务代码中的赋值

先移除这一行:

voucherUseRuleInfo.VoucherMaxUseTimes = 1;

只删除赋值可能还不够,还需要检查 SDK 是否会把默认值 0 序列化出去。

2. 检查实际发送的 biz_content

排查时应查看最终 HTTP 请求中的 biz_content,不能只检查 C# 对象。正确的请求中不应出现:

"voucher_max_use_times": 0

也不应出现:

"voucher_max_use_times": 1

同样不要发送:

"voucher_max_use_times": null

这个字段需要从请求中完全消失。

还要注意字段名称的差异。C# 属性名是 VoucherMaxUseTimes,序列化后的 JSON 字段通常是 voucher_max_use_times,错误信息中可能显示为 voucherMaxUseTimes。这三个名称指向同一个参数。

3. 优先升级 AlipaySDKNet

先确认当前使用的 AlipaySDKNet 和接口模型是否为可获得的较新版本。新版接口模型可能已经将该属性改为 nullable 类型,或者修正了默认值的序列化行为。

更新 DLL 后,也不要继续使用从旧版本复制出来的 Model 类。需要确认项目实际引用的 VoucherUseRuleInfo 来自哪个程序集或命名空间。

4. nullable 属性应保持 null

如果当前 SDK 将该属性定义为 nullable 类型,例如:

public long? VoucherMaxUseTimes { get; set; }

不要为其赋值,或者明确将其设为 null:

VoucherUseRuleInfo voucherUseRuleInfo = new VoucherUseRuleInfo();

VoucherUseTimeInfo voucherUseTimeInfo = new VoucherUseTimeInfo
{
    PeriodType = "ABSOLUTE",
    AbsolutePeriodInfo = new VoucherAbsolutePeriodInfo
    {
        ValidBeginTime = "2026-10-01 00:00:00",
        ValidEndTime = "2026-12-31 23:59:59"
    }
};

voucherUseRuleInfo.VoucherUseTimeInfo = voucherUseTimeInfo;
voucherUseRuleInfo.VoucherMaxUseTimes = null;

model.VoucherUseRuleInfo = voucherUseRuleInfo;

这样处理的前提是 SDK 序列化器会忽略 null 属性。完成修改后,仍要通过请求日志确认最终 JSON 中没有这个字段。

5. 非 nullable 属性需要修正模型或序列化结果

如果该属性是 long、int 等非 nullable 类型,而且 SDK 必然发送默认值,可以在可控的 SDK 模型源码中将其改成 nullable 类型:

[JsonProperty("voucher_max_use_times")]
public long? VoucherMaxUseTimes { get; set; }

修改后不要为该属性赋值。

如果项目引用的是 NuGet 包中的预编译模型,不建议直接修改缓存目录中的包文件。可以采用以下方式:

  • 升级到已经修正该问题的 SDK;
  • 使用项目内可维护的模型或 SDK 源码版本;
  • 在发送前构造请求 JSON,并删除 voucher_max_use_times。

自行构造 biz_content 时,结构可以写成:

var bizModel = new
{
    out_biz_no = "yaqi1111111111",
    merchant_access_mode = "SELF_MODE",
    activity_base_info = new
    {
        activity_name = "生活缴费红包"
    },
    voucher_use_rule_info = new
    {
        voucher_use_time_info = new
        {
            period_type = "ABSOLUTE",
            absolute_period_info = new
            {
                valid_begin_time = "2026-10-01 00:00:00",
                valid_end_time = "2026-12-31 23:59:59"
            }
        }

        // 不要添加 voucher_max_use_times
    }
};

如何将 JSON 设置到请求中,应以当前 AlipaySDKNet 版本公开的请求方法为准,不要假定所有版本都提供相同的重载。

建议调整后的核心代码

// 设置券核销限制
VoucherUseRuleInfo voucherUseRuleInfo = new VoucherUseRuleInfo();

VoucherUseTimeInfo voucherUseTimeInfo = new VoucherUseTimeInfo();
voucherUseTimeInfo.PeriodType = "ABSOLUTE";

VoucherAbsolutePeriodInfo absolutePeriodInfo =
    new VoucherAbsolutePeriodInfo();

absolutePeriodInfo.ValidBeginTime = "2026-10-01 00:00:00";
absolutePeriodInfo.ValidEndTime = "2026-12-31 23:59:59";

voucherUseTimeInfo.AbsolutePeriodInfo = absolutePeriodInfo;
voucherUseRuleInfo.VoucherUseTimeInfo = voucherUseTimeInfo;

// 当前接口场景不支持显式传入该参数。
// 不要设置:voucherUseRuleInfo.VoucherMaxUseTimes = 1;

model.VoucherUseRuleInfo = voucherUseRuleInfo;

这段修改只有在 SDK 不会自动将未赋值的 VoucherMaxUseTimes 序列化成 0 时才有效。如果请求日志中仍然能看到该字段,就需要继续调整 SDK 模型或序列化配置。

其他注意事项

  • 不要根据异常信息直接增加参数。如果先后出现“值不合法”和“字段不支持”,应先检查实际发送的请求报文。
  • 示例中的 2024-08-01 至 2024-12-31 已经过期。实际调用时,发放时间和券有效时间必须符合接口规则,否则删除该字段后仍可能收到日期相关错误。
  • VoucherCustomerGuideInfo 当前是空对象。如果没有引导信息,建议不要设置它,避免 SDK 发送 {} 后触发额外校验。
  • available_pids、券图片素材 ID、资金模式和商户接入模式也必须与实际签约能力一致。
  • 如果升级 SDK、将属性改为 nullable,并确认请求中已经没有该字段后,服务端仍返回同样的错误,应保存脱敏后的完整 biz_content、接口网关地址、SDK 版本和支付宝响应中的 sub_code/sub_msg,再联系支付宝开放平台技术支持,核对当前应用对应的接口版本和产品权限。

备注:内容仅供参考。