抖音团购核销接口怎么接?和美团不一样的几个地方
核销服务由无限聚核提供,美团、抖音团购核销一站式接入。

目录(11 节)
美团团购核销刚接好,老板紧接着就会问:“抖音的券能不能也核?”不少开发者以为照着美团的代码改改域名和字段就行,做起来才发现两边差得不少。美团顾客报一串数字就能验,抖音顾客多半直接亮二维码。美团拿明文券码就能核销,抖音必须先调“验券准备”,换出一个 verify_token 和加密券码。美团价格是元,抖音是分。连判断“成功”该看哪个字段,两边都不一样。
下面按开发顺序把这些差异列出来。抖音部分依据抖音开放平台“生活服务商家应用”的接口文档和技术服务商接入文档,2026年9月29日查看。
一句话回答: 抖音团购券核销用的是抖音开放平台生活服务的 /goodlife/v1/fulfilment/certificate/ 系列接口,顺序固定为“验券准备 → 验券”,验券后1小时内可以撤销。和美团相比,最要紧的有四点:
- 抖音用应用级
client_token调用,每次请求用poi_id指定门店; - 每次验券前都要重新调验券准备,用返回的
verify_token和encrypted_code去核销,不能传明文券码; - 顾客出示的二维码扫出来是短链,要取跳转后长链接里的
object_id; - 金额单位是分;判断成功要同时看
data.error_code、extra.error_code和每张券的verify_results[].result。
自己对接,要先入驻抖音服务商平台,再通过联调、压测、安全三项验收。不想自己办资质,可以通过无限聚核这类第三方接口,和美团共用一套验券、核销接口,platform 传2。

一、先确认要接的是哪一套接口
抖音开放平台上叫“核销”的接口不止一套。最常见的混淆是这两套:
| 生活服务商家应用(本文讲的) | 抖音小程序交易系统 | |
|---|---|---|
| 券从哪来 | 商家在抖音来客上架团购,顾客在抖音App团购页购买 | 商家自己的抖音小程序里下单 |
| 验券相关接口 | GET /goodlife/v1/fulfilment/certificate/prepare/、POST /goodlife/v1/fulfilment/certificate/verify/ |
/api/apps/trade/v2/fulfillment/delivery_prepare、delivery_verify |
| 门店标识 | poi_id |
以小程序交易文档为准 |
判断方法:顾客的券是在抖音App团购页买的,商家在抖音来客后台能看到这笔订单,就用生活服务这一套。网上搜到的示例代码,路径里带 /api/apps/trade/ 的属于小程序交易系统,拿来核销团购券是调不通的。
还有一个小细节:生活服务接口的路径都以 / 结尾,接入文档特意写了“/不可省略”。从美团代码改过来时顺手删掉结尾斜杠,是很常见的低级错误。
二、调用凭证:抖音一个应用一份,美团一个商家一份
| 美团 | 抖音 | |
|---|---|---|
| 调用凭证 | 每个商家单独授权,各有一套 access token 和 refresh token | 一个应用一个 client_token,所有已授权商家共用 |
| 商家怎么授权 | 商家打开授权链接,登录美团确认 | 商家在抖音来客后台把应用授权给服务商,或者在服务商的系统里完成授权 |
| 凭证过期 | 用 refresh token 续期;refresh token 失效,这家店要重新授权 | 重新生成 client_token,商家不用操作 |
抖音所有接口的请求头都要带 access-token,值是 /oauth/client_token/ 返回的 data.access_token。它是应用级凭证,带来三个后果:
- 集中生成和缓存。 多台服务器部署时,快过期前统一刷新。刷新要加分布式锁,拿到锁以后再看一眼缓存,如果别的机器已经刷新过就直接用,免得几台机器同时刷新、互相顶掉;
- 门店全靠
poi_id区分。 凭证里没有门店信息。库里要存好“自己的门店 ↔ 抖音poi_id”的映射,传错了轻则报无权限,重则把券核到别的门店; - 连锁场景多一个参数。 验券准备接口的
account_id,文档写的是“云连锁/共管场景下,挂靠商户必传,其余场景可不传”。
美团正好相反,凭证跟着商家走。每家店的 refresh token 都要可靠地存下来:刷新拿到新的 refresh token 后,先写数据库,再更新缓存。异步保存丢了一次,那家店就只能重新授权。两套凭证的管理逻辑差别很大,不要硬套进同一个类。
三、验券准备和验券:一次准备只配一次验券
抖音团购券核销分两步,这是和美团差别最大的地方。
第一步,验券准备。 code(明文券码)和 encrypted_data(从二维码解析出来的标识)二选一,poi_id 必传:
GET /goodlife/v1/fulfilment/certificate/prepare/?poi_id=<门店poi_id>&encrypted_data=<URL编码后的object_id>
access-token: <client_token>
返回里核销要用的主要是这几项(其他字段省略,数值为虚构):
{
"data": {
"error_code": 0,
"verify_token": "<本次验券标识>",
"order_id": "<订单ID>",
"certificates": [
{
"encrypted_code": "<加密券码>",
"expire_time": 1790000000,
"amount": { "original_amount": 29900, "pay_amount": 26900 },
"sku": { "sku_id": "<商品ID>", "title": "精洗10次卡", "groupon_type": 3 },
"time_card": { "times_count": 10, "times_used": 3 }
}
]
},
"extra": { "error_code": 0, "logid": "<抖音日志ID>" }
}
第二步,验券。 把上一步的 verify_token 和挑出来的 encrypted_code 传回去:
POST /goodlife/v1/fulfilment/certificate/verify/
access-token: <client_token>
Content-Type: application/json
{
"verify_token": "<验券准备返回的 verify_token>",
"poi_id": "<门店poi_id>",
"encrypted_codes": ["<验券准备返回的 encrypted_code>"]
}
文档里这几句要看仔细:
- 验券准备和验券接口的“调用次数需要一一对应”;已经验券成功的,“当前二维码会失效”,要用刷新后的二维码再调用;
- 验券准备“只返回未使用状态的券信息”,而且“不返回明文券码,只返回加密券码”;
encrypted_codes的说明是“验券准备接口返回的加密抖音券码”。
落到代码里,常见的坑有这几个:
把明文券码塞进 encrypted_codes。 从美团迁移过来最容易犯,平台会报“加密码解密失败”一类的错误,网上不少求助帖都是这个原因。明文券码只能用在验券准备的 code 参数里。
缓存 verify_token 重试。 核销失败或超时后,拿旧的 verify_token 再调一次验券,不符合“一一对应”。结果明确失败的,重新调验券准备再验。结果不明的(超时、连接断开),先查券状态,确认没核掉再重来。
券正在转赠。 转赠中的券,验券准备返回空数组。页面上别只写“券无效”,提示“这张券可能正在转赠中,请确认后再试”,能少接不少客服电话。
提货券少算张数。 文档写明,提货券订单一个订单多张券只会返回一个 certificate_id。按 certificate_id 去重计数的,这里会算少。
certificate_id 的精度。 验券准备响应里的 certificate_id 在文档中标为64位整数。Node.js 直接 JSON.parse 可能丢精度,用支持大整数的解析方式,或者按字符串处理。
四、一次扫码,可能扫出好几张券
抖音团购二维码对应的是订单。文档写明,扫码后“可返回当前订单下可用的全部券码信息”。顾客买了3张洗车券,今天只洗1次,验券准备会把3张都返回来。
所以核销前要让顾客选数量,只取需要的那几个 encrypted_code,不要把 certificates 整组塞进 encrypted_codes。一次核掉3张,顾客第二天才发现,已经过了1小时的撤销时限,只能走平台售后。
次卡是另一种情况:一张券,多次使用。time_card 里 times_count 是总次数,times_used 是已用次数。验券接口文档对 encrypted_codes 的说明是:“多次卡商品,如果需要一次核销多份,list中传多个相同encrypted_code”。一张洗车次卡今天洗两台车,就把同一个加密券码放两次。放之前先算 times_count - times_used 够不够,不够就别发请求。
五、扫二维码,拿到的是短链
顾客在抖音App里打开团购券,出示的是二维码。用 wx.scanCode 或扫码枪扫出来,是一个抖音短链。按抖音文档:
- 访问短链,拿到跳转后的长链接;
- 取长链接里
object_id参数的值作为encrypted_data,URL 编码后再传; - 只认
object_id这一个参数,域名、路径和其他参数都可能调整; - 短链长度不固定,不要限制长度,也不要截断。
顾客也可以报二维码下方的数字券码,这时用 code 参数。两个入口最后调的是同一个验券准备接口。扫码入口的完整做法,可以参考本站《小程序扫码核销团购券:美团券码、抖音二维码短链分别怎么处理?》一文。
六、金额单位是分,字段还很多

美团验券返回的套餐价是以元为单位的小数,比如 79.9;抖音验券准备的 amount 里全是以分为单位的整数,比如 7990。常用的几个:
| 字段 | 文档说明 | 用途 |
|---|---|---|
original_amount |
原价,单位分 | 套餐售价,对账主要看它 |
pay_amount |
实付金额,单位分 | 顾客实际付了多少 |
list_market_amount |
划线价,单位分 | 页面上划掉的那个价 |
merchant_ticket_amount |
商家营销金额,单位分 | 商家自己出的优惠 |
platform_discount_amount |
平台优惠金额,单位分 | 平台补贴 |
original_amount 虽然叫“原价”,指的是套餐售价,划线价另有 list_market_amount,别弄反。两个平台的券放进同一张表对账时,统一存成以分为单位的整数,不要用浮点数存元。
七、判断成功:先看三层 error_code,再逐张看结果

美团的验券接口,看顶层 code 是不是 OP_SUCCESS,再核对返回的券码和数量。抖音要看三处:
data.error_code不为0:请求失败,原因在data.description;extra.error_code或extra.sub_error_code不为0:同样按失败处理,原因在extra.description和extra.sub_description;- 前两层都为0,还要逐张看
data.verify_results[].result,文档写的是“0表示成功,非0表示失败”。
抖音的技术服务商入驻指南里专门提醒过:“验券接口返回的验券结果 result 字段必须进行业务匹配检查”,result 非0“表示业务侧提示而非技术异常”。一次核销多张券时,完全可能一张成功、一张失败。这时按“部分成功”处理:成功的那张发放权益,失败的那张单独提示。
每张成功的券,把 verify_id 和 certificate_id 存下来,撤销时要用。extra.logid 也存上,找抖音技术支持排查问题时要提供它。
// 按三层 error_code 和逐张 result 判断抖音验券结果
type verifyResp struct {
Data struct {
ErrorCode int64 `json:"error_code"`
Description string `json:"description"`
VerifyResults []struct {
Result int64 `json:"result"`
VerifyID string `json:"verify_id"`
CertificateID string `json:"certificate_id"`
} `json:"verify_results"`
} `json:"data"`
Extra struct {
ErrorCode int64 `json:"error_code"`
SubErrorCode int64 `json:"sub_error_code"`
Description string `json:"description"`
SubDescription string `json:"sub_description"`
Logid string `json:"logid"`
} `json:"extra"`
}
func judge(r verifyResp) (ok []Voucher, failed int, err error) {
if r.Data.ErrorCode != 0 {
return nil, 0, fmt.Errorf("验券失败 %d %s logid=%s", r.Data.ErrorCode, r.Data.Description, r.Extra.Logid)
}
if r.Extra.ErrorCode != 0 || r.Extra.SubErrorCode != 0 {
return nil, 0, fmt.Errorf("验券失败 %d/%d %s %s logid=%s", r.Extra.ErrorCode, r.Extra.SubErrorCode,
r.Extra.Description, r.Extra.SubDescription, r.Extra.Logid)
}
for _, v := range r.Data.VerifyResults {
if v.Result != 0 {
failed++ // 业务侧提示,逐张处理,不能把整笔当成功
continue
}
ok = append(ok, Voucher{VerifyID: v.VerifyID, CertificateID: v.CertificateID}) // 撤销要用,必须落库
}
return ok, failed, nil
}
HTTP 超时、连接断开、响应解析失败,这三种情况都不是“失败”,是“结果未知”,券可能已经核掉了。先调券状态查询接口 GET /goodlife/v1/fulfilment/certificate/get/ 确认,再决定发不发权益、要不要重试。
八、撤销:1小时内,带上 verify_id 和 certificate_id
抖音“撤销核销”接口文档写明,验券超过一个小时就不可再撤销,撤销后订单状态由“已使用”改回“待使用”;extra.error_code 和 data.error_code 均为0,才代表撤销成功。请求里带验券时保存的 verify_id 和 certificate_id。
美团是10分钟,两个平台差了6倍。系统里的撤销按钮要按平台分别倒计时。撤销功能怎么做、超时了怎么办,本站《团购券核销错了能撤销吗?》一文里有完整说明。
九、自己对接:先入驻,再过三项验收

直接调用上面这些接口,前提是你已经是抖音生活服务的技术服务商,而且应用已经上线。按抖音开放平台的技术服务商入驻指南,大致要走这些环节:
- 入驻并认证。 在服务商平台认证“生活服务商家应用代开发”能力,文档写的是“平台一般在 10 个工作日内完成审核”,通过后还要做对公认证。认证条件包括注册满一年、注册资本不低于100万元、经营范围含技术开发服务、同主体 ICP 备案(2026年9月10日核对,以平台当前要求为准);
- 创建应用。 创建“第三方生活服务商家应用”,审核时效1个工作日;
- 开通解决方案。 核销能力在行业解决方案里,比如“到综行业团购解决方案”“到店餐饮解决方案”,可以整体开通,也可以按能力开通;
- 基础配置。 包括 Webhooks 和 SPI 地址注册,以及 IP 白名单。白名单是可选项,启用后所有接口请求的源 IP 都必须在白名单里;
- 验收准备。 绑定测试店铺,把测试用的抖音账号加白;
- 联调、压测、安全三项验收,全部通过后申请应用上线;
- 商家授权。 应用上线后,商家把应用授权给你,你才能调这家商家的接口。
三项验收里,容易卡住的是这些细节。
联调验收。 用例里填的订单号和 logid 必须来自测试店铺的测试账号。测试商品名称必须包含“测试”,售卖有效期、使用有效期都不能超过14天,提交后人工审核,时效1个工作日。测试店铺不对外展示,下单要在抖音来客后台“商品管理 → 更多 → 生成二维码”,用加白的抖音账号扫码购买。调用商品创建接口时,请求头要加 Rpc-Persist-Life-Test-Data-Access: all。
压测验收。 压的是你提供给抖音调用的 SPI 接口。压测请求都带 X-Stress-Tag: 1 请求头,服务端要识别它,别把压测请求当成真实订单处理。点“发起调试”时,抖音会取参数文件第一条数据重复请求两次,接口没做去重就会出问题。通过标准是成功率大于99.95%(接口返回 error_code=0 才算成功),PCT99 耗时不超过压测计划里配置的超时时长。压测时段只能选周一到周四的23:00到次日7:00。
安全验收。 要逐项提交材料:可登录的系统地址和测试账号;登录口令至少8位、包含三种以上字符,登录页有验证码或访问频次限制;手机号、姓名等隐私字段脱敏展示,手机号保留前3位和后4位;client_secret、client_token 加密存储,不能硬编码、不能明文保存,也不能下发给客户端;从开放平台拿到的敏感字段加密存储,文档推荐 AES256 一类算法;接入 WAF 并提供最近一个月的拦截记录或购买凭证,只开放必要端口。
这些要求都合理,加起来却是实打实的工作量。只想让自己的小程序或门店设备能核抖音券,走完整套流程往往不划算。
十、不想自己办资质:以无限聚核为例
通过无限聚核的 V2 聚合接口,抖音和美团共用一套验券、核销接口,platform 传2代表抖音。无限聚核当前公开 API 文档写明:
- 门店授权。 调
POST /api/hexiao/v2/get/auth/url,传具体门店shopId和platform=2,把返回的链接发给商家,商家在抖音侧确认授权; - 验券。 调“输码验券校验”接口,
code传数字券码,或者扫码得到的完整短链。object_id解析、client_token和poi_id都由服务端处理; - 返回。
payAmount是售卖价(分),dealPrice是售卖价(元),actualPayAmount是用户实付(分),和美团券口径一致。ticketInfo是后续核销必需的凭证,要整段原样保存,不要解析;ticketData是抖音官方响应data对象的完整原文,次卡剩余次数可以从这里读; - 核销。 调“验券”接口,把
ticketInfo原样传回,num是核销数量。次卡会先校验time_card剩余次数; - 判断结果。 只看顶层
success。成功时按下标保存consumeCredential,撤销时要用。platformResult保留抖音原始的data和extra,排查问题时看它; - 计费。 预核销不计费,核销计费,撤销免费。
POST /api/hexiao/v2/ddzh-tuangou-receipt-prepare
Authorization: Bearer <key>
Content-Type: application/json
{
"shopId": 123,
"platform": 2,
"code": "<扫码得到的完整短链,或数字券码>"
}
有两件事,走第三方接口也不会变:每次核销前都要重新预核销,“一次准备配一次验券”的规则还在;撤销时限仍然是1小时。
| 自己入驻抖音服务商 | 通过第三方接口(如无限聚核) | |
|---|---|---|
| 资质 | 入驻认证、对公认证 | 不需要自己的服务商资质 |
| 上线前 | 联调、压测、安全三项验收 | 商家授权后用真实券调试 |
| 自己要实现的 | client_token、poi_id 映射、验券准备、短链解析、三层结果判断 |
调统一的验券、核销、撤销接口 |
| 能用的能力 | 解决方案里开通的全部能力 | 以第三方开放的接口为准 |
| 成本 | 研发、验收和持续运维 | 按核销次数付费 |
十一、常见问题
抖音团购券能直接用明文券码核销吗?
不能直接核销。明文券码只能作为验券准备接口的 code 参数,验券接口的 encrypted_codes 要传验券准备返回的加密券码。把明文券码直接传给验券接口,会报加密码解密失败一类的错误。
抖音验券报“加密码解密失败”是什么原因?
最常见的原因是 encrypted_codes 里传了明文券码,或者传了别的订单、上一次验券准备得到的加密券码。每次验券前重新调验券准备,用这一次返回的 verify_token 和 encrypted_code。
同一个 verify_token 可以用两次吗?
不建议。抖音文档要求验券准备和验券的调用次数一一对应,验券成功后二维码会失效。明确失败的,重新调验券准备再验;结果未知的,先查券状态再决定。
顾客买了3张券,扫码后只想用1张怎么办?
扫码后验券准备会返回这个订单下全部可用的券。让顾客选数量,只把对应数量的 encrypted_code 放进 encrypted_codes,不要整组传入。
抖音次卡怎么一次核销多次?
按抖音验券接口文档,多次卡一次核销多份时,在 encrypted_codes 里放多个相同的加密券码。放之前用 time_card 的 times_count 减去 times_used 算出剩余次数,次数不够就不要发起核销。
抖音团购核销接口的金额单位是什么?
抖音验券准备返回的金额都以分为单位,original_amount 是套餐售价,pay_amount 是用户实付,划线价是 list_market_amount。美团套餐价以元为单位,两个平台混合对账时统一换算成分。
抖音团购券核销后多久内可以撤销?
抖音撤销核销接口文档写明,验券超过一个小时就不可再撤销。撤销要带验券时返回的 verify_id 和 certificate_id,data.error_code 和 extra.error_code 均为0才算撤销成功。
不是抖音服务商,能调用抖音团购核销接口吗?
不能直接调用。抖音生活服务接口要求服务商完成入驻认证、开通解决方案、通过联调压测安全三项验收并上线应用,商家还要把应用授权给你。没有这些条件的,可以用已接入抖音的门店系统,或者通过无限聚核这类第三方接口核销。
通过无限聚核核销抖音券,和核销美团券有什么不同?
接口是同一套,platform 传2代表抖音,code 除了数字券码,还可以传扫码得到的完整抖音短链。金额口径两个平台一致:payAmount 和 actualPayAmount 以分为单位,dealPrice 以元为单位。抖音的撤销时限是1小时,美团是10分钟。



