《1688跨境分销API踩坑:alibaba.cps.* 与 crossborder.* 的授权与佣金计算》(附Python源码)
1688 跨境分销不是“普通 1688 代发 + 加个英文标题”这么简单。alibaba.cps.*是“分销/推广/选品视角”的读接口,佣金/严选价要从商品视图里取,不是自己算;crossborder.*是“跨境买家付款/寻源/跨境宝”能力,重点是授权主体、支付渠道、外币结算、订单必须走对 flow。最坑的是:用错 flow → 拿不到 retailPrice;没签信息共享协议 → cps 商品字段不全;跨境宝不是支付宝 → 是 WorldFirst/外币账户代扣;佣金别用“下游售价×比例”反推,平台按“订单实付(不含运费)×费率”扣。
一、两条能力域先切干净
域 | 典型接口 | 角色 | 干啥 |
|---|---|---|---|
CPS / 分销商品 | alibaba.cpsMedia.productInfo、alibaba.cps.queryOfferDetailActivity | 分销商 / 推广者 | 拿分销价、活动价、包邮条件、推广佣金 |
Cross Border | alibaba.offer.search.crossborder、alibaba.crossBorderPay.url.get、alibaba.trade.payWay.query | 跨境买家 / ERP | 跨境货盘、外币支付、跨境宝收银台 |
分销严选交易 | alibaba.trade.fastCreateOrder / alibaba.trade.fenxiaoOrder.create | 分销商 | 用 boutiquefenxiao / ttpft 等 flow 锁价 |
别把cpsMedia.productInfo当成“下单接口”,也别把crossBorderPay.url.get当成“创建订单接口”。cps 管“这货能赚多少”,crossborder 管“这单怎么付出去”。
二、授权层踩坑(比代码先炸)
1️⃣ 应用权限不是通用权限
普通 1688 交易应用 ≠ 寻源通 ≠ 社交电商采购 ≠ 分销严选
cpsMedia.productInfo通常要订购对应解决方案/分销能力图搜分销、跨境专供、密文面单、跨境宝各自单独开
2️⃣ access_token 是“买家授权”,不是商家 session
用买家 access_token 调 cps / 下单 / 查单
供应商那侧是商家 session,你调不到
token 过期不刷 → 下单直接
TOKEN_EXPIRED
3️⃣ 跨境宝授权是“账户绑定”,不是 OAuth scope 打勾
alibaba.crossBorderPay.url.get 背后是:1688 账号绑定 WorldFirst / 跨境收付账户
用 CNH / 外币余额付 1688 订单
没绑跨境宝 → 返回
400_4 无可使用支付渠道[跨境宝]付款的订单
4️⃣ 分销严选要先签《信息共享协议》
retailPrice/JxhyPrice/ 佣金字段可能不返回你用
consignPrice铺货 → 不是严选价 → 下游毛利算错
三、佣金与分销价:平台给,别自己编
价格优先级(cps 商品视图)
channelPrice > 一件代发包邮价(跨境/抖快常用) promotionPrice > 营销活动价 consignPrice > 分销基准价 retailPrice > 分销严选铺货价(站外分销用这个)
佣金/服务费口径
软件技术服务费 = 订单实付金额(不含运费) × 技术服务费率 站外分销:5% 生鲜/酒水:2.5%(即 5% 的一半) 运费不抽 同一笔订单不重复扣(严选/PLUS/行家选只收一次)
❌ 错误:佣金 = 下游售价 39.9 - 供货价 15 = 24.9 都是我赚的✅ 正确:平台从分销商侧/供应商侧按规则扣费,ERP 要把“平台扣费”当成成本中心,不是事后惊喜。
四、flow 用错 = 价格崩了(重点)
商品标签 | 下单接口 | flow |
|---|---|---|
老严选 isPftOffer=true | fastCreateOrder / fenxiaoOrder.create | fenxiaonew / ttpft |
新严选 isJxhyOffer=true | fastCreateOrder | 1 件 boutiquefenxiao,多件 boutiquepifa |
普通分销 consignPrice 有值 | 分销下单 | fenxiaonew |
混用分销创建 | fenxiaoOrder.create | flow=fenxiao&isSplitJxhy=true 自动拆单 |
商品明明是分销严选,你下出来是普通批发价
毛利模型算 35%,实际成交价高 8%,运费还不包邮
退款时平台说“非严选单不享受 48h/7 天无理由保障”
五、生产向:CPS 商品归一化 + 佣金预估
# ali1688/crossborder/cps_product.py
from dataclasses import dataclass
from typing import Optional
@dataclass
class CpsProductView:
offer_id: str
title: str
channel_price: Optional[float] = None # 一件代发包邮价
promotion_price: Optional[float] = None # 活动价
consign_price: Optional[float] = None # 分销基准价
retail_price: Optional[float] = None # 分销严选铺货价
jxhy_price: Optional[float] = None # 新严选专享价
is_pft_offer: bool = False # 老严选
is_jxhy_offer: bool = False # 新严选
channel_free_postage: bool = False
exclude_area_codes: list[str] = None
commission_rate: Optional[float] = None # 推广佣金(若有)
activity_info: dict = None
@property
def distribution_price(self) -> float:
"""
分销下单/铺货用哪个价:
新严选 > retailPrice
老严选 > consignPrice
活动价仅做营销展示,不直接当代发成本
"""
if self.is_jxhy_offer and self.retail_price:
return self.retail_price
if self.is_pft_offer and self.consign_price:
return self.consign_price
return self.channel_price or self.consign_price or self.promotion_price
# 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
def normalize_cps(raw: dict) -> CpsProductView:
price_model = raw.get("priceModel", {}) or raw.get("price", {}) or {}
return CpsProductView(
offer_id=str(raw.get("offerId") or raw.get("itemId")),
title=raw.get("title", ""),
channel_price=_f(price_model.get("channelPrice")),
promotion_price=_f(price_model.get("promotionPrice")),
consign_price=_f(price_model.get("consignPrice")),
retail_price=_f(price_model.get("retailPrice")),
jxhy_price=_f(price_model.get("JxhyPrice") or price_model.get("jxhyPrice")),
is_pft_offer=bool(raw.get("isPftOffer")),
is_jxhy_offer=bool(raw.get("isJxhyOffer")),
channel_free_postage=bool(price_model.get("channelPriceFreePostage")),
exclude_area_codes=price_model.get("channelPriceExcludeAreaCodes") or [],
commission_rate=_f(raw.get("commissionRate")),
activity_info=raw.get("activityInfo"),
)
def _f(v) -> Optional[float]:
try:
return float(v)
except (TypeError, ValueError):
return None佣金/平台费预估(站外分销)
PLATFORM_TECH_FEE_RATE = 0.05 # 站外分销严选
PLATFORM_TECH_FEE_RATE_FRESH = 0.025 # 生鲜/酒水
def calc_distribution_cost(
paid_amount: float, # 订单实付,不含运费
freight: float,
category: str = "normal",
downstream_sell_price: float = 0.0,
):
rate = PLATFORM_TECH_FEE_RATE_FRESH if category in ("fresh", "alcohol") else PLATFORM_TECH_FEE_RATE
platform_fee = paid_amount * rate
gross = downstream_sell_price - (paid_amount + freight) - platform_fee
return {
"paid_excl_freight": paid_amount,
"freight": freight,
"platform_fee_rate": rate,
"platform_fee": round(platform_fee, 2),
"gross_profit": round(gross, 2),
"note": "平台费按实付不含运费计算,运费不抽成",
}六、跨境支付:crossborder 不是“再调一次 trade.pay”
# ali1688/crossborder/payment.py
class CrossBorderPayClient:
def __init__(self, top_client):
self.top = top_client
def get_pay_url(self, access_token: str, order_ids: list[int]) -> dict:
# 一次别塞 30 个,建议 10 个
if len(order_ids) > 10:
raise ValueError("crossBorderPay 建议一次 <=10 单")
params = {
"access_token": access_token,
"orderIdList": order_ids,
}
# resp = self.top.execute("alibaba.crossBorderPay.url.get", params)
resp = {"success": True, "payUrl": "https://trade.1688.com/order/cashier.htm?orderId=xxx"}
if not resp.get("success"):
return {"ok": False, "err": resp.get("errorCode"), "msg": resp.get("errorMsg")}
return {
"ok": True,
"pay_url": resp["payUrl"],
# 支付链接有效期约 30 分钟,禁止长期缓存
"cant_pay_orders": resp.get("cantPayOrderList", []),
}
def ensure_payable(self, access_token: str, order_id: int) -> bool:
# 先查渠道,再决定跳跨境宝 / 支付宝 / 账期
pw = self.top.execute("alibaba.trade.payWay.query", {
"access_token": access_token,
"orderId": order_id,
})
channels = [c["payWayName"] for c in pw.get("payWays", [])]
return "跨境宝" in channels or "crossBorderPay" in channels跨境下单时序(一件代发到货代仓)
cpsMedia.productInfo ──▶ 拿 retailPrice / 是否包邮 / 是否严选 │ ▼ fastCreateOrder(flow=boutiquefenxiao, receiver=国内货代仓) │ ▼ payWay.query ──▶ 支持跨境宝? │ ▼ crossBorderPay.url.get ──▶ 买家跳收银台 / WorldFirst 扣 CNH │ ▼ 供应商发货到货代仓 ──▶ 国内 track │ ▼ 货代集运/合箱/报关 ──▶ TikTok/Shopee/Mercari 国际段
七、隐藏约束清单(上线前必看)
[ ] 应用订购了“分销 / 寻源通 / 跨境 / 严选”对应能力,不是只有一个 AppKey
[ ] 买家 token 有刷新,跨境宝绑定在买家账号上
[ ]
cpsMedia.productInfo返回价格用优先级,不把promotionPrice当代发成本[ ] 新严选用
boutiquefenxiao,老严选用fenxiaonew/ttpft,混单用isSplitJxhy=true[ ]
retailPrice有值才铺货,无价 SKU 直接过滤[ ] 平台佣金 = 实付不含运费 × 费率,不按下游售价算
[ ] 跨境宝支付链接 30 分钟过期,不落库复用
[ ] 非包邮区域(新疆/西藏/港澳台/海外)单独声明,不然毛利变负
[ ] 密文面单只在下游平台支持时传
encryptOutOrderInfo,不解密再传明文[ ] 退款/退货时平台费是否退还,按账单明细核,不假设“全退”
八、和前几篇收口
《1688 商品 API》:
offer.get/product.get是批发主数据;cpsMedia.productInfo是“能分销吗、赚多少”《1688 订单 API》:下单后状态机不变,但跨境单多一层“是否已跨境宝支付”
《统一采购适配层》:
offerId+skuId上要挂distribution_view(retailPrice/flow/commission)《两套接口边界》:cps 是“推广/选品读通道”,crossborder 是“跨境付款/寻源能力”,都不是闲鱼/Mercari 的销售侧接口
《六大坑》:这里新增——flow 错、协议没签、跨境宝没绑、佣金按售价算
九、一句话收口
1688 跨境分销的坑不在签名,而在:cps 给你“能赚多少”的视图,crossborder 决定“钱怎么跨过去”;retailPrice 是平台发的牌,flow 是发牌动作,佣金是实付不含运费的税式扣除。ERP 别当“倒卖中间件”,要当“分销合规账房”:价格认平台、flow 认标签、佣金认实付、跨境认绑定。