# KK 开放 API · 字段速查

> 版本：2026-06-13 v6（P2 正式路径）· Base URL：`https://kk.h-sh.com/api`  
> 完整规范：[KK-openAi.md](./KK-openAi.md) · HTML：[/api/open/docs](https://kk.h-sh.com/api/open/docs)

面向 ERP / 脚本接入的**字段与层级约定**，与 AI 规范同源，无歧义表述。

---

## 认证

```
Header: X-API-Key: kk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
JSON:   Content-Type: application/json
```

**数据范围**：商品读写仅 **本 Key 所属商户**；全平台公开列表用 `GET /api/public/products`（无需 Key）。

---

## 端点

| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/open/upload-image` | 上传图片 |
| POST | `/open/upload-video` | 上传主图视频（mp4/mov/webm/m4v） |
| POST | `/open/products` | 创建 |
| GET | `/open/products` | 本商户列表 `?page=&page_size=&category=&is_active=` |
| GET | `/open/products/{id}` | 详情 |
| GET | `/open/categories` | 平台类目树（大类+子类） |
| GET | `/open/merchant-categories` | 我的自定义分类（查 slug） |
| POST | `/open/merchant-categories` | 创建自定义分类 |
| PATCH | `/open/merchant-categories/{id}` | 更新自定义分类 |
| DELETE | `/open/merchant-categories/{id}` | 删除自定义分类（软删） |
| PATCH | `/open/products/{id}` | 更新商品 |
| PATCH | `/open/products/{id}/skus` | 更新 SKU |

---

## 对外标识

| 字段 | 来源 | 示例 | 说明 |
|------|------|------|------|
| `id` | 平台 | `12345` | **API 唯一键**，路径与 upload 的 `product_id` |
| `art_no` | 商户/API | `X2026-001` | 厂家款号，≤19 字，选填 |

平台内部另有前台短编码（如 W0、K10），**开放 API 不返回**，对接以 `id` 为准。

---

## POST `/open/products` 请求结构

```json
{
  "product": { "name", "category", "price", "art_no?", "description?", "tags?", ... },
  "main_images": ["https://cf.h-sh.com/kk_HSH/..."],
  "main_video_url?": "https://cf.h-sh.com/kk_HSH/.../xxx.mp4",
  "source": "https://来源页可选",
  "skus": [{ "color", "size", "stock?", "price?", "white_image_url?" }]
}
```

| 字段 | 层级 | 必填 | 说明 |
|------|------|------|------|
| name | product | ✅ | 1～200 字 |
| category | product | ✅ | 平台 slug；先 `GET /open/categories`，有 subs 传子类 |
| price | product | ✅ | > 0 |
| art_no | product | — | 货号，≤19 字 |
| description | product | — | 商品描述，≤200 字 |
| merchant_category_slug | product | — | 商户自定义分类 slug，须先创建 |
| material, brand, origin_place, packaging, unit, min_order_qty, tags | product | — | 见完整规范 |
| detail_images | **根**或 product | — | 详情图 URL；前台零边距无圆角拼接 |
| detail_content | **根**或 product | — | 块级 HTML ≤5000 字；纯文本自动包 `<p>`；GET 返回 |
| main_images | **根** | ✅ | ≥1 张，须 KK CDN URL |
| main_video_url | **根** | — | 主图视频 URL；先 `POST /open/upload-video`，**勿**放入 main_images |
| source | **根** | — | 来源页 URL；**禁止**与货号拼 `"url \| 货号"` |
| skus | **根** | — | SKU 数组；**可含** `white_image_url`（公开 API 选填） |

**400 常见原因：** `main_images` / `main_video_url` / `skus` / `source` 误放入 `product` 内。

---

## PATCH `/open/products/{id}` 请求结构

扁平 JSON，**无 `product` 包装**：

```json
{ "name?", "price?", "art_no?", "main_video_url?", "source?", "detail_content?", "detail_images?", "merchant_category_slug?", "clear_merchant_category?", "is_active?", "main_images?", "tags?", ... }
```

`detail_content` / `detail_images` 创建时可放**根或 product**（根优先）；PATCH 仅根层级扁平 JSON。

---

## 分类体系（两套，勿混）

| | 平台类目 `category` | 自定义分类 `merchant_category_slug` |
|--|---------------------|-------------------------------------|
| 位置 | `product.category` | `product.*`（创建）/ 根层级（PATCH） |
| 必填 | ✅ | 选填 |
| 值 | 平台 slug（大类或子类，见 `/open/categories`） | 商户 slug，如 `yun-dong-xie`；`POST /open/merchant-categories` 或后台创建 |
| 用途 | 编码前缀（按所属大类 W/K/H/B）、全站筛选 | 商户主页 Tab（`?cat=slug`） |
| 查/建 | `GET /open/categories` | `GET /open/merchant-categories`；批跑前 `POST` 创建 |

❌ 勿把自定义分类名填入 `category`。❌ 大类有 `subs` 时勿传大类 slug（如女鞋须传 `sandals` 等子类）。❌ 勿把 `women_shoes` 当作 `merchant_category_slug`。

---

## PATCH `/open/products/{id}/skus` 请求结构

```json
[{ "color": "黑色", "size": "38", "stock": 50, "white_image_url?": "..." }]
```

或 `{"items":[...]}` / `{"skus":[...]}`。定位键：`(color, size)` 字符串完全相等。

响应 `updated_skus[]` 含 `action`、`white_image_url` 等字段。

---

## 库存约定

| 写法 | 是否允许 |
|------|----------|
| `skus[].stock` | ✅ 唯一写入方式 |
| 商品级 `stock`（GET 响应） | 只读，= SKU 之和 |

---

## 响应字段（创建 / 详情）

| 字段 | 说明 |
|------|------|
| `product.id` / `id` | 商品 ID，后续 API 唯一键 |
| `art_no` | 货号 |
| `main_video_url` | 主图视频 CDN URL（无则为 null）；P2：`{merchant_id}/products/{product_id}/main_video.{ext}` |
| `source` | 来源页 URL |
| `merchant_category_slug` | 商户自定义分类 slug（未分类为 null） |
| `detail_content` | 块级 HTML 图文详情（无则为 `""`） |
| `detail_images` | 详情图 URL 数组 |
| `status` | 创建时：`active` 或 `pending_review` |
| `skus[]` | 含 `id`, `color`, `size`, `stock`, `price`, **`white_image_url`**（POST 创建与 GET 详情结构一致） |

**不返回：** 平台内部前台短编码。

**接入自检：** 创建后直接看 POST 响应的 `skus[].white_image_url` 与 `product.main_video_url`，无需反复向商户确认是否存上。

---

## 媒体 URL

### 图片

仅接受：

- `https://cf.h-sh.com/kk_HSH/...`
- `https://kk.h-sh.com/kk_HSH/...`

创建前 upload 无 `product_id` → `temp/`；创建商品后平台自动迁入 P2 正式路径 `{merchant_id}/products/{product_id}/{uuid}.jpg`（**2026-06-12 起新商品**）。存量商品仍为 `{date}/{code}_{序号}.jpg`。

**Bulk 补图：禁止 `product_id`，必须 temp → POST/PATCH。** 单张追加时 `product_id` 直接写入 P2 路径（UUID 文件名，按店铺+商品隔离）。

**归属校验（2026-06-12）：** POST 创建仅接受本商户 `temp/` URL；PATCH 另可接受本商品 P2 正式路径或存量 `{code}_*`；跨商品引用正式 URL → **400**。Bulk 须每货号独立 URL 缓冲，upload 完立刻写库。

### 主图视频

1. `POST /open/upload-video` 上传（可不传 `product_id`）
2. 将返回的 `url` 写入根层级 `main_video_url`
3. 支持 `.mp4` / `.mov` / `.webm` / `.m4v`
4. 创建商品时 temp 视频迁入 `{merchant_id}/products/{product_id}/main_video.{原扩展名}`（**保留视频后缀**）
5. **禁止**把视频 URL 放进 `main_images`

---

## 错误码

| HTTP | 含义 |
|------|------|
| 401 | Key 无效 |
| 403 | 未实名 / 非本商户商品 |
| 404 | 商品不存在 |
| 400 | 层级错误、**图片/视频 URL 归属不符**、业务参数 |
| 422 | 字段校验（货号/描述过长、内部 API 白底图缺失、标签过长等） |

---

完整流程与 AI 接入见 **[KK-openAi.md](./KK-openAi.md)**。
