> ## Documentation Index
> Fetch the complete documentation index at: https://beaver.voc.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 商品数据同步接入接口文档

## 1. 概述

Solvea 会主动调用接入方提供的商品查询接口，拉取商品及 SKU 数据。

接入方需要提供一个支持分页和条件查询的 HTTP 接口，并在商品同步配置中填写接口 Base URL 和 Token。

## 2. 接口信息

商品接口地址为渠道 Base URL 拼接 `/products`。

例如：

```text theme={null}
POST https://{baseUrl}/products
```

| 项目           | 要求                                 |
| ------------ | ---------------------------------- |
| 请求方向         | Solvea → 接入方系统                     |
| 请求方法         | `POST`                             |
| Content-Type | `application/json`                 |
| 字符集          | UTF-8                              |
| 鉴权方式         | Bearer Token                       |
| 分页范围         | `pageSize` 为 1-200 的整数             |
| 时间格式         | ISO-8601，例如 `2024-05-01T00:00:00Z` |

每次请求携带以下 Header：

```http theme={null}
Authorization: Bearer {Token}
Content-Type: application/json
```

Token 由 Solvea 在自研数据系统渠道中生成并展示。商品同步和订单同步使用同一个渠道 Token。

## 3. 请求体

| 字段                    | 类型      | 必填 | 说明                                                                                  |
| --------------------- | ------- | -- | ----------------------------------------------------------------------------------- |
| `page`                | Integer | 是  | 页码，从 1 开始。                                                                          |
| `pageSize`            | Integer | 是  | 每页最大返回条数，范围为 1-200。                                                                 |
| `lastUpdateTimeStart` | String  | 否  | 增量同步起始时间，筛选 `externalUpdatedAt >= lastUpdateTimeStart`。需与 `lastUpdateTimeEnd` 配对使用。 |
| `lastUpdateTimeEnd`   | String  | 否  | 增量同步结束时间，筛选 `externalUpdatedAt <= lastUpdateTimeEnd`。需与 `lastUpdateTimeStart` 配对使用。 |
| `createTimeStart`     | String  | 否  | 历史/全量同步起始时间，筛选 `publishedAt >= createTimeStart`。需与 `createTimeEnd` 配对使用。            |
| `createTimeEnd`       | String  | 否  | 历史/全量同步结束时间，筛选 `publishedAt <= createTimeEnd`。需与 `createTimeStart` 配对使用。            |
| `productId`           | String  | 否  | 单商品查询。传入后忽略其他过滤条件，仅返回指定商品。                                                          |

## 4. 查询场景

### 4.1 增量同步

使用 `lastUpdateTimeStart`、`lastUpdateTimeEnd`、`page` 和 `pageSize`。

```json theme={null}
{
  "page": 1,
  "pageSize": 200,
  "lastUpdateTimeStart": "2024-05-01T00:00:00Z",
  "lastUpdateTimeEnd": "2024-05-01T01:00:00Z"
}
```

返回 `externalUpdatedAt` 在时间范围内的商品。

### 4.2 历史回填

使用 `createTimeStart`、`createTimeEnd`、`page` 和 `pageSize`。

```json theme={null}
{
  "page": 1,
  "pageSize": 200,
  "createTimeStart": "2024-01-01T00:00:00Z",
  "createTimeEnd": "2024-01-31T23:59:59Z"
}
```

返回 `publishedAt` 在时间范围内的商品。

### 4.3 单商品查询

传入 `productId`。`productId` 存在时忽略其他过滤条件。

```json theme={null}
{
  "page": 1,
  "pageSize": 1,
  "productId": "P10001"
}
```

### 4.4 无时间过滤

仅传入分页参数，接口分页返回全部商品。

```json theme={null}
{
  "page": 1,
  "pageSize": 200
}
```

## 5. 响应结构

接口成功时返回 HTTP 200 及 JSON 响应：

| 字段            | 类型      | 必填 | 说明                       |
| ------------- | ------- | -- | ------------------------ |
| `data`        | Array   | 是  | 商品对象列表。无数据时必须返回空数组 `[]`。 |
| `page`        | Integer | 是  | 当前页码。                    |
| `pageSize`    | Integer | 是  | 当前分页大小。                  |
| `hasNextPage` | Boolean | 是  | 是否还有下一页。为 `false` 时停止翻页。 |

示例：

```json theme={null}
{
  "data": [],
  "page": 1,
  "pageSize": 200,
  "hasNextPage": false
}
```

## 6. 商品对象

`data` 数组中的每一项为商品对象。

| 字段                  | 类型              | 必填 | 说明                     |
| ------------------- | --------------- | -- | ---------------------- |
| `externalId`        | String          | 是  | 接入方系统中的唯一商品 ID，必须稳定。   |
| `title`             | String          | 是  | 商品标题。                  |
| `description`       | String          | 否  | 商品描述。                  |
| `brand`             | String          | 否  | 商品品牌。                  |
| `categoryId`        | String          | 否  | 商品分类 ID。               |
| `category`          | String          | 否  | 商品分类名称。                |
| `country`           | String          | 否  | 商品所属国家或地区。             |
| `currency`          | String          | 否  | 商品价格使用的 ISO 4217 货币代码。 |
| `spuUrl`            | String          | 否  | 商品详情页地址。               |
| `mainImageUrl`      | String          | 否  | 商品主图地址。                |
| `images`            | Array of String | 否  | 商品图片地址列表。              |
| `videos`            | Array of String | 否  | 商品视频地址列表。              |
| `tags`              | Array of String | 否  | 商品标签列表。                |
| `metaFields`        | Object          | 否  | 商品扩展属性。                |
| `status`            | String          | 否  | 商品状态。                  |
| `publishedAt`       | String          | 否  | 商品发布时间，ISO-8601。       |
| `externalUpdatedAt` | String          | 否  | 商品最后更新时间，ISO-8601。     |
| `isDeleted`         | Boolean         | 否  | 商品是否已删除。               |
| `shopId`            | String          | 否  | 商品所属店铺的外部 ID。          |
| `skus`              | Array of Object | 否  | SKU 列表。无规格商品可返回空数组。    |

## 7. SKU 对象

商品对象中的 `skus` 数组中的每一项为 SKU 对象。

| 字段               | 类型      | 必填 | 说明                     |
| ---------------- | ------- | -- | ---------------------- |
| `externalId`     | String  | 是  | 接入方系统中的唯一 SKU ID，必须稳定。 |
| `sku`            | String  | 否  | 卖家 SKU 编码。             |
| `name`           | String  | 否  | SKU 展示名称。              |
| `description`    | String  | 否  | SKU 描述。                |
| `image`          | String  | 否  | SKU 图片地址。              |
| `price`          | Number  | 否  | SKU 售价。                |
| `compareAtPrice` | Number  | 否  | SKU 划线价。               |
| `stockQuantity`  | Integer | 否  | SKU 可售库存数量。            |
| `available`      | Boolean | 否  | SKU 是否可用。              |
| `onSale`         | Boolean | 否  | SKU 是否在售。              |
| `status`         | String  | 否  | SKU 状态。                |
| `metaFields`     | Object  | 否  | SKU 扩展属性。              |
| `isDeleted`      | Boolean | 否  | SKU 是否已删除。             |

## 8. 完整响应示例

```json theme={null}
{
  "data": [
    {
      "externalId": "P10001",
      "title": "Wireless Noise-Cancelling Headphones",
      "description": "Bluetooth headphones with active noise cancellation",
      "brand": "Example Brand",
      "categoryId": "audio",
      "category": "Headphones",
      "country": "US",
      "currency": "USD",
      "spuUrl": "https://example.com/products/P10001",
      "mainImageUrl": "https://example.com/images/P10001.jpg",
      "images": [
        "https://example.com/images/P10001-1.jpg"
      ],
      "videos": [],
      "tags": ["new", "featured"],
      "metaFields": {
        "material": "plastic"
      },
      "status": "active",
      "publishedAt": "2024-01-01T00:00:00Z",
      "externalUpdatedAt": "2024-05-01T00:30:00Z",
      "isDeleted": false,
      "shopId": "SHOP-001",
      "skus": [
        {
          "externalId": "SKU10001",
          "sku": "SKU-BLACK",
          "name": "Black",
          "description": "Black variant",
          "image": "https://example.com/images/SKU10001.jpg",
          "price": 29.99,
          "compareAtPrice": 39.99,
          "stockQuantity": 100,
          "available": true,
          "onSale": true,
          "status": "active",
          "metaFields": {},
          "isDeleted": false
        }
      ]
    }
  ],
  "page": 1,
  "pageSize": 200,
  "hasNextPage": false
}
```

## 9. 接入与测试

1. 实现 `POST {baseUrl}/products` 接口。
2. 将接口部署到 Solvea 服务可以访问的地址。
3. 在自研数据系统渠道中配置 Base URL 和 Token。
4. 点击「测试连接」，验证接口可访问且 Token 有效。
5. 点击「测试商品协议&响应结构」，验证响应结构。
6. 测试通过后确认商品同步配置。

协议结构测试会使用 `page=1`、`pageSize=1`，并携带最近一小时的增量时间范围，校验接口连通性、分页包装、首条商品和首个 SKU。

## 10. 实现要求

* `page` 从 1 开始。
* `pageSize` 必须支持 1-200，返回数量不能超过请求的 `pageSize`。
* `lastUpdateTimeStart` 必须与 `lastUpdateTimeEnd` 配对使用。
* `createTimeStart` 必须与 `createTimeEnd` 配对使用。
* `productId` 存在时忽略其他过滤条件。
* `data` 无数据时必须返回 `[]`，不能返回 `null`。
* `externalId` 必须稳定且唯一；修改外部 ID 会被视为新商品或新 SKU。
* 布尔字段返回 JSON 布尔值 `true` 或 `false`，不要返回字符串。
* 金额字段返回 Number，不要返回带货币符号的字符串。
* 商品和 SKU 的图片、视频 URL 应确保 Solvea 服务可以访问。

## 11. 常见 HTTP 状态码

| 状态码      | 说明                      |
| -------- | ----------------------- |
| `200`    | 请求成功，返回合法 JSON 和完整响应结构。 |
| `401`    | Token 缺失或无效。            |
| `403`    | 无接口访问权限。                |
| `429`    | 请求触发限流。                 |
| `5xx`    | 接入方服务异常。                |
| 其他 `4xx` | 请求参数或接口实现不符合要求。         |
