商户进件
特约商户进件
基础支付
JSAPI支付
APP支付
H5支付
Native支付
小程序支付
合单支付
付款码支付
经营能力
支付即服务
点金计划
行业方案
平台收付通
智慧商圈
微信支付分停车服务
电子发票
营销工具
代金券
商家券
委托营销
支付有礼
小程序发券插件
H5发券
图片上传(营销专用)
现金红包
资金应用
分账
连锁品牌分账
风险合规
商户开户意愿确认
消费者投诉2.0
商户平台处置通知
其他能力
图片上传
视频上传
微信支付平台证书

支付有礼开发指引

1. 接口规则

为了在保证支付安全的前提下,带给商户简单、一致且易用的开发体验,我们推出了全新的微信支付APIv3接口。该版本API的具体规则请参考“APIv3接口规则

2. 开发准备

2.1. 搭建和配置开发环境

为了帮助开发者调用开放接口,我们提供了JAVA、PHP、GO三种语言版本的开发库,封装了签名生成、签名验证、敏感信息加/解密、媒体文件上传等基础功能(更多语言版本的开发库将在近期陆续提供

测试步骤

1、根据自身开发语言,选择对应的开发库并构建项目,具体配置请参考下面链接的详细说明:

    • wechatpay-java(推荐)wechatpay-apache-httpclient,适用于Java开发者。

    • wechatpay-php(推荐)、wechatpay-guzzle-middleware,适用于PHP开发者

    注:当前开发指引接口PHP示例代码采用wechatpay-guzzle-middleware版本

    • wechatpay-go,适用于Go开发者

更多资源可前往微信支付开发者社区搜索查看

2、创建加载商户私钥、加载平台证书、初始化httpClient的通用方法


@Before
public void setup() throws IOException {
    // 加载商户私钥(privateKey:私钥字符串)
    PrivateKey merchantPrivateKey = PemUtil
            .loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
 
    // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
    AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
            new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes("utf-8"));
 
    // 初始化httpClient
    httpClient = WechatPayHttpClientBuilder.create()
            .withMerchant(mchId, mchSerialNo, merchantPrivateKey)
            .withValidator(new WechatPay2Validator(verifier)).build();
}
 
@After
public void after() throws IOException {
    httpClient.close();
}

use GuzzleHttp\Exception\RequestException;
use WechatPay\GuzzleMiddleware\WechatPayMiddleware;
use WechatPay\GuzzleMiddleware\Util\PemUtil;
use GuzzleHttp\HandlerStack;
 
// 商户相关配置,
$merchantId = '1000100'; // 商户号
$merchantSerialNumber = 'XXXXXXXXXX'; // 商户API证书序列号
$merchantPrivateKey = PemUtil::loadPrivateKey('./path/to/mch/private/key.pem'); // 商户私钥文件路径
 
// 微信支付平台配置
$wechatpayCertificate = PemUtil::loadCertificate('./path/to/wechatpay/cert.pem'); // 微信支付平台证书文件路径
 
// 构造一个WechatPayMiddleware
$wechatpayMiddleware = WechatPayMiddleware::builder()
    ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey) // 传入商户相关配置
    ->withWechatPay([ $wechatpayCertificate ]) // 可传入多个微信支付平台证书,参数类型为array
    ->build();
 
// 将WechatPayMiddleware添加到Guzzle的HandlerStack中
$stack = GuzzleHttp\HandlerStack::create();
$stack->push($wechatpayMiddleware, 'wechatpay');
 
// 创建Guzzle HTTP Client时,将HandlerStack传入,接下来,正常使用Guzzle发起API请求,WechatPayMiddleware会自动地处理签名和验签
$client = new GuzzleHttp\Client(['handler' => $stack]);

/*
    Package core 微信支付api v3 go http-client 基础库,你可以使用它来创建一个client,并向微信支付发送http请求
    只需要你在初始化客户端的时候,传递credential以及validator
    credential用来生成http header中的authorization信息
    validator则用来校验回包是否被篡改
    如果http请求返回的err为nil,一般response.Body 都不为空,你可以尝试对其进行序列化
    请注意及时关闭response.Body
    注意:使用微信支付apiv3 go库需要引入相关的包,该示例代码必须引入的包名有以下信息

    "context"
    "crypto/x509"
    "fmt"
    "io/ioutil"
    "log"
    "github.com/wechatpay-apiv3/wechatpay-go/core"
    "github.com/wechatpay-apiv3/wechatpay-go/core/option"
    "github.com/wechatpay-apiv3/wechatpay-go/utils"

    */
func SetUp() (opt []option.ClientOption, err error) {
    //商户号
    mchID := ""
    //商户证书序列号
    mchCertSerialNumber := ""
    //商户私钥文件路径
    privateKeyPath := ""
    //平台证书文件路径
    wechatCertificatePath := ""

    // 加载商户私钥
    privateKey, err := utils.LoadPrivateKeyWithPath(privateKeyPath)
    if err != nil {
        log.Printf("load private err:%s", err.Error())
        return nil, err
    }
    // 加载微信支付平台证书
    wechatPayCertificate, err := utils.LoadCertificateWithPath(wechatCertificatePath)
    if err != nil {
        log.Printf("load certificate err:%s",err)
        return nil, err
    }
    //设置header头中authorization信息
    opts := []option.ClientOption{
        option.WithMerchant(mchID, mchCertSerialNumber, privateKey), // 设置商户相关配置
        option.WithWechatPay([]*x509.Certificate{wechatPayCertificate}), // 设置微信支付平台证书,用于校验回包信息用
    }
    return opts, nil
}

3、基于接口的示例代码,替换请求参数后可发起测试

说明:

• 上面的开发库为微信支付官方开发库,其它没有审核或者控制下的第三方工具和库,微信支付不保证它们的安全性和可靠性

通过包管理工具引入SDK后,可根据下面每个接口的示例代码替换相关参数后进行快速测试

开发者如果想详细了解签名生成、签名验证、敏感信息加/解密、媒体文件上传等常用方法的具体代码实现,可阅读下面的详细说明:

    1.签名生成

    2.签名验证

    3.敏感信息加解密

    4.merchantPrivateKey(私钥)

    5.wechatpayCertificates(平台证书)

    6.APIV3Key(V3 key)

如想更详细的了解我们的接口规则,可查看我们的接口规则指引文档

3. 快速接入

3.1. 业务流程图

业务流程时序图:

重点步骤说明:

步骤5 商户创建商家券后,可通过创建全场满额送活动接口创建支付有礼活动,微信支付生成支付有礼活动并返回活动ID给到商户。

步骤20 支付有礼活动创建后,商户可通过《查询活动详情接口》查询管理活动。

步骤22 活动创建后,如需结束活动,可通过《终止活动》接口,结束活动。

3.2. API接入(含示例代码)

文档展示了如何使用微信支付服务端 SDK 快速接入支付有礼,完成与微信支付对接的部分。

注意

  • 文档中的代码示例是用来阐述 API 基本使用方法,代码中的示例参数需替换成商户自己账号及请求参数才能跑通
  • 以下接入步骤仅提供参考,请商户结合自身业务需求进行评估、修改。
3.2.1. 【服务端】创建全场满额送活动

步骤说明:服务商可以创建满额送活动,用户支付后送全场券,提升交易额。

示例代码


public void CreateActivity() throws Exception{
    //请求URL
    HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/unique-threshold-activity");
    // 请求body参数
    String reqdata = "{"
            + "\"activity_base_info\": {"
            + "\"activity_name\":\"良品铺子回馈活动\","
            + "\"activity_second_title\":\"海飞丝的券\","
            + "\"merchant_logo_url\":\"https://tool.oschina.net/regex.jpg\","
            + "\"background_color\":\"COLOR010\","
            + "\"begin_time\":\"2015-05-20T13:29:35+08:00\","
            + "\"end_time\":\"2015-05-20T13:29:35+08:00\","
            + "\"available_periods\": {"
            + "\"available_time\": ["
            + "{"
            + "\"begin_time\":\"2015-05-20T00:00:00+08:00\","
            + "\"end_time\":\"2015-05-20T23:59:59+08:00\""
            + "}"
            + "],"
            + "\"available_day_time\": ["
            + "{"
            + "\"begin_day_time\":\"110000\","
            + "\"end_day_time\":\"135959\""
            + "}"
            + "]"
            + "},"
            + "\"out_request_no\":\"100002322019090134234sfdf\","
            + "\"delivery_purpose\":\"OFF_LINE_PAY\","
            + "\"mini_programs_appid\":\"wx23232232323\","
            + "\"mini_programs_path\":\"/path/index/index\""
            + "},"
            + "\"award_send_rule\": {"
            + "\"transaction_amount_minimum\":100,"
            + "\"send_content\":\"SINGLE_COUPON\","
            + "\"award_type\":\"BUSIFAVOR\","
            + "\"award_list\": ["
            + "{"
            + "\"stock_id\":\"98065001\","
            + "\"original_image_url\":\"https://tool.oschina.net/regex.jpg\","
            + "\"thumbnail_url\":\"https://tool.oschina.net/regex.jpg\""
            + "}"
            + "],"
            + "\"merchant_option\":\"MANUAL_INPUT_MERCHANT\","
            + "\"merchant_id_list\": ["
            + "\"0\":\"10000022\","
            + "\"1\":\"10000023\""
            + "]"
            + "},"
            + "\"advanced_setting\": {"
            + "\"delivery_user_category\":\"DELIVERY_MEMBER_PERSON\","
            + "\"merchant_member_appid\":\"34567890\","
            + "\"goods_tags\": ["
            + "\"0\":\"xxx\","
            + "\"1\":\"yyy\""
            + "]"
            + "}"
            + "}";
    StringEntity entity = new StringEntity(reqdata,"utf-8");
    entity.setContentType("application/json");
    httpPost.setEntity(entity);
    httpPost.setHeader("Accept", "application/json");

    //完成签名并执行请求
    CloseableHttpResponse response = httpClient.execute(httpPost);

    try {
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) { //处理成功
            System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
        } else if (statusCode == 204) { //处理成功,无返回Body
            System.out.println("success");
        } else {
            System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
            throw new IOException("request failed");
        }
    } finally {
        response.close();
    }
} 

try {
    $resp = $client->request(
        'POST',
        'https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/unique-threshold-activity', //请求URL
        [
            // JSON请求体
            'json' => [
                "activity_base_info" => [
                    "activity_name" => "良品铺子回馈活动", 
                    "activity_second_title" => "海飞丝的券", 
                    "merchant_logo_url" => "https://tool.oschina.net/regex.jpg", 
                    "background_color" => "COLOR010", 
                    "begin_time" => "2015-05-20T13:29:35+08:00", 
                    "end_time" => "2015-05-20T13:29:35+08:00", 
                    "available_periods" => [
                        "available_time" => [
                            [
                                "begin_time" => "2015-05-20T00:00:00+08:00", 
                                "end_time" => "2015-05-20T23:59:59+08:00", 
                            ],
                        ],
                        "available_day_time" => [
                            [
                                "begin_day_time" => "110000", 
                                "end_day_time" => "135959", 
                            ],
                        ],
                    ],
                    "out_request_no" => "100002322019090134234sfdf", 
                    "delivery_purpose" => "OFF_LINE_PAY", 
                    "mini_programs_appid" => "wx23232232323", 
                    "mini_programs_path" => "/path/index/index", 
                ],
                "award_send_rule" => [
                    "transaction_amount_minimum" => 100, 
                    "send_content" => "SINGLE_COUPON", 
                    "award_type" => "BUSIFAVOR", 
                    "award_list" => [
                        [
                            "stock_id" => "98065001", 
                            "original_image_url" => "https://tool.oschina.net/regex.jpg", 
                            "thumbnail_url" => "https://tool.oschina.net/regex.jpg", 
                        ],
                    ],
                    "merchant_option" => "MANUAL_INPUT_MERCHANT", 
                    "merchant_id_list" => [
                        "0" => "10000022", 
                        "1" => "10000023", 
                    ],
                ],
                "advanced_setting" => [
                    "delivery_user_category" => "DELIVERY_MEMBER_PERSON", 
                    "merchant_member_appid" => "34567890", 
                    "goods_tags" => [
                        "0" => "xxx", 
                        "1" => "yyy", 
                    ],
                ]
            ],
            'headers' => [ 'Accept' => 'application/json' ]
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //处理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //处理成功,无返回Body
        echo "success";
    }
} catch (RequestException $e) {
    // 进行错误处理
    echo $e->getMessage()."\n";
    if ($e->hasResponse()) {
        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
    }
    return;
}
      

func CreateActivity() {
       // 初始化客户端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
  //设置请求地址
  URL := "https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/unique-threshold-activity"
  //设置请求信息,此处也可以使用结构体来进行请求
  mapInfo := map[string]interface{}{
    "activity_base_info": map[string]interface{}{
      "activity_name": "良品铺子回馈活动",
      "activity_second_title": "海飞丝的券",
      "merchant_logo_url": "https://tool.oschina.net/regex.jpg",
      "background_color": "COLOR010",
      "begin_time": "2015-05-20T13:29:35+08:00",
      "end_time": "2015-05-20T13:29:35+08:00",
      "available_periods": map[string]interface{}{
        "available_time": [...]interface{}{
          map[string]interface{}{
            "begin_time": "2015-05-20T00:00:00+08:00",
            "end_time": "2015-05-20T23:59:59+08:00",
       },
      },
        "available_day_time": [...]interface{}{
          map[string]interface{}{
            "begin_day_time": "110000",
            "end_day_time": "135959",
       },
      },
     },
      "out_request_no": "100002322019090134234sfdf",
      "delivery_purpose": "OFF_LINE_PAY",
      "mini_programs_appid": "wx23232232323",
      "mini_programs_path": "/path/index/index",
    },
    "award_send_rule": map[string]interface{}{
      "transaction_amount_minimum": 100,
      "send_content": "SINGLE_COUPON",
      "award_type": "BUSIFAVOR",
      "award_list": [...]interface{}{
        map[string]interface{}{
          "stock_id": "98065001",
          "original_image_url": "https://tool.oschina.net/regex.jpg",
          "thumbnail_url": "https://tool.oschina.net/regex.jpg",
      },
     },
      "merchant_option": "MANUAL_INPUT_MERCHANT",
      "merchant_id_list": [...]interface{}{
        "10000022",
        "10000023",
     },
    },
    "advanced_setting": map[string]interface{}{
      "delivery_user_category": "DELIVERY_MEMBER_PERSON",
      "merchant_member_appid": "34567890",
      "goods_tags": [...]interface{}{
        "xxx",
        "yyy",
     },
    },
  }

  // 发起请求
  response, err := client.Post(ctx, URL, mapInfo)
  if err != nil{
    log.Printf("client post err:%s",err)
    return
  }
  // 校验回包内容是否有逻辑错误
  err = core.CheckResponse(response)
  if err != nil{
    log.Printf("check response err:%s",err)
    return
  }
  // 读取回包信息
  body, err := ioutil.ReadAll(response.Body)
  if err != nil{
    log.Printf("read response body err:%s",err)
    return
  }
  fmt.Println(string(body))
}

    

重要入参说明

activity_name:活动名称

activity_second_title:活动副标题

merchant_logo_url:商户logo,送出优惠券时展示, 仅支持通过《图片上传API》接口获取的图片URL地址。

out_request_no:商户请求单号,商户创建批次凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性,可包含英文字母,数字,|,_,*,-等内容,不允许出现其他不合法符号。

delivery_purpose:投放目的。枚举值:

OFF_LINE_PAY:拉用户回店消费
JUMP_MINI_APP:引导用户前往小程序消费

• send_content:发放内容,可选单张券或礼包,选礼包时奖品限定3-5个。枚举值:

SINGLE_COUPON:单张券
GIFT_PACKAGE:礼包

注意

更多参数、响应详情及错误码请参见创建全场满额送活动接口文档

3.2.2. 【服务端】查询活动详情接口

步骤说明:服务商创建活动后,可以通过该接口查询支付有礼的活动详情,用于管理活动。

示例代码


public void QueryActivity() throws Exception{
    //请求URL
    HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001");
    httpGet.setHeader("Accept", "application/json");

    //完成签名并执行请求
    CloseableHttpResponse response = httpClient.execute(httpGet);

    try {
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) { //处理成功
            System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
        } else if (statusCode == 204) { //处理成功,无返回Body
            System.out.println("success");
        } else {
            System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
            throw new IOException("request failed");
        }
    } finally {
        response.close();
    }
} 

try {
    $resp = $client->request(
        'GET',
        'https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001', //请求URL
        [
            'headers' => [ 'Accept' => 'application/json']
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //处理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //处理成功,无返回Body
        echo "success";
    }
} catch (RequestException $e) {
    // 进行错误处理
    echo $e->getMessage()."\n";
    if ($e->hasResponse()) {
        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
    }
    return;
}
      

func QueryActivity() {
       // 初始化客户端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
  //设置请求地址
   URL := "https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001"
  // 发起请求
  response, err := client.Get(ctx, URL)
  if err != nil{
    log.Printf("client get err:%s",err)
    return
  }
  // 校验回包内容是否有逻辑错误
  err = core.CheckResponse(response)
  if err != nil{
    log.Printf("check response err:%s",err)
    return
  }
  // 读取回包信息
  body, err := ioutil.ReadAll(response.Body)
  if err != nil{
    log.Printf("read response body err:%s",err)
    return
  }
  fmt.Println(string(body))
}
    

重要入参说明

activity_id:活动id

注意

更多参数、响应详情及错误码请参见查询活动详情接口文档

3.2.3. 【服务端】查询活动发券商户号

步骤说明:服务商创建活动后,可以通过该接口查询支付有礼的发券商户号,用于管理活动。

示例代码


public void QueryActivityMch() throws Exception{
    //请求URL
    HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001/merchants");
    httpGet.setHeader("Accept", "application/json");

    //完成签名并执行请求
    CloseableHttpResponse response = httpClient.execute(httpGet);

    try {
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) { //处理成功
            System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
        } else if (statusCode == 204) { //处理成功,无返回Body
            System.out.println("success");
        } else {
            System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
            throw new IOException("request failed");
        }
    } finally {
        response.close();
    }
}

try {
    $resp = $client->request(
        'GET',
        'https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001/merchants', //请求URL
        [
            'headers' => [ 'Accept' => 'application/json']
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //处理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //处理成功,无返回Body
        echo "success";
    }
} catch (RequestException $e) {
    // 进行错误处理
    echo $e->getMessage()."\n";
    if ($e->hasResponse()) {
        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
    }
    return;
}
      

func QueryActivityMch() {
       // 初始化客户端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
    //设置请求地址
   URL := "https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001/merchants?offset=1&limit=20"
  // 发起请求
  response, err := client.Get(ctx, URL)
  if err != nil{
    log.Printf("client get err:%s",err)
    return
  }
  // 校验回包内容是否有逻辑错误
  err = core.CheckResponse(response)
  if err != nil{
    log.Printf("check response err:%s",err)
    return
  }
  // 读取回包信息
  body, err := ioutil.ReadAll(response.Body)
  if err != nil{
    log.Printf("read response body err:%s",err)
    return
  }
  fmt.Println(string(body))
}
    

重要入参说明

activity_id:活动id

注意

更多参数、响应详情及错误码请参见查询活动发券商户号接口文档

3.2.4. 【服务端】查询活动指定商品列表

步骤说明:服务商创建活动后,可以通过该接口查询支付有礼的活动指定商品,用于管理活动。

示例代码


public void QueryActivityGoods() throws Exception{
    //请求URL
    HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001/goods");
    httpGet.setHeader("Accept", "application/json");

    //完成签名并执行请求
    CloseableHttpResponse response = httpClient.execute(httpGet);

    try {
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) { //处理成功
            System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
        } else if (statusCode == 204) { //处理成功,无返回Body
            System.out.println("success");
        } else {
            System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
            throw new IOException("request failed");
        }
    } finally {
        response.close();
    }
} 

try {
    $resp = $client->request(
        'GET',
        'https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001/goods', //请求URL
        [
            'headers' => [ 'Accept' => 'application/json']
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //处理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //处理成功,无返回Body
        echo "success";
    }
} catch (RequestException $e) {
    // 进行错误处理
    echo $e->getMessage()."\n";
    if ($e->hasResponse()) {
        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
    }
    return;
}
      

func QueryActivityGoods() {
       // 初始化客户端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
  //设置请求地址
  URL := "https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001/goods?offset=1&limit=20"
  // 发起请求
  response, err := client.Get(ctx, URL)
  if err != nil{
    log.Printf("client get err:%s",err)
    return
  }
  // 校验回包内容是否有逻辑错误
  err = core.CheckResponse(response)
  if err != nil{
    log.Printf("check response err:%s",err)
    return
  }
  // 读取回包信息
  body, err := ioutil.ReadAll(response.Body)
  if err != nil{
    log.Printf("read response body err:%s",err)
    return
  }
  fmt.Println(string(body))
}
    

重要入参说明

activity_id:活动id

注意

更多参数、响应详情及错误码请参见查询活动指定商品列表接口文档

3.2.5. 【服务端】终止活动

步骤说明:服务商可通过该接口停止支付有礼活动。

示例代码


public void TerminateActivity() throws Exception{
    //请求URL
    HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001/terminate");
    // 请求body参数
    String reqdata ="";
    StringEntity entity = new StringEntity(reqdata,"utf-8");
    entity.setContentType("application/json");
    httpPost.setEntity(entity);
    httpPost.setHeader("Accept", "application/json");

    //完成签名并执行请求
    CloseableHttpResponse response = httpClient.execute(httpPost);

    try {
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) { //处理成功
            System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
        } else if (statusCode == 204) { //处理成功,无返回Body
            System.out.println("success");
        } else {
            System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
            throw new IOException("request failed");
        }
    } finally {
        response.close();
    }
} 

try {
    $resp = $client->request(
        'POST',
        'https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001/terminate', //请求URL
         [
            'headers' => [ 
                'Accept' => 'application/json',
                'Content-Type'=>'application/json'
            ]
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //处理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //处理成功,无返回Body
        echo "success";
    }
} catch (RequestException $e) {
    // 进行错误处理
    echo $e->getMessage()."\n";
    if ($e->hasResponse()) {
        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
    }
    return;
}
      

func TerminateActivity() {
       // 初始化客户端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
  //设置请求地址
  URL := "https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/{activity_id}/terminate"
  //设置请求信息,此处也可以使用结构体来进行请求
  mapInfo := map[string]interface{}{}

  // 发起请求
  response, err := client.Post(ctx, URL, mapInfo)
  if err != nil{
    log.Printf("client post err:%s",err)
    return
  }
  // 校验回包内容是否有逻辑错误
  err = core.CheckResponse(response)
  if err != nil{
    log.Printf("check response err:%s",err)
    return
  }
  // 读取回包信息
  body, err := ioutil.ReadAll(response.Body)
  if err != nil{
    log.Printf("read response body err:%s",err)
    return
  }
  fmt.Println(string(body))
}

    

重要入参说明

activity_id:活动id

注意

更多参数、响应详情及错误码请参见终止活动接口文档

3.2.6. 【服务端】新增活动发券商户号

步骤说明:服务商创建活动后,可以通过该接口增加支付有礼的发券商户号,用于管理活动。

示例代码


public void GetActivityList() throws Exception{
  // 加载商户私钥(privateKey:私钥字符串)
  PrivateKey merchantPrivateKey = PemUtil
          .loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));

  // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3秘钥)
  AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
          new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes("utf-8"));

  CloseableHttpClient httpClient = HttpClients.createDefault();
  // 初始化httpClient
  httpClient = WechatPayHttpClientBuilder.create()
          .withMerchant(mchId, mchSerialNo, merchantPrivateKey)
          .withValidator(new WechatPay2Validator(verifier)).build();

  //请求URL
  HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001/merchants/add");
  // 请求body参数
  String reqdata = "{"
          + "\"merchant_id_list\": ["
          + "\"100123456\","
          + "\"100123457\""
          + "],"
          + "\"add_request_no\":\"100002322019090134234sfdf\""
          + "}";
  StringEntity entity = new StringEntity(reqdata,"utf-8");
  entity.setContentType("application/json");
  httpPost.setEntity(entity);
  httpPost.setHeader("Accept", "application/json");

  //完成签名并执行请求
  CloseableHttpResponse response = httpClient.execute(httpPost);

  try {
      int statusCode = response.getStatusLine().getStatusCode();
      if (statusCode == 200) { //处理成功
          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
      } else if (statusCode == 204) { //处理成功,无返回Body
          System.out.println("success");
      } else {
          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
          throw new IOException("request failed");
      }
  } finally {
      response.close();
  }
} 

try {
    $resp = $client->request(
        'POST',
        'https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001/merchants/add', //请求URL
        [
            // JSON请求体
            'json' => [
                "merchant_id_list" => [
                    "0" => "100123456", 
                    "1" => "100123457", 
                ],
                "add_request_no" => "100002322019090134234sfdf",
            ],
            'headers' => [ 'Accept' => 'application/json' ]
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //处理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //处理成功,无返回Body
        echo "success";
    }
} catch (RequestException $e) {
    // 进行错误处理
    echo $e->getMessage()."\n";
    if ($e->hasResponse()) {
        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
    }
    return;
}
      

func GetActivityList() {
       // 初始化客户端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
  //设置请求地址
  URL := "https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/10028001/merchants/add"
  //设置请求信息,此处也可以使用结构体来进行请求
  mapInfo := map[string]interface{}{
    "merchant_id_list": [...]interface{}{
      "100123456",
      "100123457",
    },
    "add_request_no": "100002322019090134234sfdf",
  }

  // 发起请求
  response, err := client.Post(ctx, URL, mapInfo)
  if err != nil{
    log.Printf("client post err:%s",err)
    return
  }
  // 校验回包内容是否有逻辑错误
  err = core.CheckResponse(response)
  if err != nil{
    log.Printf("check response err:%s",err)
    return
  }
  // 读取回包信息
  body, err := ioutil.ReadAll(response.Body)
  if err != nil{
    log.Printf("read response body err:%s",err)
    return
  }
  fmt.Println(string(body))
}

    

重要入参说明

activity_id:活动id

add_request_no:请求业务单据号,商户添加发券商户号的凭据号,商户侧需保持唯一性

注意

更多参数、响应详情及错误码请参见新增活动发券商户号接口文档

3.2.7. 【服务端】获取支付有礼活动列表

步骤说明:服务商根据一定过滤条件,查询已创建的支付有礼活动。

示例代码


public void GetActivityList() throws Exception{
  // 加载商户私钥(privateKey:私钥字符串)
  PrivateKey merchantPrivateKey = PemUtil
          .loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));

  // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3秘钥)
  AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
          new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes("utf-8"));

  CloseableHttpClient httpClient = HttpClients.createDefault();
  // 初始化httpClient
  httpClient = WechatPayHttpClientBuilder.create()
          .withMerchant(mchId, mchSerialNo, merchantPrivateKey)
          .withValidator(new WechatPay2Validator(verifier)).build();

  //请求URL
  HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities?offset=0&limit=10&activity_status=ONGOING_ACT_STATUS");
  httpGet.setHeader("Accept", "application/json");

  //完成签名并执行请求
  CloseableHttpResponse response = httpClient.execute(httpGet);

  try {
      int statusCode = response.getStatusLine().getStatusCode();
      if (statusCode == 200) { //处理成功
          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
      } else if (statusCode == 204) { //处理成功,无返回Body
          System.out.println("success");
      } else {
          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
          throw new IOException("request failed");
      }
  } finally {
      response.close();
  }
}

try {
    $resp = $client->request(
        'GET',
        'https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities?offset=0&limit=10&activity_status=ONGOING_ACT_STATUS', //请求URL
        [
            'headers' => [ 'Accept' => 'application/json']
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //处理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //处理成功,无返回Body
        echo "success";
    }
} catch (RequestException $e) {
    // 进行错误处理
    echo $e->getMessage()."\n";
    if ($e->hasResponse()) {
        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
    }
    return;
}
      

func GetActivityList() {
       // 初始化客户端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
  //设置请求地址
  URL := "https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities?offset=0&limit=10&activity_status=ONGOING_ACT_STATUS"
  // 发起请求
  response, err := client.Get(ctx, URL)
  if err != nil{
    log.Printf("client get err:%s",err)
    return
  }
  // 校验回包内容是否有逻辑错误
  err = core.CheckResponse(response)
  if err != nil{
    log.Printf("check response err:%s",err)
    return
  }
  // 读取回包信息
  body, err := ioutil.ReadAll(response.Body)
  if err != nil{
    log.Printf("read response body err:%s",err)
    return
  }
  fmt.Println(string(body))
}
    

重要入参说明

offset:分页页码,页面从0开始

limit:分页大小。特殊规则:最大取值为100,最小为1

注意

更多参数、响应详情及错误码请参见获取支付有礼活动列表接口文档

3.2.8. 【服务端】删除活动发券商户号

步骤说明:服务商创建活动后,可以通过该接口删除支付有礼的发券商户号,用于管理活动。

示例代码


public void DelActivityMch() throws Exception{
  // 加载商户私钥(privateKey:私钥字符串)
  PrivateKey merchantPrivateKey = PemUtil
          .loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));

  // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3秘钥)
  AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
          new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes("utf-8"));

  CloseableHttpClient httpClient = HttpClients.createDefault();
  // 初始化httpClient
  httpClient = WechatPayHttpClientBuilder.create()
          .withMerchant(mchId, mchSerialNo, merchantPrivateKey)
          .withValidator(new WechatPay2Validator(verifier)).build();

  //请求URL
  HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/126002309/merchants/delete");
  // 请求body参数
  String reqdata = "{"
          + "\"merchant_id_list\": ["
          + "\"100123456\","
          + "\"100123457\""
          + "],"
          + "\"delete_request_no\":\"100002322019090134234sfdf\""
          + "}";
  StringEntity entity = new StringEntity(reqdata,"utf-8");
  entity.setContentType("application/json");
  httpPost.setEntity(entity);
  httpPost.setHeader("Accept", "application/json");

  //完成签名并执行请求
  CloseableHttpResponse response = httpClient.execute(httpPost);

  try {
      int statusCode = response.getStatusLine().getStatusCode();
      if (statusCode == 200) { //处理成功
          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
      } else if (statusCode == 204) { //处理成功,无返回Body
          System.out.println("success");
      } else {
          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
          throw new IOException("request failed");
      }
  } finally {
      response.close();
  }
}  

try {
    $resp = $client->request(
        'POST',
        'https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/126002309/merchants/delete', //请求URL
        [
            // JSON请求体
            'json' => [
                "merchant_id_list" => [
                    "0" => "100123456", 
                    "1" => "100123457", 
                ],
                "delete_request_no" => "100002322019090134234sfdf",
            ],
            'headers' => [ 'Accept' => 'application/json' ]
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //处理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //处理成功,无返回Body
        echo "success";
    }
} catch (RequestException $e) {
    // 进行错误处理
    echo $e->getMessage()."\n";
    if ($e->hasResponse()) {
        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
    }
    return;
}
      

func DelActivityMch() {
       // 初始化客户端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
  //设置请求地址
  URL := "https://api.mch.weixin.qq.com/v3/marketing/paygiftactivity/activities/126002309/merchants/delete"
  //设置请求信息,此处也可以使用结构体来进行请求
  mapInfo := map[string]interface{}{
    "merchant_id_list": [...]interface{}{
      "100123456",
      "100123457",
    },
    "delete_request_no": "100002322019090134234sfdf",
  }

  // 发起请求
  response, err := client.Post(ctx, URL, mapInfo)
  if err != nil{
    log.Printf("client post err:%s",err)
    return
  }
  // 校验回包内容是否有逻辑错误
  err = core.CheckResponse(response)
  if err != nil{
    log.Printf("check response err:%s",err)
    return
  }
  // 读取回包信息
  body, err := ioutil.ReadAll(response.Body)
  if err != nil{
    log.Printf("read response body err:%s",err)
    return
  }
  fmt.Println(string(body))
}
    

重要入参说明

activity_id:活动id

注意

更多参数、响应详情及错误码请参见删除活动发券商户号接口文档

4. 常见问题

Q1:支付有礼创建全场满额送活动API返回“发券商户号校验失败,请核实是否满足同品牌等规则”

A1:支付有礼活动的曝光商户号必须是商家券归属商户号的同品牌。同品牌商户号是指同一企业/集团/品牌/公司旗下,如果存在多个微信支付商户号,该企业/集团/品牌/公司可以授权财付通支付科技有限公司将其旗下的多个商户号创建为同品牌商户号组合。主要用于更便利使用免充值营销产品功能,包括开通产品权限、配置组合内商户号为可用商户、配置活动后可用商户免审核等

Q2:支付有礼创建全场满额送活动API返回“商家券信息不满足活动规则,请核实券有效期或code”

A2:支付有礼中投放批次的校验,请按照以下几点排查

1. 单张券/券包中所有的券开始时间需早于支付有礼活动的开始时间,结束时间需晚于支付有礼的结束时间
2. 如果批次为上传code模式,需先上传code再投放到支付有礼
3. 添加券包时,库存、限领和归属商户号需要保持一致
4. 曝光商户号、批次的归属商户号需要全部为同品牌,创建活动的商户号为服务商时,需要是曝光/归属商户号的父商户

Q3:支付有礼创建全场满额送活动API,开始时间和结束时间描述的“最长可以配置1年内的活动”中的“1年”如何计算?

A3:间隔需要小于31536000s,即需要小于365天

Q4:支付有礼创建全场满额送活动API上传了merchant_id_list字段,接着调用了获取支付有礼活动列表API,并没有merchant_id_list返回,该字段在什么情况下才返回?

A4:查询活动发券商户号API才会有这个字段返回,接口文档地址

Q5:支付有礼发放商家券,用户领券没有收到领券事件通知openid

A5:请检查对应的批次,调用创建商家券接口时是否有设置事件通知APPID参数(notify_appid)



技术咨询

文档反馈