01 — Overview
概览
https://kjlong.com/developers/agent.md
开放接口面向店铺开发者与自动化 agent——适合用脚本批量上品、对接自有
ERP/选品系统、驱动采集工具,或让 agent 自动完成商品录入。
单店脚本用店铺级 sk_,需要在多家店之间切换的工具用账号级
ak_(见 鉴权与 Token)。所有请求走统一的 Base URL:
| Base URL | https://api.kjlong.com |
|---|---|
| 协议 |
HTTPS。写接口 POST +
multipart/form-data,读接口 GET + query 参数
|
| 鉴权方式 |
请求头 Authorization: Bearer <token>
—— 店铺级 sk_ 或账号级 ak_ |
02 — Authentication
鉴权与 Token
接口以 API Token 鉴权,两种令牌共用同一个请求头:
Authorization: Bearer <sk_ 或 ak_> 两者都在商户后台「设置 → 开发者」页面获得,区别在于 作用范围与店铺怎么指定:
| — | sk_ 店铺级 | ak_ 账号级 |
|---|---|---|
| 作用范围 | 一店一枚,绑死单个店铺 | 覆盖账号名下全部店铺 |
| 怎么拿 | 「设置 → 开发者 → 店铺 API Token」手动生成 | 「设置 → 开发者 → Chrome 采集插件」授权插件时自动签发 |
| 数量 | 每店一枚(重新生成即作废旧的) | 可有多枚(多设备各一枚),可逐枚单独吊销 |
| 店铺由谁定 | Token 本身 | 请求头 X-Store-Id |
X-Store-Id | 不需要,也不应该带(带了会被忽略) | 调店铺维度端点时必须带 |
| 典型用途 | 服务器上的定时脚本、自有 ERP 对接单店 | Chrome 采集插件、需要在多店间切换的工具 |
已在用 sk_ 的接入方无需任何改动。 sk_ 的行为与此前完全一致:店铺归属由 Token 决定,请求里的
storeId 字段被忽略,不需要也不要带 X-Store-Id。
ak_ 的 X-Store-Id 规则
账号级 Token 覆盖多家店,所以每次调用都要说明「打哪家店」。值为店铺的数字 ID,从 店铺列表 获取:
Authorization: Bearer ak_xxx
X-Store-Id: 3 -
后端校验该店铺是否属于该 Token 所属账号,不通过即拒绝——
ak_拿不到别人的店。 -
X-Store-Id缺失或不是数字 →4100(HTTP400)。Token 本身没问题,纯参数问题。 -
X-Store-Id指向的店铺不存在,或存在但不属于该账号 →4404(HTTP404)。 两种情况故意不区分,避免接口被拿来探测某个 storeId 是否存在。 -
唯一不带
X-Store-Id的端点是/openapi/store/list——它天然没有店铺维度。
鉴权失败统一返回:Token 无效或缺失 → code = 4001(HTTP
401);Token 已停用或已被吊销 → code = 4002(HTTP
403)。详见 错误码。
03 — Response Envelope
响应信封
所有响应都是统一信封 { code, msg, data, success }:
{
"code": 0,
"msg": "success",
"data": { },
"success": true
} | 字段 | 类型 | 说明 |
|---|---|---|
success | bool | 成功与否的权威判据,成功为 true |
code | int | 业务码,成功为 0;失败见错误码表 |
msg | string | 提示信息,失败时说明原因 |
data | object | 业务数据,随接口而定 |
code 与 HTTP 状态码均语义化、均可靠。每个业务码都对应
一个明确的 HTTP 状态(如 4001→401、
4003/4004→429、4404→404),
两个维度按需读取都行;为便于精确分支,推荐以 success 判成败、以
code 定分支。
04 — Rate Limits
限流与配额
三个互不抵扣的计数桶。窗口一律按 UTC 划分(小时桶为整点固定窗口, 日桶为 UTC 日切):
| 桶 | 计量维度 | 额度 | 可否调整 |
|---|---|---|---|
| 小时限流 | 按店铺 | 默认 600 次 / 小时 | 平台后台可配,0 = 不限 |
| 账号兜底 | 按账号 | 固定 120 次 / 小时 | 不可配 |
| 上架日限额 | 按店铺 | 默认 200 次 / 天 | 平台后台可配 |
小时限流 — 按店铺计
-
同一店铺下
sk_与ak_共享该店铺的同一个桶——换令牌换不来额度。 -
ak_打不同店铺时,各店各有独立的小时桶 (打 3 家店约等于 3 份额度)。 - 被拒绝的调用同样计数、且不回滚(含参数错误、图片错误、404 等业务失败), 所以别用重试硬撞。
- 超限返回
4004(HTTP429),退避 ≥ 60 秒后重试。
账号兜底桶 — 120 次 / 小时
账号维度、全设备共享、不可配置。只有两类请求会命中它:
-
/openapi/store/list的正常调用—— 该端点没有店铺维度,只计这个桶,不碰任何店铺的桶。 - 任何未通过归属校验的请求——缺
X-Store-Id、X-Store-Id非法、或指向不属于本账号的店铺。这类请求落不到任何店铺桶上, 若不计数就等于绕过限流。
不要高频轮询店铺列表。 /openapi/store/list 只吃 120 次/时 的账号桶,而这个桶被同一账号下
所有设备共享——一个设备打满,其余设备一起被拒。
请在本地缓存店铺列表,仅在用户打开店铺选择器、或刚新建店铺时重拉。
上架日限额 — 默认 200 / 店 / 天
-
只有
/openapi/product/create消耗, 且仅成功上架才扣;参数、图片、引用校验失败不计入。 -
按店铺计、UTC 日切。
ak_打不同店铺时各店各有独立日限额。 -
达到上限返回
4003(HTTP429), 其余端点不受影响;等次日(UTC)再上架。
05 — Endpoints
接口总览
开放接口目前提供七个端点:商品的上架、检索、查询与编辑, 外加店铺列表、分类列表与图片上传三个辅助端点。共享同一套约定:
- 均以 Bearer Token 鉴权(见 鉴权与 Token)。
- 请求体不带 storeId:
payload里若带storeId会被忽略。店铺由sk_本身、或ak_的X-Store-Id请求头决定。 - 限流与配额:小时限流按店铺计、上架日限额按店铺计,
/openapi/store/list走账号兜底桶。详见 限流与配额。
| 方法 | 路径 | 用途 | 令牌 | X-Store-Id | 日限额 |
|---|---|---|---|---|---|
GET | /openapi/store/list | 名下店铺清单 | 仅 ak_ | 不带 | 不消耗 |
GET | /openapi/category/list | 本店分类清单 | sk_ / ak_ | ak_ 必带 | 不消耗 |
POST | /openapi/media/upload | 纯图片上传(不建商品) | sk_ / ak_ | ak_ 必带 | 不消耗 |
POST | /openapi/product/create | 上架新商品 | sk_ / ak_ | ak_ 必带 | 消耗 |
GET | /openapi/product/list | 分页检索(裁剪投影) | sk_ / ak_ | ak_ 必带 | 不消耗 |
GET | /openapi/product/get | 单个商品全量详情 | sk_ / ak_ | ak_ 必带 | 不消耗 |
POST | /openapi/product/update | 部分更新已有商品 | sk_ / ak_ | ak_ 必带 | 不消耗 |
推荐接入流程 · 采集类场景
把外站商品搬进店铺,一次 create 建成,不要绕路:
- ①
store/list拿 storeId(本地缓存)。 - ②
category/list拿categoryCode(本地缓存)。 - ③
media/upload把详情长图转存,拿回[{ key, url }]。 - ④ 把第 ③ 步的
url拼进descriptionHTML。 - ⑤
product/create一次建品:商品图集走本次请求的imagespart,详情图已在description里。
不要再用「create → get → update」老路径。
在 media/upload 上线前,想把我们的图片 URL 嵌进详情只能先建品、
再查详情取 URL、再回填——比上面多两次请求,且中间存在「详情图缺失」的脏态。
现在 ③ + ⑤ 两步即可,无中间态。
06 — Store List
店铺列表
/openapi/store/list
返回当前账号名下的全部店铺,用于让工具端填店铺选择器、并拿到后续请求要用的
X-Store-Id。不分页(单账号店铺数天然可控)。
仅账号级 ak_ 可调,且不带 X-Store-Id。
用 sk_ 调用返回 4001,
msg 为「该接口仅支持账号级 Token(ak_)」——sk_ 绑死单店,
「名下所有店」对它没有意义。
返回字段
data 是店铺数组,每项:
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 店铺 ID,即后续请求 X-Store-Id 的值 |
name | string | 店铺名称 |
subdomain | string | 买家端子域名 |
currency | string | 店铺币种 |
status | int | 店铺状态,1(启用)/ 0(停用) |
调用配额
只消耗账号兜底桶(120 次 / 小时、全设备共享),不碰任何店铺的小时额度, 也不消耗上架日限额。请本地缓存,切勿高频轮询——详见 限流与配额。
示例 · curl
curl -G https://api.kjlong.com/openapi/store/list \
-H "Authorization: Bearer ak_xxx" 响应示例
{
"code": 0,
"msg": "success",
"data": [
{ "id": 3, "name": "GoldCoast Mart", "subdomain": "goldcoast", "currency": "GHS", "status": 1 },
{ "id": 7, "name": "Lagos Outlet", "subdomain": "lagos", "currency": "NGN", "status": 1 }
],
"success": true
} 07 — Categories
分类列表
/openapi/category/list
返回当前店铺的分类清单(sk_ 取令牌所属店,ak_ 取
X-Store-Id 指定店),用于在上架前拿到合法的
categoryCode。两种令牌都可调。
按 sort 升序返回,不分页。
返回字段
| 字段 | 类型 | 说明 |
|---|---|---|
code | string | 上架 / 编辑 / 检索时 categoryCode 要填的就是它(不是 id) |
name | string | 分类名称 |
sort | int | 排序值,升序 |
status | int | 分类状态,1(启用)/ 0(停用) |
不按 status 过滤——下架分类同样会出现在列表里。
这与 上架接口 解析 categoryCode
的口径一致(建品时下架分类同样能被引用)。若这里滤掉,就会出现
「列表里没有、但 create 能用」的割裂。需要只展示启用分类,请在你这端按
status 筛。
示例 · curl
# sk_(店铺级)——店铺由 Token 决定,不带 X-Store-Id
curl -G https://api.kjlong.com/openapi/category/list \
-H "Authorization: Bearer sk_xxx"
# ak_(账号级)——必须指明打哪家店
curl -G https://api.kjlong.com/openapi/category/list \
-H "Authorization: Bearer ak_xxx" \
-H "X-Store-Id: 3" 响应示例
{
"code": 0,
"msg": "success",
"data": [
{ "code": "phones", "name": "Phones", "sort": 1, "status": 1 },
{ "code": "audio", "name": "Audio", "sort": 2, "status": 1 },
{ "code": "clearance", "name": "Clearance", "sort": 9, "status": 0 }
],
"success": true
} 08 — Media Upload
图片上传
/openapi/media/upload multipart/form-data,文件字段名固定 images(可重复)。
只把图片存进店铺素材库并返回地址,不创建商品。两种令牌都可调。
它是「详情图先转存、再一次建品」的关键一步。
先用本接口把外站详情长图转存到我们的存储、拿到 url,把这些
url 拼进 description HTML,然后一次 product/create 建成商品——
比旧的「create → get → update」少两次请求,且不存在中间脏态。
请求
| part | 数量 | 说明 |
|---|---|---|
images | 1 ~ 100 | 文件 part,字段名固定为 images |
校验口径与 上架接口 完全一致:单图
≤ 10MB、类型限 jpeg / png /
webp / gif、单请求总大小 ≤ 100MB、
最多 100 张。任一张校验失败 → 整批失败
并指明第几张(4200)。
返回字段
data 是数组,顺序与入参 part 顺序一致:
| 字段 | 类型 | 说明 |
|---|---|---|
key | string | 存储键,可直接填进 create / update 的图片引用位 |
url | string | 公网可读地址,可直接嵌进 description HTML |
调用配额
不消耗上架日限额——日限额的语义是「上架了多少个商品」,传图不是上架,
否则传 60 张详情图就把当天的上架额度烧光了。
但消耗店铺小时限流(见 限流与配额)。
同店同图按内容去重(秒传),重复上传返回同一 key / url,
不产生冗余对象。
示例 · curl
用 ak_ 把两张详情图转存到店铺 3 的素材库:
curl -X POST https://api.kjlong.com/openapi/media/upload \
-H "Authorization: Bearer ak_xxx" \
-H "X-Store-Id: 3" \
-F 'images=@detail_01.jpg' -F 'images=@detail_02.jpg' 响应示例
{
"code": 0,
"msg": "success",
"data": [
{ "key": "store/3/9c1e2f.jpg", "url": "https://res.kjlong.com/store/3/9c1e2f.jpg" },
{ "key": "store/3/4b7a80.jpg", "url": "https://res.kjlong.com/store/3/4b7a80.jpg" }
],
"success": true
} 示例 · 接着一次建品
把上一步返回的 url 嵌进 description,商品图集走本次请求的
images part,一次调用完成:
curl -X POST https://api.kjlong.com/openapi/product/create \
-H "Authorization: Bearer ak_xxx" \
-H "X-Store-Id: 3" \
-F 'payload={"title":"Collected Phone","categoryCode":"phones","price":199.00,"stock":50,"description":"<p><img src=\"https://res.kjlong.com/store/3/9c1e2f.jpg\"></p>"}' \
-F 'images=@main_01.jpg' 09 — Create Product
上架商品
/openapi/product/create
一次 multipart/form-data 请求即完成商品创建。请求体由两种 part 组成:
| part | 数量 | 说明 |
|---|---|---|
payload | 1 | 文本 part,商品信息 JSON,≤ 1MB |
images | 0 ~ 100 | 文件 part,商品/规格图片 |
图片规则
- 顺序即图集顺序:
images的排列顺序就是商品图集顺序,第一张为主图。 - 单图 ≤ 10MB;类型限
jpeg/png/webp/gif。 - 单次请求所有 part 总大小 ≤ 100MB。
- 任一图片校验失败,整单失败并指明第几张,不会产生半成品商品。
payload 通用字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
title | string | 是 | 商品标题,≤ 255 字 |
sub | string | 否 | 副标题 |
description | string | 否 | 商品详情,支持 HTML;内嵌图片 URL 建议先走 图片上传 转存 |
categoryCode | string | 否 | 按店内分类 code 解析(取自 分类列表);填写但不存在则整单报错 |
aiShortTitle | string | 否 | AI 短标题 |
aiPrompt | string | 否 | AI 提示词 |
status | int | 否 | 商品状态,默认 1(上架) |
简单模式 — 单一规格
不传 skus 即为简单模式,系统据下列字段生成单个
Standard SKU:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
price | number | 是 | 售价,必须 > 0 |
origPrice | number | 否 | 原价(划线价) |
stock | int | 否 | 库存 |
高级模式 — 多规格 SKU
skus 非空即进入高级模式,由 skuGroups[]
定义规格维度、skus[] 定义每个规格组合的绝对价与独立库存。
skuGroups[] — 每项定义一个规格维度:
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | 规格组名称,如 Color、Storage |
opts | string[] | 该规格组的可选值,如 ["Black","White"] |
imageEnabled | bool | 是否为该规格组启用规格图 |
optImages | object | 选项值 → 图片文件名的映射,值须为 images 中某个 part 的文件名 |
skus[] — 每项定义一个规格组合:
| 字段 | 类型 | 说明 |
|---|---|---|
spec | string | 规格组合串,各组选项以 / 连接,如 Black / 128GB |
skuCode | string | SKU 编码,缺省取 spec |
price | number | 该 SKU 售价(绝对价) |
origPrice | number | 该 SKU 原价 |
stock | int | 该 SKU 库存 |
image | string | 该 SKU 图片文件名,须为 images 中某个 part 的文件名 |
status | int | SKU 状态,默认 1;status ≠ 1 的 SKU 不参与最低价 / 总库存聚合 |
图片靠文件名映射。skus[].image 与
skuGroups[].optImages 的值,都填 images
里某个文件 part 的文件名,服务端据此关联;
只要引用到不存在的文件名,整单报错。
成功返回
成功时 data 返回新建商品的信息:
| 字段 | 说明 |
|---|---|
id | 商品 ID |
title | 商品标题 |
status | 商品状态 |
url | 买家端商品页地址 |
调用配额
默认 200 单 / 店 / 天(按店铺计、UTC 日切,可联系平台调整)。
只有成功上架才消耗配额;参数校验失败、图片校验失败等不计入。
达到上限返回 code = 4003(HTTP 429)。
本接口同时消耗店铺小时限流,详见 限流与配额。
示例 · 简单模式 curl
单一规格,三张商品图,第一张 img_red.png 为主图:
curl -X POST https://api.kjlong.com/openapi/product/create \
-H "Authorization: Bearer sk_xxx" \
-F 'payload={"title":"Open API Test Phone","sub":"via openapi","categoryCode":"phones","price":199.00,"origPrice":299.00,"stock":50,"description":"<p>Hello <b>world</b></p>"}' \
-F 'images=@img_red.png' -F 'images=@img_green.png' -F 'images=@img_blue.png' 示例 · 高级模式 curl
两个规格维度(Color × Storage)共四个 SKU,规格图与 SKU 图用文件名引用
images 里上传的图片:
curl -X POST https://api.kjlong.com/openapi/product/create \
-H "Authorization: Bearer sk_xxx" \
-F 'payload={"title":"Advanced Phone","categoryCode":"phones","status":1,"skuGroups":[{"name":"Color","opts":["Black","White"],"imageEnabled":true,"optImages":{"Black":"img_black.png","White":"img_white.png"}},{"name":"Storage","opts":["128GB","256GB"],"imageEnabled":false}],"skus":[{"spec":"Black / 128GB","skuCode":"BLK-128","price":300,"origPrice":350,"stock":10,"image":"img_black.png"},{"spec":"Black / 256GB","skuCode":"BLK-256","price":350,"stock":8,"image":"img_black.png"},{"spec":"White / 128GB","skuCode":"WHT-128","price":320,"stock":5,"image":"img_white.png"},{"spec":"White / 256GB","skuCode":"WHT-256","price":370,"stock":0,"status":0,"image":"img_white.png"}]}' \
-F 'images=@img_black.png' -F 'images=@img_white.png' 示例 · Python requests
与上面的简单模式等价,注意最后按 success / code 分支:
import requests
url = "https://api.kjlong.com/openapi/product/create"
headers = {"Authorization": "Bearer sk_xxx"}
# payload:一个 JSON 文本 part,内容与简单模式 curl 完全一致
payload = (
'{"title":"Open API Test Phone","sub":"via openapi",'
'"categoryCode":"phones","price":199.00,"origPrice":299.00,'
'"stock":50,"description":"<p>Hello <b>world</b></p>"}'
)
# images:文件 part,顺序即商品图集顺序,第一张为主图
files = [
("images", ("img_red.png", open("img_red.png", "rb"), "image/png")),
("images", ("img_green.png", open("img_green.png", "rb"), "image/png")),
("images", ("img_blue.png", open("img_blue.png", "rb"), "image/png")),
]
resp = requests.post(url, headers=headers, data={"payload": payload}, files=files)
result = resp.json()
# 按 success 判断成败,按 code 精确分支(HTTP 状态码同样语义化、可一并参考)
if result["success"]:
print("上架成功:", result["data"]["url"])
else:
print("上架失败:", result["code"], result["msg"]) 成功返回示例
{"code":0,"msg":"success","data":{"id":389,"title":"Open API Test Phone","status":1,"url":"https://yourstore.kjlong.com/product/389"},"success":true} 10 — List Products
商品列表
/openapi/product/list
分页检索本店商品,用于对账、增量同步,或在编辑前先定位商品 ID。返回的是
裁剪投影——不含 description 等重字段;需要全量请用
商品详情。
Query 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
page | int | 否 | 页码,从 1 起,默认 1 |
size | int | 否 | 每页条数,默认 20,上限 100(超限自动收敛到 100) |
status | int | 否 | 按状态过滤,0(下架)或 1(上架) |
categoryCode | string | 否 | 按分类 code 过滤 |
keyword | string | 否 | 按标题模糊匹配 |
返回结构
| 字段 | 类型 | 说明 |
|---|---|---|
list | array | 当前页商品投影,元素字段见下表 |
page | int | 当前页码 |
size | int | 每页条数(收敛后的实际值) |
total | int | 符合条件的总条数 |
totalPages | int | 总页数 |
list[] — 单个商品投影(不含 description):
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | 商品 ID |
title | string | 标题 |
sub | string | 副标题 |
price | number | 售价(多规格为最低价聚合) |
origPrice | number | 原价(划线价) |
stock | int | 库存(多规格为总和聚合) |
status | int | 状态,0 / 1 |
apiLocked | int | API 编辑锁,1=锁定(编辑接口会拒绝)/ 0=开放 |
categoryCode | string | 分类 code |
mainImage | string | 主图 URL(可直接展示) |
createTime | string | 创建时间,yyyy-MM-dd HH:mm:ss |
modifyTime | string | 修改时间,yyyy-MM-dd HH:mm:ss |
示例 · curl
取第 1 页、每页 20 条、仅上架、标题含 phone 的商品:
curl -G https://api.kjlong.com/openapi/product/list \
-H "Authorization: Bearer sk_xxx" \
-d page=1 -d size=20 -d status=1 -d keyword=phone 响应示例
{
"code": 0,
"msg": "success",
"data": {
"list": [
{
"id": 412,
"title": "Advanced Phone",
"sub": "",
"price": 300.00,
"origPrice": 350.00,
"stock": 23,
"status": 1,
"apiLocked": 0,
"categoryCode": "phones",
"mainImage": "https://res.kjlong.com/upload/2026/06/8f3a1c.png",
"createTime": "2026-06-20 10:31:55",
"modifyTime": "2026-06-21 08:04:12"
},
{
"id": 389,
"title": "Open API Test Phone",
"sub": "via openapi",
"price": 199.00,
"origPrice": 299.00,
"stock": 50,
"status": 1,
"apiLocked": 0,
"categoryCode": "phones",
"mainImage": "https://res.kjlong.com/upload/2026/06/5e1f0a.png",
"createTime": "2026-06-20 09:12:03",
"modifyTime": "2026-06-20 09:12:03"
}
],
"page": 1,
"size": 20,
"total": 2,
"totalPages": 1
},
"success": true
} 11 — Get Product
商品详情
/openapi/product/get?id=
返回单个商品的全量详情,含图片、规格与 SKU 的完整结构。
商品不存在、或不属于本店 → 4404(两种情况不区分)。
Query 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | int | 是 | 商品 ID |
返回字段
顶层为商品常规字段,外加图片与规格结构:
| 字段 | 类型 | 说明 |
|---|---|---|
id / title / sub / description | — | 商品常规字段(详情含 HTML) |
categoryCode | string | 分类 code |
price / origPrice / stock / status | — | 聚合价、原价、总库存与状态 |
apiLocked | int | API 编辑锁,1=锁定 / 0=开放;编辑前先看这个值 |
aiShortTitle / aiPrompt | string | AI 短标题与提示词 |
url | string | 买家端商品页地址 |
mainImage | object|null | { key, url },无主图为 null |
images | array | 图集,元素为 { key, url } |
skuGroups | array | 规格维度定义;其中 optImages 的值为图片 URL |
skus | array | SKU 列表,元素字段见下表 |
skus[] — 单个 SKU:
| 字段 | 类型 | 说明 |
|---|---|---|
id | int | SKU ID |
spec | string | 规格组合串,如 Black / 128GB |
skuCode | string | SKU 编码 |
price / origPrice | number | 该 SKU 售价 / 原价 |
stock | int | 该 SKU 库存 |
status | int | 该 SKU 状态 |
image | object|null | { key, url },无图为 null |
key 供引用,url 供展示。图片对象里的 key 是稳定的存储键,
拿去编辑接口的 images /
optImages / image 里即可复用已有图、无需重新上传;
url 则是可直接放进页面的展示地址。
示例 · curl
curl -G https://api.kjlong.com/openapi/product/get \
-H "Authorization: Bearer sk_xxx" \
-d id=412 响应示例
{
"code": 0,
"msg": "success",
"data": {
"id": 412,
"title": "Advanced Phone",
"sub": "",
"description": "<p>Hello <b>world</b></p>",
"categoryCode": "phones",
"price": 300.00,
"origPrice": 350.00,
"stock": 23,
"status": 1,
"apiLocked": 0,
"aiShortTitle": "",
"aiPrompt": "",
"url": "https://yourstore.kjlong.com/product/412",
"mainImage": {
"key": "upload/2026/06/8f3a1c.png",
"url": "https://res.kjlong.com/upload/2026/06/8f3a1c.png"
},
"images": [
{ "key": "upload/2026/06/8f3a1c.png", "url": "https://res.kjlong.com/upload/2026/06/8f3a1c.png" },
{ "key": "upload/2026/06/7d2e9b.png", "url": "https://res.kjlong.com/upload/2026/06/7d2e9b.png" }
],
"skuGroups": [
{
"name": "Color",
"opts": ["Black", "White"],
"imageEnabled": true,
"optImages": {
"Black": "https://res.kjlong.com/upload/2026/06/8f3a1c.png",
"White": "https://res.kjlong.com/upload/2026/06/7d2e9b.png"
}
}
],
"skus": [
{
"id": 4101,
"spec": "Black / 128GB",
"skuCode": "BLK-128",
"price": 300.00,
"origPrice": 350.00,
"stock": 10,
"status": 1,
"image": {
"key": "upload/2026/06/8f3a1c.png",
"url": "https://res.kjlong.com/upload/2026/06/8f3a1c.png"
}
}
]
},
"success": true
} 12 — Update Product
编辑商品
/openapi/product/update
请求形态与上架接口一致
(multipart/form-data,payload + 可选
images),但 payload.id 必填,且语义为
部分更新。商品不存在 / 不属本店 → 4404。本接口
不消耗上架日限额。
payload 字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | int | 是 | 目标商品 ID |
| 其余字段 | — | 否 | 同上架接口;只有传入的字段被更新,未出现的保持原样 |
更新语义
- 部分更新:只改
payload里出现的字段,其余原样保留。 - 整体替换:
images/skus/skuGroups一旦传入,即用新值整体替换旧值;不传则保持原样。images传空数组即清空图集。 - 图片引用可混用:图片位(
images/optImages/ SKU 的image)既可填现有图的 key (来自商品详情),也可填本次上传文件的文件名。 - 移除 ≠ 删除:从
images[]移除仅解除图集引用, 文件仍在店铺素材库、URL 长期有效——「图片先上传取 URL 嵌入description,再从图集移除」是受支持的用法。 - 商品锁定:商户可在后台锁定商品(
apiLocked=1,人工创建的 默认锁定;API 创建的默认开放)。锁定商品调用本接口 →4405/423。 列表与详情均返回apiLocked,编辑前先检查;payload 中的apiLocked会被忽略——锁的开关只属于商户后台。 - 顶层 price / stock 不生效:编辑接口不吃顶层价格 / 库存,
调价 / 改库存请走
skus的绝对价与独立库存。
示例 · 只改标题
不带 images part,图集与规格原样不动,仅更新标题:
curl -X POST https://api.kjlong.com/openapi/product/update \
-H "Authorization: Bearer sk_xxx" \
-F 'payload={"id":412,"title":"Advanced Phone (2026)"}' 示例 · 混合引用重排图集
保留一张现有图(用详情返回的 key)、
再追加一张新上传文件,以新的顺序整体替换图集:
curl -X POST https://api.kjlong.com/openapi/product/update \
-H "Authorization: Bearer sk_xxx" \
-F 'payload={"id":412,"images":["upload/2026/06/8f3a1c.png","img_new.png"]}' \
-F 'images=@img_new.png' 13 — Errors
错误码
失败时 success = false,按 code 分支处理。
HTTP 状态码同样语义化,与 code 一致、可一并参考。
下表 msg 为服务端原文,N(数量)、X(具体名称)、
f(文件名)为运行时替入的值。
| code | HTTP | 说明与 msg 原文示例 |
|---|---|---|
0 | 200 | 成功 —— success |
4001 | 401 |
Token 无效或缺失;或用 sk_ 调了仅 ak_ 可用的端点 ——
无效的 API Token该接口仅支持账号级 Token(ak_) |
4002 | 403 | Token 已停用(含 ak_ 被商户吊销) —— API Token 已停用 |
4003 | 429 |
达到今日上架限额(仅上架接口消耗额度,失败不扣) ——
已达今日上架限额(N),可联系平台调整 |
4004 | 429 |
调用过于频繁(店铺小时桶,或账号兜底桶 120 次/时) ——
调用过于频繁(600 次/时),请稍后重试调用过于频繁(120 次/时),请稍后重试 |
4100 | 400 |
参数错误(含 X-Store-Id 缺失或非数字) ——
账号级 Token 必须携带 X-Store-Id 请求头X-Store-Id 不是合法的店铺 ID缺少 payload 参数payload 过大(上限 1MB)payload 不是合法 JSONtitle 必填title 不能超过 255 字status 只能是 0 或 1分类 code 不存在: X简单模式需要 price 且大于 0第 N 个 SKU 缺少 specupdate 需要 payload.id 等
|
4200 | 400 |
图片错误 ——
缺少 images 文件图片最多 100 张第 N 张图片为空第 N 张图片(f)超过 10MB第 N 张图片(f)仅支持图片格式: [gif, jpg, jpeg, webp, png] |
4300 | 400 |
引用错误 ——
第 N 个 SKU 引用的图片文件名不在 images 中: X规格图 引用的图片文件名不在 images 中: Ximages[N] 引用的图片既不是本次上传文件也不是现有图: X |
4404 | 404 |
商品不存在(含不属于本店,不区分) —— 商品不存在X-Store-Id 指向的店铺不存在,或存在但不属于该账号
(两种情况不区分,防探测) —— 店铺不存在 |
4405 | 423 | 商品已被商户锁定,编辑接口拒绝 —— 商品已锁定,禁止通过 API 编辑 |
5000 | 500 | 服务端错误 —— 服务端错误 |
畸形请求不走这套错误码
如果请求在被路由到端点之前就被判非法——例如给 multipart 端点发了
非 multipart 的 body、Content-Type 不匹配、或用错 HTTP 动词——
异常在 handler 映射阶段就抛出,根本没进入开放接口的错误处理。
此时返回的是平台全局信封,HTTP 状态 500:
{"code":2,"msg":"error_system"} 分支判断前,先确认拿到的 code 是 4xxx(或 0)。
收到 code = 2 / msg = "error_system" 时,
请当作「本地请求构造错误」处理——检查 HTTP 方法、
Content-Type、multipart 编码与字段名——
不要当成服务端故障去重试,原样重试必然再失败。