当前位置: 首页 > news >正文

[特殊字符]《京东订单API(jd.order.detail.get)对接ERP:企业认证+OAuth授权避坑指南》(附Python源码)

🧾《京东订单API(jd.order.detail.get)对接ERP:企业认证+OAuth授权避坑指南》(附Python源码)

直接说结论先:

京东订单类接口(jingdong.pop.order.search/jd.order.detail.get/jingdong.etms.waybill.send个人开发者应用无权限,必须:

  1. 企业支付宝/企业对公认证​ 创建「商家自用型应用」

  2. 申请订单相关接口权限(需填场景说明)

  3. 店铺卖家账号OAuth 2.0授权获取access_token(session参数)

个人应用调会返回403 no permission / invalid method,属正常限制。


一、现象对照表

你做的

返回

原因

个人应用 +jd.order.detail.get

403 no permission/invalid method

个人号无订单接口权限

企业应用未申请接口

同上 403

控制台→API权限→申请jingdong.pop.order.search/jd.order.detail.get

传了买家​ AccessToken

空/403

必须是店铺卖家​ OAuth 换的 token

沙箱调订单

返回 mock/空

沙箱不支持真实订单,仅验签名

session 过期

Invalid access_token

refresh_token刷新


二、企业认证 + OAuth授权流程(关键!)

  1. 企业认证

    JOS控制台 → 账户管理 → 企业实名(营业执照 + 企业对公/企业支付宝)

  2. 创建应用

    应用类型选「商家自用型应用」(ISV需额外软服中心入驻)

  3. 申请接口权限

    应用→接口权限→申请:

    • jingdong.pop.order.search(订单列表)

    • jd.order.detail.get(订单明细)

    • jingdong.etms.waybill.send(发货回填运单)

    • jingdong.etms.trace.get(物流轨迹)

    📌 场景说明示例:"ERP系统同步本店铺已付款订单生成内部销售单,并回写发货物流,仅访问授权店铺数据"

  4. 卖家OAuth授权换取 AccessToken

    ① 引导卖家访问: https://auth.jd.com/oauth2/toLogin.action ?response_type=code &client_id=YOUR_APP_KEY &redirect_uri=URLENCODE(你在应用配置的回调地址) &state=erp_jd ② 回调 → redirect_uri?code=xxx ③ POST https://auth.jd.com/oauth2/accessToken grant_type=authorization_code client_id=APP_KEY client_secret=APP_SECRET code=xxx redirect_uri=同上 → {access_token, refresh_token, expires_in, user_nick}

    access_token= JOS接口中的access_token(session) 参数


三、Python:订单列表 + 明细调用封装(含权限提示)

# jd_order_sync.py """ 京东订单同步 Demo(企业应用 + 卖家AccessToken) jingdong.pop.order.search → jd.order.detail.get 依赖: requests (pip install requests) """ import hashlib import json import requests import time from datetime import datetime, timedelta from typing import Dict, List # 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex class JdOrderClient: GW = "https://api.jd.com/routerjson" def __init__(self, app_key: str, app_secret: str): self.ak = app_key self.as_ = app_secret # ─── JOS MD5签名(秒级timestamp)─── def _sign(self, p: Dict) -> str: filt = sorted((k, v) for k, v in p.items() if v is not None and str(v).strip() != '' and k != 'sign') qs = ''.join(f"{k}{v}" for k, v in filt) return hashlib.md5(f"{self.as_}{qs}{self.as_}".encode() ).hexdigest().upper() def _call(self, method: str, biz: Dict, access_token: str): api_p = { "app_key": self.ak, "method": method, "timestamp": str(int(time.time())), # ← 秒级! "format": "json", "v": "2.0", "sign_method": "md5", "360buy_param_json": json.dumps(biz, ensure_ascii=False, separators=(',', ':')), "access_token": access_token } api_p["sign"] = self._sign(api_p) r = requests.post(self.GW, data=api_p, timeout=15) r.raise_for_status() d = r.json() resp_key = method.replace(".", "_") + "_response" if resp_key not in d: for k in d: if k.endswith("_response"): resp_key = k break data = d.get(resp_key, d) # 权限/业务错误检测 if isinstance(data, dict): err = data.get("error_response") or d.get("error_response") if err: code = str(err.get("code", "")) zh = err.get("zh_desc") or err.get("en_desc") if "no permission" in zh or "invalid method" in zh: raise PermissionError( "❌ 【无权限】订单接口需:\n" " 1) 企业实名商家应用\n" " 2) 已申请 jingdong.pop.order.search / jd.order.detail.get\n" " 3) access_token 须是【卖家】OAuth授权所得(非买家token)\n" f" 原始: [{code}] {zh}" ) raise Exception(f"JOS [{code}]: {zh} sub:{err.get('sub_code')}") return data # ─── 增量拉取订单列表 ─── def list_orders(self, access_token: str, minutes_back: int = 30, order_state: str = "WAIT_SELLER_STOCK_OUT", page: int = 1, page_size: int = 50) -> Dict: now = datetime.now() start = (now - timedelta(minutes=minutes_back)).strftime("%Y-%m-%d %H:%M:%S") end = now.strftime("%Y-%m-%d %H:%M:%S") return self._call( "jingdong.pop.order.search", { "start_modified": start, "end_modified": end, "order_state": order_state, # WAIT_SELLER_STOCK_OUT=已付待发 "page": page, "page_size": min(page_size, 100) }, access_token ).get("popOrderSearch", {}).get("orderSearch", {}) # ─── 订单明细 ─── def get_detail(self, access_token: str, order_id: str) -> Dict: return self._call( "jd.order.detail.get", {"orderId": order_id}, access_token ).get("orderDetail", {}).get("orderInfo", {}) # ========================================================= # 使用示例 # ========================================================= if __name__ == "__main__": client = JdOrderClient( app_key="YOUR_JD_ENTERPRISE_APP_KEY", app_secret="YOUR_JD_APP_SECRET" ) SELLER_TOKEN = "SELLER_ACCESS_TOKEN" # ← OAuth2 换取的卖家 token try: result = client.list_orders(SELLER_TOKEN, minutes_back=30) orders = result.get("orderInfoList", []) or [] total = result.get("orderTotal", 0) print(f"✅ 近30分钟变更订单: {len(orders)} / 共计{total}") for o in orders[:3]: detail = client.get_detail(SELLER_TOKEN, str(o.get("orderId"))) print(f" 单 {detail.get('orderId')} {detail.get('orderState')} " f"¥{detail.get('orderPrice')}") except PermissionError as pe: print(pe) print("\n➡ 解决:企业实名→创建自用型应用→申请订单权限→卖家OAuth授权→填入SELLER_TOKEN") except Exception as e: print("❌", e)

四、OAuth Token 交换最简片段(补全用)

def jd_exchange_token(app_key, app_secret, code, redirect_uri): r = requests.post("https://auth.jd.com/oauth2/accessToken", data={ "grant_type": "authorization_code", "client_id": app_key, "client_secret": app_secret, "code": code, "redirect_uri": redirect_uri }, timeout=15) r.raise_for_status() return r.json() # access_token / refresh_token / expires_in / user_nick

五、避坑清单(京东订单对接必看)

现象

解决

个人应用调订单

403 no permission

企业实名商家自用应用

接口未申请

同上 403

应用→API权限→申请订单接口

传买家 token

空/403

必须用店铺卖家​ OAuth 换的 AccessToken

token 过期

Invalid access_token

refresh_token提前刷新(建议过期前7天)

沙箱返回空订单

正常

沙箱只验签,用生产网关

ISV应用403

未入驻软服/未绑定店铺

完成 ISV 入驻并绑定授权店铺

timestamp 毫秒

Invalid Timestamp

JOS用秒级int(time.time())


六、面试/方案一句话

京东订单API(jingdong.pop.order.search/jd.order.detail.get)须企业实名商家应用 + 申请订单权限 + 卖家OAuth AccessToken(session参数);增量按start_modified/end_modified时间窗拉取防超量,遇403先确认以上三点,沙箱仅验签名不返回真实订单。

需要我补APScheduler 定时增量订单同步(断点续跑+Token自动刷新)​ 或京东发货回填jingdong.etms.waybill.send完整参数​ 吗?

http://www.jsqmd.com/news/1118678/

相关文章:

  • Unity碰撞检测优化与Tag系统实战指南
  • Python Pygame坦克绘制教程:从零开始学图形编程
  • Unity编辑器入门:核心功能与3D场景开发实战
  • UE4中PSO与Shader编译优化实战指南
  • 开源无限画布工作台:可视化编排AI视觉创作全流程
  • 工业级传感器与执行器控制系统核心组件解析与应用
  • EvolVE框架:AI驱动的Verilog自动生成与优化技术
  • 提升大模型浏览器Agent稳定性:增强视觉感知与工程实践
  • AI大模型学习路线与实战指南
  • Pygame入门:从零开发2D游戏《飞机大战》实战指南
  • Unity实战第二版:面向工业级项目的工程化重构
  • AI绘画工作流革新:开源无限画布infinite-canvas部署与实战指南
  • 无人机航拍小目标检测:YOLOv8改进与工程落地全解析
  • 基于YOLOv8的铁路障碍物检测系统:从原理到部署的完整实践指南
  • YOLO-Master实战解析:MoE架构如何重塑目标检测的算力分配与部署策略
  • Unity图片处理全流程实战:截图、下载与跨平台保存
  • 教育硬件AI集成实战:从零构建智能辅导与专注学习系统
  • Unity导出.glb模型全流程指南
  • Unreal Engine插件开发:GPU统计模块构建指南
  • Unity安卓游戏手柄支持实战:从输入原理到完整实现
  • 360游戏盾SDK集成指南:防护DDoS攻击与游戏安全实践
  • 从零搭建AI自动追踪摄像机:YOLO目标检测与云台伺服控制实战
  • ASP.NET SQL注入进阶审计:ORM、存储过程与动态查询的隐蔽风险
  • 研究生论文写作AI工具全流程指南
  • 西门子交换机环网冗余设置(理论篇)
  • Python深度学习实战:从环境搭建到模型部署
  • 提升AI智能体成功率:构建多策略融合的浏览器感知层实战
  • Unity网络通信实战:TCP/UDP双通道与协议优化
  • Python游戏开发入门:Pygame实现坦克大战
  • STM32L442KC与SLO2016低功耗LoRa通信方案解析