×

《1688 API:落地方案、接口边界与业务踩坑 —— 从采购到分销的全链路对接》(附Python源码)

万邦科技Lex 万邦科技Lex 发表于2026-09-29 09:18:27 浏览32 评论0

抢沙发发表评论

《1688 API:落地方案、接口边界与业务踩坑 —— 从采购到分销的全链路对接》(附Python源码)

先拍结论:
1688 不是“另一个闲鱼”。它是B2B 供货底座:你这边是买家/分销商,1688 商家是供应商。
接口边界必须按角色切:选品(读)→ 采购下单(写)→ 支付(资金)→ 履约回传(物流/退款)→ 分销回流(下游平台)。
最坑的不是签名,而是:库存不是强一致、密文地址要白名单、分销价靠 flow、物流回传会静默失败、Token 会过期、QPS 不是日额度。

一、1688 对接的角色模型(先别写代码)

角色
在 1688 的身份
持有凭证
能干什么
下游卖家
1688 买家 / 分销商
买家 access_token
搜品、下单、查单、处理退款
供应商
1688 商家
商家 session
接单、发货、退换货、回传物流
ISV/ERP
开放平台应用
AppKey/AppSecret
代买家/代分销商调 API
跨境卖家
寻源通/跨境分销买家
跨境标签应用
拿 HS Code、申报价、账期支付
⚠️ 和闲鱼不同:闲鱼 ISV 是“代卖家管自己店”;1688 ISV 是“代买家去买货 / 代分销商管供应链”。
所以 1688 的 trade.order.create 是用买家 token 调的,不是商家 token。

二、全链路接口地图(采购 → 分销)

选品层(读)
  alibaba.product.search / product.get / product.batch.get
  alibaba.product.category.get
  alibaba.cpsMedia.productInfo(分销价/佣金)
        │
        ▼
采购层(写)
  alibaba.createOrder.preview       价格/运费/优惠预校验
  alibaba.trade.fastCreateOrder     轻量下单(代发首选)
  alibaba.trade.order.create        完整下单
  alibaba.trade.fenxiaoOrder.create 分销/代发回流单(带下游渠道+下游单号)
        │
        ▼
支付层(资金)
  alibaba.trade.payWay.query
  alibaba.trade.pay / protocolPay.preparePay(免密,需签约)
  alibaba.crossBorderPay.url.get(跨境宝)
        │
        ▼
履约层(供应商动作 + 回传)
  alibaba.trade.order.get           查状态/运单号
  alibaba.trade.getLogisticsTraceInfo
  alibaba.logistics.repush_tracking 物流重推(单号丢了用)
        │
        ▼
售后层
  alibaba.trade.refund.get
  分销退货退款创建 / 售后订单回传(分销方案专用)
官方方案里“ERP 分销(分销商侧)”和“分销严选(服务商侧)”是两套权限,别混申。

三、六大业务踩坑(比技术坑更贵)

1️⃣ 库存不是强一致:“显示有货”≠“能下单”

  • product.get 的库存是快照,不是占用后库存

  • 1688 一件代发是订单触发式扣减:下游付钱 → 才向供应商占库存

  • 正确做法:下单前调 createOrder.preview,下单失败按 SUB_ORDER_NOT_ENOUGH 类错误回退到备供

2️⃣ 分销价靠 flow 和 retailPrice

  • 老严选:isPftOffer=true + ttpft

  • 新严选:isJxhyOffer=true + boutiquefenxiao / boutiquepifa

  • 用错 flow → 价格不对 / 下单失败“无 retailPrice”

3️⃣ 密文地址不是“传进去就行”

  • 抖音/淘宝/拼多多下游订单:姓名手机脱敏

  • 1688 侧要用 encryptOutOrderInfo 之类字段传密文,不是自己解密再传明文

  • 没白名单:接口直接权限拒绝

  • 传明文:占用解密额度,甚至违规

4️⃣ 物流回传会“静默成功”

  • 供应商点了发货,分销商后台“已发货但无单号”

  • 原因:物流渠道没做电子面单授权 / 网络抖动 / 回传超时

  • 解法:定时扫 status=shipped and tracking_no is null → 调重推接口,重推前先查渠道授权

5️⃣ Token 有效期短,必须刷

  • 1688 买家 access_token 通常几小时到一天级,不是永久

  • 生产里要有:刷新器 + 多卖家 token 表 + 过期重授权二维码

  • 把 token 写死在配置里 = 一周后半夜报警

6️⃣ QPS ≠ 日调用量

  • 商品搜索默认 ~10/s,订单类 ~20/s

  • 500 个 offer × 30s 轮询 = 16.7/s,单 Key 必限流

  • 正解:事件订阅(价格/库存变更)+ 下单前预览 + 本地缓存 + 多 AppKey 分域


四、生产向源码:1688 采购→分销骨架

# commerce_mesh/suppliers/ali1688/client.py
import time
import uuid
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional


class Ali1688Env(str, Enum):
    SANDBOX = "https://gw-api.passport.alibaba.com/sandbox"
    PROD = "https://gw.open.1688.com/openapi"


class OrderStatus(str, Enum):
    WAIT_PAY = "wait_pay"
    PAID = "paid"
    SHIPPED = "shipped"
    SIGNED = "signed"
    REFUNDING = "refunding"
    CLOSED = "closed"


@dataclass
class BuyerToken:
    seller_erp_id: str
    access_token: str
    refresh_token: str
    expires_at: float
    account: str = ""


@dataclass
class PurchaseReq:
    offer_id: str
    sku_id: str
    qty: int
    receiver: dict          # 明文/密文由 downstream 决定
    outer_order_no: str     # 下游平台订单号
    channel: str = "shopee" # shopee/tiktok/taobao/douyin
    flow: str = ""          # boutiquefenxiao / ttpft / ""
    encrypt_out_order_info: Optional[str] = None

# 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
class TokenStore:
    """聚石塔/内网:token 不出内网"""
    def __init__(self):
        self._t: dict[str, BuyerToken] = {}

    def save(self, t: BuyerToken):
        self._t[t.seller_erp_id] = t

    def usable(self, erp_id: str) -> Optional[str]:
        t = self._t.get(erp_id)
        if not t:
            return None
        if t.expires_at - 300 < time.time():
            return None
        return t.access_token


class Ali1688PurchaseClient:
    def __init__(self, token_store: TokenStore, qps_limiter):
        self.tokens = token_store
        self.limiter = qps_limiter
        self.preview_cache: dict[str, float] = {}

    # ---------- 1. 下单前预览(防超卖/防错价) ----------
    def preview(self, erp_id: str, req: PurchaseReq) -> dict:
        token = self.tokens.usable(erp_id)
        if not token:
            return {"ok": False, "code": "TOKEN_EXPIRED"}

        self.limiter.acquire("createOrder.preview")   # 令牌桶

        # 伪调用:alibaba.createOrder.preview
        preview = {
            "offer_id": req.offer_id,
            "sku_id": req.sku_id,
            "unit_price": 39.9,
            "freight": 4.0,
            "retail_price": 39.9 if req.flow else None,
            "available": True,
        }
        if req.flow and preview["retail_price"] is None:
            return {"ok": False, "code": "NO_RETAIL_PRICE", "msg": "该SKU未报名严选"}
        return {"ok": True, "preview": preview}

    # ---------- 2. 创建采购单 ----------
    def create_purchase_order(self, erp_id: str, req: PurchaseReq) -> dict:
        pre = self.preview(erp_id, req)
        if not pre["ok"]:
            return pre

        token = self.tokens.usable(erp_id)
        self.limiter.acquire("trade.order.create")

        # 分销/代发单:带下游单号 + 密文
        params = {
            "offerId": req.offer_id,
            "skuId": req.sku_id,
            "quantity": req.qty,
            "outerOrderNo": req.outer_order_no,
            "downstreamChannel": req.channel,
        }
        if req.flow:
            params["flow"] = req.flow
        if req.encrypt_out_order_info:
            params["encryptOutOrderInfo"] = req.encrypt_out_order_info
        else:
            params["receiver"] = req.receiver   # 明文仅限非密文下游

        # resp = top_execute(method="alibaba.trade.fenxiaoOrder.create", ...)
        resp = {
            "success": True,
            "purchase_order_id": f"1688-{uuid.uuid4().hex[:12]}",
            "payable_amount": 39.9 * req.qty + 4.0,
        }
        return {"ok": True, **resp}

    # ---------- 3. 物流回传补偿 ----------
    def repair_missing_tracking(self, erp_id: str, shipped_orders: list[dict]) -> list[dict]:
        fixed = []
        for o in shipped_orders:
            if o.get("status") == "shipped" and not o.get("tracking_no"):
                # 1. 查渠道授权
                # 2. 调 alibaba.logistics.repush_tracking
                fixed.append({
                    "purchase_order_id": o["purchase_order_id"],
                    "action": "repush_tracking",
                    "note": "渠道未授权时重推无效,需先电子面单授权",
                })
        return fixed

五、和前面系列的拼接关系

  • 《聚石塔入塔》:1688 买家端可以公网调,但下游 PII / 密文 / 分销商关系建议内网存

  • 《闲鱼 order.ship》:闲鱼是“卖家用 token 发自己单”;1688 是“买家用 token 买别人货”

  • 《两套接口边界》:1688 商品采集 ≠ 1688 代发下单;选品池 → 采购池必须过一道“供应商白名单 + 分销协议”

  • 《六大坑》:时区/税价/超卖/编码/映射/消息丢失,在 1688 里变成:库存快照、retailPrice、密文面单、物流静默、SKU spec 映射、回调丢失

  • 《中台调度》:Ali1688Adapter 只负责“采购侧统一模型”,不要让它知道 TikTok/Shopee 的店铺逻辑


六、落地检查表(上线前)

  • [ ] 企业实名 + 应用权限(商品/交易/物流/退款)都开了

  • [ ] 跨境场景额外开“寻源通 / 跨境分销”标签

  • [ ] Token 有刷新,不下发到前端

  • [ ] 下单前必调 createOrder.preview

  • [ ] 分销单用对 flow 和 retailPrice

  • [ ] 下游密文订单走密文字段,不解密

  • [ ] 物流回传有“已发无单”补偿任务

  • [ ] 库存变更走消息订阅,不 30s 全量轮询

  • [ ] QPS 令牌桶 + 多 AppKey 分域

  • [ ] 供应商维度建“备供表”,主供售罄自动切


七、一句话收口

1688 对接的成熟度,不看你会不会调 trade.order.create,
而看你能不能处理:库存快照、严选 flow、密文面单、物流静默、token 过期、供应商跑路。
选品是数学,采购是状态机,分销是合规,履约是补偿——四件事用一套 ERP 模型撑起来,才算“对接完了”。


群贤毕至

访客