# 微信小程序团购服务 — 商家接入指引

商家通过 POI 挂载「团购优惠」服务，需完成以下核心步骤：

1. 认领微信位置及关联小程序：[微信位置运营 | 微信开放文档](wxpoi/)
2. 挂载团购服务：**规范团购下单页路径 → 接入退款能力 → 接入核销组件 → 创建服务 → 授权账期管理**。

通过审核后，你的微信位置页将展示「团购优惠」入口，点击后可跳转至团购页面。未完成审核挂载前，可先使用核销组件的调试预览模式完成组件开发和审核截图准备。

## 一、规范团购页面路径

1. 区分两种页面路径

| 路径类型 | 用途 | 填写建议 |
| - | - | - |
| 服务页面路径 | 用户在 POI 页点击「团购优惠」后进入的小程序页面 | 多个套餐可填团购列表页；只推广一个套餐可填该套餐详情页 |
| 团购下单页面路径 | 平台识别团购订单所使用的统一支付页路径 | 所有套餐共用一个页面路径，通过不同参数区分套餐 |

2. 统一团购下单页面路径

平台通过「团购下单页面路径（path）」来识别哪些订单属于团购订单。因此你需要确保：小程序内所有团购套餐的下单页面，都必须通过参数挂载在同一个页面路径下。

![](https://res8.wxqcloud.qq.com.cn/wxdoc/f6aa80b0-936b-432d-977c-2e349ee13cf6.png)

**正确示例：**

提审填写的团购下单页面路径为：`page/groupbuy/pay`

- 套餐 A 的下单链接：`page/groupbuy/pay?id=283` ✅ 正确
- 套餐 B 的下单链接：`page/groupbuy/pay?id=456` ✅ 正确

**错误示例：**

- 套餐 C 的下单链接：`page/shopping/pay?id=789` ❌ 路径不一致，无法识别

> 注意：如果有团购套餐的下单页不在提审路径下，审核将被驳回。

**新增套餐怎么办？**

新增团购套餐只需通过不同的参数（如 `?id=新ID`）挂载在同一个页面路径下即可，无需重新提审。

## 二、接入退款能力（随时退 & 过期退）

为保障消费者权益，商家必须接入平台提供的[退款接口](https://pay.weixin.qq.com/doc/v3/merchant/4012791862)，实现以下两种退款能力：

| 退款类型 | 说明                                   | 商家需做                                           |
| -------- | -------------------------------------- | -------------------------------------------------- |
| 随时退   | 用户在有效期内未核销，可随时申请退款   | 在购买成功页面提供退款入口，用户申请后调用退款接口 |
| 过期退   | 团购券超过有效期未核销，自动退款给用户 | 根据有效期字段，到期后需商家调用退款接口退款       |

**页面要求：**

- 团购详情页需展示「随时退」「过期退」标识
- 支付成功后的订单详情页需包含「申请退款」入口

## 三、接入核销组件

平台提供标准化的「用户二次确认核销组件」，确保用户到店消费时可安全核销。

用户在组件中确认后，平台侧完成核销确认并进入资金解冻流程；商户侧订单是否已核销，仍由商户扫码及自己的订单系统管理。

**1. 请求核销接口：**

开发者可通过调用 `wx.openBusinessView` 方式在本小程序打开团购核销组件，让用户完成团购券确认核销操作。

通过审核并正式挂载到 POI 前，订单尚不能按团购订单识别，直接请求核销可能报错或使组件静默关闭。此阶段请通过调试预览模式完成联调并获取审核截图，请查看**调试预览模式章节**了解。

**核销接口参数**

| 属性 | 类型 | 必填 | 说明 |
| - | - | - | - |
| `businessType` | string | 是 | 固定配置：`weappOrderConfirm` |
| `extraData` | object | 是 | 用于向组件传递团购核销信息；通过 `transaction_id` 唯一指定订单，通过 `group_buy_item` 传递团购商品详情。 |

`extraData` 字段：

| 属性 | 类型 | 必填 | 说明 |
| - | - | - | - |
| `transaction_id` | string | 是 | 真实的用户交易单号。正式核销和调试预览都需要传入真实订单，调试模式可以传入任意类型的真实订单，正式核销场景需要传入真实团购订单，否则会返回失败信息。 |
| `group_buy_item` | GroupBuyItem | 是 | 团购商品详情，见下方数据结构说明 |

**GroupBuyItem 数据结构**

`group_buy_item` 为团购商品详情，由开发者组装并通过 `extraData` 传入，包含团购券信息 `coupon` 和套餐分组 `packages` 两部分。

coupon 团购券信息：

| 属性 | 类型 | 必填 | 说明 | 示例 |
| - | - | - | - | - |
| `name` | string | 是 | 团购名称，≤ 30 字 | `'【双人实惠】烤全鱼双人餐'` |
| `quantity` | number | 是 | 券数量，≥ 1；多券时一次性全部核销，不支持部分核销 | `1` |
| `original_price` | number | 是 | 原价，单位为分；必须 ≥ 实付金额 | `29800` |
| `paid_amount` | number | 是 | 实付金额，单位为分；需与订单实际支付金额一致 | `19900` |
| `valid_until` | number | 是 | 有效期至，Unix 时间戳（秒级）；过期后核销将返回失败 | `1788769682` |

packages 套餐分组：

| 属性 | 类型 | 必填 | 说明 | 示例 |
| - | - | - | - | - |
| `group_name` | string | 是 | 分组名称，≤ 20 字 | `'招牌'` / `'小食'` |
| `select_type` | number | 是 | `1`=固定包含，`2`=N 选 1，`3`=N 选几；仅用于展示，用户无需选择 | `1` |
| `select_count` | number | 否 | `select_type=3` 时必填，表示可选数量；必须小于本组餐品总数 | `2` |
| `items` | PackageItem[] | 是 | 分组下的餐品列表 | `[{ name: '烤全鱼', quantity: 1 }]` |

PackageItem 餐品信息：

| 属性 | 类型 | 必填 | 说明 | 示例 |
| - | - | - | - | - |
| `name` | string | 是 | 餐品名称，只填写菜品名称，≤ 30 字 | `'烤全鱼'` |
| `quantity` | number | 是 | 份数，≥ 1 | `1` |

**核销组件回调**

组件通过 `wx.navigateBackMiniProgram` 回调小程序，开发者可以通过 `App.onShow` 处理回调参数。

回调参数位于 `referrerInfo`，其中 `appId` 固定为 `wx1183b055aeec94d1`，`extraData` 定义如下：

| 属性 | 类型 | 必填 | 说明 |
| - | - | - | - |
| `status` | string | 是 | `success`：核销成功/预览模拟成功；`fail`：组件内查单、参数校验或核销失败；`cancel`：用户取消 |
| `errormsg` | string | 否 | 当 `status=fail` 时返回具体失败原因 |
| `req_extradata` | any | 是 | 开发者调用组件时传入的完整原始 `extraData`，原样返回 |

**常见组件内业务结果**

以下结果均表示组件已经成功拉起，调用方通过 `App.onShow` 接收回调。`页面表现` 描述的是组件内用户看到的内容。

| 场景 | `status` | `errormsg` | 页面表现 |
| - | - | - | - |
| 缺少有效订单号 | `fail` | `invalid order info` | 提示「无有效订单信息」 |
| 未查询到对应订单 | `fail` | `order not found` | 提示「获取用户订单失败」，请先检查对应商户号是否已完成账期授权。 |
| 缺少 `group_buy_item` | `fail` | `missing group_buy_item` | 提示「团购订单缺少商品信息」 |
| `group_buy_item` 结构无效 | `fail` | `invalid group_buy_item` | 提示「团购商品信息无效」 |
| 正式模式传入团购参数但查到非团购订单 | `fail` | `not groupbuy order` | 静默关闭，不展示 Toast，建议开发者自行衔接原有展码页面 |
| 实付金额不一致 | `fail` | `paid_amount mismatch` | 提示「传入的实付金额与微信支付订单实付金额不一致，无法发起核销」 |
| 团购券已过期 | `fail` | `coupon expired` | 提示「团购券已过期」 |
| 团购券已核销 | `fail` | `already verified` | 提示「该团购券已核销」 |
| 正式核销接口返回成功 | `success` | 无 | 提示「核销成功」 |
| 用户关闭主半屏 | `cancel` | 无 | 直接关闭 |

需注意：非调试模式下，如果传入了 `group_buy_item`，但真实订单不是**团购订单**，组件会静默关闭并返回，开发者需要自行处理**非团购订单场景**的后续逻辑，建议自行衔接原有展码流程。开发者可以在回调中接收：

```js
{
  status: 'fail',
  errormsg: 'not groupbuy order'
}
```

**核销示例代码**

```js
// 组装团购商品详情
const groupBuyItem = {
  coupon: {
    name: '【双人实惠】烤全鱼双人餐',
    quantity: 1,
    original_price: 29800, // 单位：分，即 ¥298.00
    paid_amount: 19900, // 单位：分，即 ¥199.00，需与订单实付金额一致
    valid_until: 1788519809
  },
  packages: [
    {
      group_name: '招牌',
      select_type: 1,
      items: [{ name: '烤全鱼', quantity: 1 }]
    },
    {
      group_name: '小食',
      select_type: 3,
      select_count: 2,
      items: [
        { name: '薯条', quantity: 1 },
        { name: '鸡米花', quantity: 1 }
      ]
    }
  ]
}

wx.openBusinessView({
  businessType: 'weappOrderConfirm',
  extraData: {
    transaction_id: '420123123123123123123',
    group_buy_item: groupBuyItem,
  },
  success() {
    // do something
  },
  fail() {
    // do something
  },
  complete() {
    // do something
  }
})

// 响应组件回调
App({
  onShow(options) {
    // do something
  }
})
```

**调试预览模式**

调试预览模式用于审核通过前的组件联调，以及挂载团购服务所需的审核截图。请求参数和业务回调沿用上一节的接口定义，按以下方式开启调试模式。

调用 `wx.openBusinessView` 时，在 `extraData` 中传入精确值 `mode: 'dev'` 即可开启调试预览模式；正式上线前需要删除该参数。

`extraData` 字段新增调试字段：

| 属性 | 类型 | 说明 |
| - | - | - |
| `mode` | string | 仅未完成 POI 准入流程时调试使用，传入精确值 `'dev'` 时开启调试预览模式；未传或传入其他值时走正式流程，正式上线需要删除该参数。 |

调试预览模式不会发生真实核销，但仍会使用 `transaction_id` 查询真实订单，并校验传入的套餐、金额和过期时间；但是会跳过真实订单是否属于团购订单以及订单状态校验。

用户点击「确认」后，组件会返回模拟成功事件：

```js
{
  status: 'success',
  simulated: true,
}
```

调用方可以通过 `simulated === true` 判断是否为模拟结果。调试预览模式与正式核销模式均返回 `status: 'success'`。

调试预览模式的**调用示例**：

```js
wx.openBusinessView({
  businessType: 'weappOrderConfirm',
  extraData: {
    transaction_id: '420123123123123123123',
    group_buy_item: groupBuyItem,
    mode: 'dev',
  },
  success() {
    // do something
  },
  fail() {
    // do something
  },
  complete() {
    // do something
  }
})
```

调试预览模式下，用户在二次确认页点击「确认」后，页面提示「模拟核销成功」，并通过 `App.onShow` 回调：

| 场景 | `status` | `simulated` | 页面表现 |
| - | - | - | - |
| 调试预览二次确认点击「确认」 | `success` | `true` | 提示「模拟核销成功」 |

![](https://res8.wxqcloud.qq.com.cn/wxdoc/01cda06b-5277-43f3-92f0-bad31b734feb.png)

**2. 建议接入方式：**

① 用户进入订单详情页，点击「确认核销/获取二维码」。

② 商家**调用接口请求核销，展示二次确认组件。**
用户在组件上确认套餐信息无误，点击「确认」

③ 确认成功后，小程序向用户展示核销二维码，商户扫码后成功核销，由商户系统记录实际消费及核销状态。

④ 平台收到用户确认事件后，资金按 T+3 解冻给商户号。

> ⚠️ 注意：平台必须收到用户确认事件，才能完成平台侧核销并按规则解冻。
>
> 建议将二次确认放在展码前；如果先展码、商户已扫码但用户未确认，资金将无法按该核销链路解冻。

![](https://res8.wxqcloud.qq.com.cn/wxdoc/b30bee75-aa7c-4acf-b80a-0aa56909da3d.png)

**3. 套餐变更提示：**

若套餐内容有变更，商家需同步更新二次确认组件中的字段和套餐详情页，并与用户沟通确认。平台以核销时组件上展示的信息为准处理纠纷。

**4. 购买数量与核销的限制**

因微信支付首期仅支持整笔订单统一冻结和打款，暂不支持分次核销（即一笔订单购买多张券后分批到店使用）。建议你在开发团购时**将每个订单的购买数量限制为 1 张；若用户需购买多张，可引导其分多次下单。**

## 四、创建团购服务

**1. 特别说明：**

- 目前首期支持「美食」一级类目
- 创建服务前，请先完成「微信位置认领」及「关联小程序账号」，详情参考：[微信位置运营 | 微信开放文档](wxpoi/)
- **账期授权入口仅面向已认领 POI 且提交团购审核的小程序展示。若看不到「已关联商户号」或账期授权入口，请先确保已提交团购服务审核。**

**2. 创建服务操作步骤：**

① 进入「微信位置管理」小程序，点击「服务管理 - 创建服务」

② 选择服务类型为「团购优惠」，填写小程序及服务页面路径（用户从 POI 入口进入的小程序页面）

③ 填写「团购下单页面路径」：所有团购套餐挂载的统一下单页路径

④ 上传「团购流程截图」并提交审核。此时尚未完成正式审核挂载，请使用核销组件的调试预览模式获取核销组件截图。

⑤ 服务进入审核流程后，登录 MP 后台「支付与交易 - 微信支付」，即可查看「已关联商户号」与账期授权入口，并按第五章完成授权。审核通过并正式挂载后，再切换到线上验证核销。

**3. 团购流程截图要求：**

| 截图内容                                         | 数量 | 要求               |
| ------------------------------------------------ | ---- | ------------------ |
| 含「随时退」「过期退」标识的团购详情页           | 1 张 | 需清晰展示相应标识 |
| 含「申请退款」入口的已支付订单详情页             | 1 张 | 需展示退款入口     |
| 核销流程页面（获取二维码 → 用户二次确认 → 展码） | 3 张 | 需包含完整核销链路；可使用调试预览模式准备核销组件截图。 |

> 注意：所有截图需包含小程序名称或 AppID 以验证真实性。截图不清晰或信息不完整将被驳回。

![](https://res8.wxqcloud.qq.com.cn/wxdoc/92a6f86b-eb3f-48db-953d-eb35d58a943a.png)

## 五、授权账期管理

**1. 什么是账期管理？**

为保障消费者权益，团购订单的资金不会立即到账，而是在核销成功后才解冻打款给商家。

默认规则：团购订单资金默认冻结 90 天。核销成功后，资金将在 T+3 个工作日解冻打款至你的商户号账户。

**2. 如何授权？**

小程序需属于美食类目，且已手动认领 POI 并提交团购服务审核，才展示账期授权入口。

**注：如通过支付服务商接入微信支付，请在授权前告知服务商，当前小程序正接入餐饮团购，将涉及账期管控，请配合接入。**

**尚未看到入口的餐饮小程序，应先认领 POI、关联小程序、并提交团购服务审核；进入审核流程后，再进行以下操作：**

① 登录微信小程序管理平台

② 进入「支付与交易 - 微信支付」

③ 找到对应「已关联商户号」，在 MP 后台逐个点击授权，对应商户号超级管理员在移动端确认授权申请。

④授权后的状态说明：
- **显示「授权生效中」：部分商户号的授权需在 T+7 日后生效，请耐心等待。授权生效后，系统会自动提交团购审核，无需重复操作。**
- 此前已完成授权：如果你的小程序或服务商此前已经授权过「交易结算管理」，则无需重复操作，系统会自动识别为已授权。

![](https://res8.wxqcloud.qq.com.cn/wxdoc/a1e94f96-9278-41ac-9551-9d2501fd3415.png)

**3. 商户类型说明：**

| 商户类型               | 授权方式                                                                         |
| ---------------------- | -------------------------------------------------------------------------------- |
| 直联商户               | 在小程序 MP 后台逐个点击授权，对应商户号超级管理员在移动端确认授权申请。 |
| 间联商户（普通服务商） | 在小程序 MP 后台逐个点击授权，对应商户号超级管理员在移动端确认授权申请。 |
| 间联商户（银行、第三方支付机构等） | 需对应支付机构与微信支付线下签约授权，授权后机构代开的所有商户号均支持。授权前，请先联系你对应的支付机构，告知当前在接入餐饮团购，会进行账期授权和管控。 |

**4. 账期解冻完整规则：**

| 情况             | 冻结时长   | 资金去向   |
| ---------------- | ---------- | ---------- |
| 核销成功         | 核销后 T+3 | 打款给商家 |
| 有效期内用户退款 | 即时       | 退还用户   |
| 有效期内商户退款 | 即时       | 退还用户   |
| 超有效期自动退   | 有效期满   | 退还用户   |
| 兜底：平台自动退 | 满 90 天   | 退还用户   |

## 六、常见问题

**1. MP 后台为什么看不到已关联商户号或账期授权入口？**

入口展示有前置条件：小程序需属于「美食」类目，且已手动认领 POI 或已自动匹配到 POI。看不到入口的餐饮小程序，完成技术改造后先认领 POI、关联小程序并提交「团购优惠」服务审核；进入审核流程后，即可登录 MP 后台「支付与交易 - 微信支付」查看商户号并授权。

**2. MP后台点击授权后，显示授权生效中怎么办？**

![](https://res8.wxqcloud.qq.com.cn/wxdoc/ff56c523-41f3-4995-870f-604dae56d585.png)
此类商户号点击授权后，需T+7日生效授权，因此显示授权生效中。过T+7日生效后，会自动提交团购审核。

**3. 如何查询小程序是否已完成账期授权？**

可使用接口查询：[查询小程序是否已完成交易结算管理确认](/miniprogram/dev/server/API/order_shipping/api_istrademanagementconfirmationcompleted.md)

**4. 审核前无法使用正式核销组件 如何准备审核截图？**

审核通过并正式挂载到 POI 前，订单尚不能按正式团购订单识别，直接以正式模式调用可能报错或静默关闭。请在 extraData 内传入 mode: 'dev'，通过调试预览模式获取截图后提交审核。调试仍需真实交易单号、匹配的实付金额和未过期的有效期；审核通过并挂载团购优惠在 POI 后，再验证正式流程。

**5. 核销组件返回not groupbuy order 怎么处理？**

表示传入订单不是团购订单，资金不会按团购规则冻结；组件会静默关闭。常见原因包括未通过审核挂载到 POI、未授权账期或小程序类目非餐饮。开发者需在 App.onShow 中处理该返回，自行衔接原有展码流程。

**6. 核销组件返回 order not found 怎么处理？**

多数是小程序未授权账期管理，订单未同步到团购侧。请先在 MP 后台完成对应商户号的账期授权；服务审核通过并正式挂载后，用新下单的团购订单验证。

**7. 用户确认后为何商户订单仍显示待核销？**

用户确认触发的是平台侧核销与后续解冻流程；商户订单状态由商户自己的系统管理。用户确认后仍需商户扫码消费，再更新商户侧核销状态。

**8. 用户确认后没有扫上码怎么办？**

若尚未被商户扫码核销，应允许用户再次获取有效核销码。检查小程序是否将展码错误地限制为一次，以及扫码结果是否正确同步到订单；不要将重新展码等同于重新发起平台核销。

**9. 团购订单产生交易纠纷如何处理？**

可参考：[小程序交易投诉开发者处理流程指引](/miniprogram/product/jiaoyilei/shangjiazhiyin932.md)。

## ✓ 联系我们
接入中有任何疑问，可扫码添加以下企业微信进行咨询。

添加时，请简述你遇到的问题+小程序appid

![](https://res8.wxqcloud.qq.com.cn/wxdoc/d2bfa8e8-c162-45ee-8e46-21dc79185601.png)

## 【可选】接入小程序订单展示功能

**1. 这个功能有什么用？**

接入后，顾客在你小程序里下的每一笔团购订单，都会自动同步到微信「我 - 小店与卡包 - 小程序购物订单」中。顾客可以在这里集中查看所有订单，包括：

- 订单列表和商品描述
- 支付时间、支付金额、退款金额、交易单号
- 每个订单都配有「前往小程序」按钮，点击后直接跳转到你小程序里对应的订单详情页

顾客查单更方便，你也少接「我的订单在哪」这类咨询。

![](https://res8.wxqcloud.qq.com.cn/wxdoc/51751f09-4a0f-4303-bd5b-44f3872161c7.png)

**2. 接入流程**

**第一步：签署授权协议**

进入小程序管理后台 - 订单管理，找到订单中心相关入口，完成授权协议签署。签署后才能进行后续配置。

![](https://res8.wxqcloud.qq.com.cn/wxdoc/ddf8c546-118b-440a-bf82-214334004dce.png)

**第二步：配置订单跳转路径**

![](https://res8.wxqcloud.qq.com.cn/wxdoc/f284bac0-a86a-4d91-91d6-d0024b5a4c75.png)

**方式 01：在小程序管理后台配置订单跳转路径**

授权完成后，在小程序管理后台配置订单详情路径。这个路径就是顾客在「小程序购物订单」中点击「前往小程序」时，要跳转到的小程序页面。

路径需要包含 `${商品订单号}` 这个固定占位符。举个例子，如果你的订单详情页路径是 `pages/order/detail/index`，接收一个名为 `orderId` 的参数，那么配置的路径应该是：

```
pages/order/detail/index?orderId=${商品订单号}
```

![](https://res8.wxqcloud.qq.com.cn/wxdoc/65a162de-207c-410e-85d5-bf1da1db5d64.png)

**方式 02：调用 API 接口配置订单跳转路径**

如果你是由服务商代为操作，或者希望通过代码自动化管理，可以通过以下接口来配置：

```
POST https://api.weixin.qq.com/wxa/sec/order/update_order_detail_path?access_token=ACCESS_TOKEN
```

请求参数：

| 属性 | 类型   | 必填 | 说明         |
| ---- | ------ | ---- | ------------ |
| path | string | 是   | 订单详情路径 |

请求示例：

```json
{
    "path": "pages/index/index?id=${商品订单号}"
}
```

返回示例（成功）：

```json
{
    "errcode": 0,
    "errmsg": "ok"
}
```

常见错误码：

| 错误码        | 含义           | 解决方法               |
| ------------- | -------------- | ---------------------- |
| -1 / 10060012 | 系统繁忙       | 稍后重试               |
| 10060034      | 授权协议未签署 | 先完成第一步的授权签署 |
| 10060035      | path 有误      | 检查路径格式是否正确   |
| 10060036      | 编码问题       | 确保使用 UTF-8 编码    |

> 该接口所属权限集 ID 为 182，服务商获得授权后可使用 `authorizer_access_token` 代商家调用。

**第三步：下单时给微信支付传入商品描述和订单号**

在下单时（使用 JSAPI 或小程序支付接口 [JSAPI/小程序下单](https://pay.weixin.qq.com/doc/v3/merchant/4012070978)），需要在接口中传入两个关键字段：

| 字段         | 作用                                                                                                                             |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| description  | 作为商品描述，展示在「小程序购物订单」的订单列表和详情页中，让顾客一眼看出买了什么                                               |
| out_trade_no | 你的商品订单号，用于实现跳转——当顾客点击「前往小程序」时，系统会自动把路径中的 `${商品订单号}` 替换为该订单的真实 `out_trade_no` |
