×

《抖店开放平台API:落地方案、接口边界与业务踩坑 —— 2026.7.1 商品发布接口收费》(附 Python 源码)

万邦科技Lex 万邦科技Lex 发表于2026-10-16 13:47:43 浏览42 评论0

抢沙发发表评论

《抖店开放平台API:落地方案、接口边界与业务踩坑 —— 2026.7.1 商品发布接口收费》(附 Python 源码)

一、2026.7.1 新规先拍死(官方口径)

抖店开放平台 2026-06-16 发《收费范围调整公告》+《技术服务费规则 V1.3》,2026-07-01 起生效:
类型
接口
抖店云内
抖店云外(公网/ECS/本地)
计费
基础 API
/product/addV2、/product/addSchema 等
¥0.018 / 百次 / AppKey
¥0.18 / 百次 / AppKey(×10)
按实际调用量
基础 API
订单/售后/商品详情等
¥0.018 / 百次
¥0.18 / 百次
按实际调用量
增值 API
批量解密等
¥0.05 / 百次
禁止云外调用
按实际调用量
新增收费类目:
  • 电商软件服务商 → 商品供应链

  • 电商软件服务商 → 选品铺货-微应用

结算模型:
预充值。每月 5 号扣上月费用;余额不足 = 硬断调用(不是 429 限流);已充金额不退、不提现、不转账。
这点和拼多多一样毒:
淘宝/京东是“用后结”,抖店/拼多多是“先充钱,欠费断气”。

二、抖店 API 的“视角”和别家不同

平台
商品发布
订单真相
推送
淘宝
item.add 聚石塔内
trade.fullinfo.get
DSS 推送
京东
jd.goods.create / read 模型
jd.order.detail.get
JMQ
拼多多
pdd.goods.add
pdd.order.information.get
增量轮询为主
抖店
/product/addV2 / /product/addSchema
/order/orderDetail
数据推送(订单/售后→RDS)免费
抖店最舒服的一点:
订单/售后数据推送是免费产品,官方明着建议你“云内调用 + 数据推送”代替轮询。
抖店最坑的一点:
商品发布以前是铺货 ERP 的“免费洼地”,2026.7.1 起填平了。
店群/选品铺货/微应用 ISV 的“日发几万 SKU”模型直接变成本中心。

三、商品发布接口边界(别把 addV2 当 detail 用)

接口
作用
收费?
/product/publishPreCheck
发品前置校验(类目/资质/门槛)
官方定位为前置校验,别当 addV2 发
/product/addSchema
Schema 草稿/结构化发品
收费(基础 API)
/product/addV2
直接发布商品
收费(基础 API)
/product/editV2
编辑商品
是否收费看当期收费列表
/product/listQuery
商品列表
看收费列表
/product/detail
商品详情
看收费列表
/spu/query
SPU 是否存在
批量化摊薄
数据推送(订单/售后)
变更写 RDS
免费
生产铁律:
免费前置校验 → 拦掉必败请求
批量查 SPU / 类目 / 属性 → 摊薄
addSchema 建草稿 → 同源商品复用
addV2 正式发 → 只发一次
listQuery 兜底 → 别逐单 detail

四、成本测算(店群一眼看懂)

# douyin/cost_calc.py
class DouyinErpCost:
    RATES = {
        "cloud_inner": 0.018 / 100,   # 元/次
        "cloud_outer": 0.18 / 100,    # 元/次
    }

    def monthly(self, calls_per_day: int, shops: int, env: str, days=30):
        if env not in self.RATES:
            raise ValueError(env)
        unit = self.RATES[env]
        total_calls = calls_per_day * shops * days
        return total_calls * unit


if __name__ == "__main__":
    c = DouyinErpCost()
    # 单店日 1 万次发布类调用
    print("云内 1店:", c.monthly(10_000, 1, "cloud_inner"))   # 54.0
    print("云外 1店:", c.monthly(10_000, 1, "cloud_outer"))   # 540.0
    print("云内 20店:", c.monthly(10_000, 20, "cloud_inner")) # 1080.0
    print("云外 20店:", c.monthly(10_000, 20, "cloud_outer")) # 10800.0
店群场景:
  • 100 店 × 日 3000 发品调用

  • 云内:≈ ¥1620 / 月

  • 云外:≈ ¥16200 / 月

云外不是“贵一点”,是把商品发布 ERP 的利润模型打穿。

五、抖店签名 Client(method + timestamp 秒级)

# douyin/client.py
import hashlib
import time
import requests


class DouyinOpenClient:
    GATEWAY = "https://openapi-fxg.jinritemai.com/"

    def __init__(self, app_key, app_secret, access_token=None, timeout=5):
        self.app_key = app_key
        self.app_secret = app_secret
        self.access_token = access_token
        self.timeout = timeout
# 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
    def _sign(self, params: dict) -> str:
        flat = {k: v for k, v in params.items() if v is not None and k != "sign"}
        qs = "".join(f"{k}{v}" for k, v in sorted(flat.items()))
        raw = self.app_secret + qs + self.app_secret
        return hashlib.md5(raw.encode("utf-8")).hexdigest().upper()

    def execute(self, method: str, biz: dict):
        params = {
            "app_key": self.app_key,
            "method": method,
            "timestamp": str(int(time.time())),
            "v": "2.0",
            "sign_method": "md5",
            "format": "json",
        }
        if self.access_token:
            params["access_token"] = self.access_token
        params.update(biz)
        params["sign"] = self._sign(params)

        resp = requests.post(self.GATEWAY, data=params, timeout=self.timeout)
        return resp.json()
⚠️ 抖店:
  • 时间戳秒级

  • app_secret 头尾包

  • 公共参数 + 业务参数一起排

  • 和拼多多很像,但 gateway / method 命名体系不同


六、预充值余额守卫(和拼多多同思路,但按月扣)

# douyin/balance_guard.py
class DouyinBalanceGuard:
    def __init__(self, redis, client,
                 warn_yuan=200.0, stop_yuan=50.0, alarm=None):
        self.r = redis
        self.client = client
        self.warn = warn_yuan
        self.stop = stop_yuan
        self.alarm = alarm
# 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
    def cached(self):
        v = self.r.get("douyin:balance")
        return float(v) if v else 999999.0

    def refresh(self):
        # 调开放平台账户/费用查询接口(伪代码)
        resp = self.client.execute("open.account.balance.query", {})
        bal = float(resp["data"]["balance"])
        self.r.set("douyin:balance", bal, ex=120)
        return bal

    def pre_check(self, is_paid_api=True):
        if not is_paid_api:
            return
        bal = self.cached()
        if bal <= self.stop:
            self.alarm and self.alarm(f"抖店余额熔断: {bal}")
            raise CircuitOpen("douyin balance too low")
        if bal <= self.warn:
            self.alarm and self.alarm(f"抖店余额预警: {bal}")
规则:
  • 订单推送(免费):照常消费

  • addV2 / addSchema / 收费详情:先过 guard

  • 欠费不是限流,是发品链路整段熄火


七、发品降本:把“N 次散弹”合并成“1 次收费”

# douyin/product_publisher.py
class ProductPublisher:
    def __init__(self, client, guard, bucket):
        self.client = client
        self.guard = guard
        self.bucket = bucket
# 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
    def publish_batch(self, products: list):
        # 1) 免费前置校验
        pre = self.client.execute("/product/publishPreCheck", {
            "products": products
        })
        valid = [p for p in products if pre_ok(pre, p)]
        if not valid:
            return []

        # 2) 批量查 SPU 是否存在(摊薄)
        existing = self.batch_spu_query([p["outer_spu_id"] for p in valid])

        # 3) 同源商品先建 schema 草稿
        drafts = self.build_schema_drafts(valid)

        # 4) 只对新 SPU 调 addV2
        for p in drafts:
            if p["spu_id"] in existing:
                continue
            self.guard.pre_check(is_paid_api=True)
            self.bucket.acquire()
            self.client.execute("/product/addV2", p)

    def batch_spu_query(self, outer_ids: list):
        out = {}
        for i in range(0, len(outer_ids), 50):
            chunk = outer_ids[i:i+50]
            resp = self.client.execute("/spu/query", {"outer_spu_ids": chunk})
            out.update(parse_spu(resp))
        return out

    def build_schema_drafts(self, products):
        # 同源(同图/同详情/不同规格)合成一个 schema
        groups = group_by_template(products)
        drafts = []
        for g in groups:
            self.guard.pre_check(is_paid_api=True)
            self.bucket.acquire()
            d = self.client.execute("/product/addSchema", g)
            drafts.append(d)
        return drafts
降本公式(经验):
散弹式:preCheck(0?) + spu查×N + addV2×N + detail×N
合并式:preCheck(1) + spu查(N/50) + addSchema(组数) + addV2(新SPU数) + listQuery(1/20)
铺货型 ERP 通常能砍掉 60%~75% 收费调用。

八、订单侧:推送为主,轮询兜底

抖店数据推送(免费)
  └─ 订单/售后变更 → RDS
        └─ ERP 读库 + 状态机

每 5~10 min:
  /order/searchList(收费基础API)
     └─ 补漏单/晚到事件

详情:
  /order/orderDetail
     └─ 真相源,别拿列表写业务
和淘宝 DSS、京东 JMQ 同构:
推送/消息 = 触发器,列表 = 兜底,详情 = 法官。

九、云内部署决策(抖店比拼多多更硬)

场景
建议
自研单店 ERP
云外能跑,但发品/订单量大就亏
铺货/店群/选品微应用
必须抖店云内
订单地址/手机解密
云外直接无权限(和淘宝增值/拼多多增值同逻辑)
大促
云内 + 推送 + 限流桶 + 余额守卫
架构:
抖店云内 ECS
 ├─ DyBaseClient   基础API(订单/商品/库存)  令牌桶
 ├─ DyAdvClient    增值API(解密)            单独AppKey + 强制云内
 ├─ PushConsumer   数据推送 → RDS             免费
 └─ Redis          幂等键 / 日调用计数 / 余额缓存

十、错误分类(抖店特有)

现象
处理
sign invalid
secret/排序/时间戳
access_token expired
刷新 1 次
no permission / 非云内调用
增值 API 别云外调
系统错误/余额类
熔断 + 充值,不重试业务
限流
退避
网络超时
退避,但别当“发布失败”直接重发(会双发)
发品审核挂起
不是接口错,进人工/异步审核流
发品最阴的 bug:
超时 → 你重试 addV2 → 同商品发两次 → 重复 SPU / 类目违规 / 被平台判铺货异常。
解决:
idempotency_key = sha1(shop_id + outer_spu_id + spec_fingerprint)
if dedup.exists(idempotency_key):
    return existing_product

十一、和前几篇收口

  • 1688:基础免费,QPS 卡脖,签名 secret 头尾

  • 淘宝 TOP:聚石塔内外 10 倍,DSS 推送免费

  • 京东 JOS:云鼎内稳,POP 时间窗滚动

  • 拼多多:预充值,云外 ×10,增值禁外

  • 抖店:预充值 + 云外 ×10 + 商品发布 2026.7.1 起收费 + 数据推送免费

一句话:
抖店 2026.7.1 之前,铺货 ERP 的潜规则是“商品发布不要钱,拼命发”;
2026.7.1 之后,规则变成“发一次就计费,云外发一次顶云内十次,欠费不是限流是断气”。
能活下来的抖店 ERP 不是“能发品”,而是:
前置校验拦废单、SPU 批量查、schema 并草稿、addV2 只发新、推送替轮询、余额守卫在 Client 层。


群贤毕至

访客