小程序扫码核销团购券:美团券码、抖音二维码短链分别怎么处理?
核销服务由无限聚核提供,美团、抖音团购核销一站式接入。

目录(7 节)
顾客到店,不想手输十几位券码,希望在小程序里点一下“扫码”就能验券。做这个功能的开发者,最常卡在几个地方:wx.scanCode 扫出来的是什么?扫到一个网址能不能直接传给核销接口?美团和抖音的码要不要分开处理?
一句话回答: 扫码只负责把内容读进来,验券和核销仍然在服务端调接口完成。wx.scanCode 返回的 res.result 分三种处理:去掉空格后是纯数字的,当作券码,和顾客选定的平台一起提交;抖音团购二维码扫出来是 v.douyin.com 短链,按抖音开放平台文档,要取跳转后长链接里的 object_id 作为 encrypted_data,通过无限聚核这类第三方接口时可以把完整短链直接作为券码、platform=2 提交;其他网址(包括美团券二维码扫出的网址)不要自己猜格式,提示顾客输入二维码下方的数字券码。不要按长度判断平台,也不要截断短链。

一、先想清楚:谁扫谁
顾客在自己手机上打开团购券,没法再用同一台手机的摄像头去扫它。所以“扫码核销”要先分清场景:
| 场景 | 谁扫谁 | 做法 |
|---|---|---|
| 店员端小程序 | 店员手机扫顾客手机上的券 | 调 wx.scanCode 用相机扫 |
| 顾客自助 | 顾客只有一台手机 | 先截图券码页面,在扫码界面从相册选图;或者直接手输券码 |
| 门店固定设备 | 扫码盒、扫码枪扫顾客手机 | 这类设备通常把扫到的内容当键盘输入,页面用输入框接收,回车后提交 |
顾客自助的场景,手输入口一定要保留。截图选图多了一步,不少顾客会直接选择输码。
二、wx.scanCode 返回什么
根据微信官方文档(2026年9月28日查看):
scanType默认是['barCode', 'qrCode', 'wxCode'],还可以加datamatrix、pdf417。团购券一般是二维码或条形码,设成['qrCode', 'barCode']就够了;onlyFromCamera为true时不允许从相册选图。顾客自助场景不要设成true;- 成功回调里,
res.result是所扫码的内容,res.scanType是码的类型。
小程序端只把 res.result 原样发给自己的服务端,不在前端判断平台,更不在前端调用核销接口。核销接口的凭证只能放在服务端。
// 小程序端:只负责读码,原样交给自己的服务端
wx.scanCode({
scanType: ['qrCode', 'barCode'],
success: (res) => {
wx.request({
url: SERVER_BASE_URL + '/coupon/scan', // 自己业务服务端的地址
method: 'POST',
data: { raw: res.result, storeId: this.data.storeId },
});
},
});
三、扫出来的三种结果,分别怎么处理
| 扫到的内容 | 示例 | 服务端处理 |
|---|---|---|
| 纯数字(可能带空格) | 1234 5678 9012(示例) |
去掉空白字符后作为券码,平台由顾客选择或门店默认 |
| 抖音券码短链 | v.douyin.com/xxxx/ |
按第四节处理,platform=2 |
| 其他网址 | 美团券二维码扫出的网址等 | 不自己解析,提示“请输入二维码下方的数字券码” |
| 其他文本 | 小程序码、收款码等 | 提示“这不是团购券码” |
美团券为什么只收数字? 部分收银系统的帮助文档提到,用摄像头识别美团团购二维码时返回的是一个网址,也可以用二维码下方的纯数字券码核销。这个网址的格式,我们没有在美团开放平台的公开文档里找到说明。自己去截取网址里的某一段,平台一调整就会出错,稳妥的做法是只提交数字券码。
纯数字为什么要顾客选平台? 美团和抖音都有纯数字券码,长度并不固定,按位数猜平台迟早会猜错。只开了一个平台的门店,可以默认那个平台;两个平台都开的,页面上放“美团/抖音”两个选项。也不建议两个平台轮流试:错误提示会变得混乱,请求量也翻倍。
// 服务端:只按内容分流,不按长度猜平台
function classifyScan(raw) {
const text = String(raw).trim();
const digits = text.replace(/\s+/g, '');
if (/^\d+$/.test(digits)) return { kind: 'digits', code: digits }; // 平台由顾客选择
let url;
try { url = new URL(text); } catch { return { kind: 'unknown' }; }
if (url.protocol === 'https:' && url.hostname === 'v.douyin.com') {
return { kind: 'douyin-link', code: text, platform: 2 }; // 完整短链,不截断
}
return { kind: 'ask-digits' }; // 其他网址:提示输入二维码下方的数字券码
}
四、抖音二维码短链:取 object_id,不要截断
抖音开放平台“验券准备”接口文档(2026年9月28日查看)写明:
- 二维码扫出来是一个短链,文档示例形如
v.douyin.com/eHHc1ft/; - 访问短链得到长链接,长链接中
object_id参数的值,就是验券准备接口要传的encrypted_data; - 请仅感知链接中的
object_id参数,其他参数、域名、路径以后都有调整的可能; encrypted_data和code二选一必传;- 验券准备和验券的调用次数要一一对应。验券成功后,当前二维码会失效,要使用刷新后的二维码再调用。
自己对接抖音开放平台时,解析短链要放在服务端,并做好限制:只接受 https 协议、域名为 v.douyin.com 的链接,只读取第一跳响应的 Location,不要跟随任意跳转,也不要用正则按固定长度去截链接。
// 服务端:自己对接抖音开放平台时,从短链取 encrypted_data
async function resolveDouyinObjectId(link) {
const u = new URL(link);
if (u.protocol !== 'https:' || u.hostname !== 'v.douyin.com' || u.username || u.password) {
throw new Error('不是抖音券码短链');
}
const res = await fetch(u, { redirect: 'manual', signal: AbortSignal.timeout(3000) });
const location = res.headers.get('location');
if (res.status < 300 || res.status >= 400 || !location) throw new Error('短链无法解析');
const objectId = new URL(location, u).searchParams.get('object_id');
if (!objectId) throw new Error('短链响应缺少 object_id');
return objectId; // 作为验券准备接口的 encrypted_data
}
通过无限聚核的V2聚合接口时,这一步可以省掉。当前公开API文档写明:“输码验券校验”接口在 platform=2 时,code 也支持扫码得到的完整 v.douyin.com 短链;服务端只访问 v.douyin.com 的首跳并提取 object_id,解析失败时不会继续请求平台,返回 INVALID_COUPON_LINK(code 10001),这时提示顾客改输明文券码即可。文档同样提醒:短链长度不固定,禁止按长度截断。
补三条联调里常见的短链细节(2026-10-17 对照抖音开放平台验券准备说明与无限聚核公开文档):
- 短链只是入口,真正核销仍走两段式。 自己对接时:短链 →
object_id(encrypted_data)→ 验券准备certificate.prepare→ 验券确认certificate.verify。通过无限聚核时:完整短链进预核销的code,服务端完成首跳解析与准备,你仍要保存ticketInfo再核销; - 解析失败不要改去试美团。 返回
INVALID_COUPON_LINK时,提示顾客改输抖音券页面上的明文券码,或刷新二维码再扫;不要把同一短链改platform=1重试; - 日志与缓存。 完整短链等同于券,日志只留域名与末尾若干字符;不要把短链缓存在小程序本地当“下次还能用”——核销成功后旧码失效,次卡也要重新打开券页刷新二维码。
五、扫码之后:验券、确认、核销
扫码只是入口,后面的步骤和手输券码完全一样:
- 验券。 服务端用具体门店的
shopId、平台和券码(或抖音短链)调用无限聚核的“输码验券校验”(预核销)接口,成功后保存响应里的ticketInfo原文; - 让顾客确认。 页面显示套餐名称、售卖价和适用门店,顾客点“确认使用”才进入下一步。扫错券、扫到别人的券,都在这一步拦下来;
- 核销。 把
ticketInfo整段原样传给核销接口,只以顶层success判断成功,按下标保存consumeCredential; - 发放权益。 核销成功后再开门、上电或记入会员账户。
抖音券还有一点要提醒顾客:核销成功后,原来的二维码就失效了。次卡下次到店要重新打开券页面,用刷新后的二维码。
六、防误扫、防连点、防刷
- 确认按钮防连点。 核销请求在途时按钮置灰。以无限聚核为例,同一张券的核销在途时再提交,会返回
CONSUME_IN_PROGRESS; - 限制验券频率。 同一个用户、同一台设备,短时间内连续验券失败多次,就暂停一会儿,防止有人批量试券码;
- 日志不要打印完整券码和完整短链。 抖音短链等同于券本身,日志里只保留脱敏后的片段和关联ID;
- 友好提示平台拒绝。 券已使用、已过期或不适用本店时,平台会拒绝,页面按错误码给出对应提示,不要只显示“核销失败”。
顾客实在找不到券码时,还有一个店员端的兜底办法。以无限聚核为例,公开文档开放了美团原生“手机号查询可用团购券”接口,需要传用户绑定的手机号、团购ID和套餐ID,每次最多查5条。它要求店员知道顾客买的是哪个套餐,并且涉及手机号,只适合放在店员端,不适合做成顾客自助入口。
七、常见问题
小程序能直接识别美团团购券的二维码吗?
能扫,但不建议解析。美团券二维码扫出的网址格式,我们没有在美团开放平台公开文档中找到说明。稳妥的做法是提示顾客输入二维码下方的数字券码,服务端只提交数字券码。
抖音短链核销失败,最常见是哪几类?
一类是短链域名或跳转不符合约定,服务端应只接受 https://v.douyin.com/… 的首跳并取 object_id;一类是码已核销或转赠中,验券准备拿不到可用券;一类是门店未完成抖音授权或 poi_id/shopId 映射错误。通过无限聚核时,先看是 INVALID_COUPON_LINK 还是 PLATFORM_REJECTED,再决定提示刷新二维码、改输明文,还是检查授权。
抖音团购二维码扫出来是一个网址,怎么核销?
那是 v.douyin.com 短链。自己对接抖音开放平台时,在服务端读取短链跳转后的长链接,取其中的 object_id 作为验券准备接口的 encrypted_data;通过无限聚核接口时,可以把完整短链作为 code、platform=2 直接提交。
可以按券码长度判断是美团还是抖音吗?
不可以。两个平台的纯数字券码长度都不固定,抖音短链的长度也不固定。纯数字券码让顾客选择平台,或者按门店开通的平台默认;抖音短链按域名识别。
顾客只有一部手机,怎么扫自己的团购券?
让顾客先截图券码页面,再在小程序的扫码界面从相册选图,wx.scanCode 不要把 onlyFromCamera 设为 true。同时保留手动输码入口。
抖音团购二维码核销后还能再用吗?
不能。抖音开放平台文档写明,验券成功后当前二维码会失效,需要使用刷新后的二维码再调用。次卡每次到店都要重新打开券页面。
扫到的券码提交给无限聚核后,预核销会返回什么?
成功时顶层 success=true,data 里有套餐名称 ticketName、售卖价 dealPrice(元)和 payAmount(分)、用户实付 actualPayAmount(分)、核销凭证 ticketInfo,抖音券还有抖音官方券信息 ticketData。ticketInfo 要整段原样保存,核销时传回,不要解析;抖音次卡的剩余次数从 ticketData 里读取。短链解析失败返回 INVALID_COUPON_LINK,券不存在、已使用或不适用本店返回 PLATFORM_REJECTED。
接口字段以无限聚核当前公开API文档为准。



