# #3090 Tezber 合作方 API v2

来源：https://gitlab.parsec.com.cn/umay/doc-and-issues/-/issues/3090

读取时间：2026-10-01T14:06:53.854019+00:00；当前更新时间：2026-09-30T07:05:34.390Z。

> 当前内容快照，非历史版本。身份提及、电话示例和订单编号经最小化处理；不据此认定需求已实现。

## 当前描述

# Tezber 合作方 API v2

面向合作方的集成文档。

**Base URL：** `https://mobile.tezber.kz`  
**格式：** JSON，UTF-8

> 译注：本文译自俄文原版 [PARTNER_API_V2.md](https://gitlab.parsec.com.cn/umay/doc-and-issues/uploads/7c06a9e87600bc185ee917bbb6760eb4/PARTNER_API_V2.md)。文中「ПВЗ」译为「自提点」，「мешок」译为「集包袋」。示例 JSON / cURL 中的数据保持原样（含俄文示例值），以便与接口实际报文对照。

---

## 目录

1. [认证](#认证)
2. [通用规则](#通用规则)
3. [自提点](#自提点)
4. [用户](#用户)
5. [包裹](#包裹)
6. [客户运单认领申请](#客户运单认领申请)
7. [出站 Webhook](#出站-webhook)
8. [接收中国仓集包袋](#接收中国仓集包袋)
9. [集包袋状态](#集包袋状态)
10. [包裹状态](#包裹状态)
11. [响应码](#响应码)
12. [集成流程](#集成流程)
13. [接口汇总](#接口汇总)

---

## 认证

每个请求都必须携带请求头：

```http
X-Api-Token: <你的_token>
```

Token 由 Tezber 团队发放，无需用户名和密码。

Token 错误或缺失时返回：

```http
HTTP/1.1 401 Unauthorized
```

---

## 通用规则

- 你只能操作**自己的**自提点和用户。
- 请求中**无需**传递合作方代码——系统根据 Token 自动识别。
- 所有用户相关操作均以**手机号**为标识（`87001234567`、`[电话示例已隐藏]` 等格式均可）。
- 绑定包裹请使用 API 响应中返回的 `systemId`。
- `proxyId` 为你方内部的客户唯一编码。
- 用户所属的自提点必须**事先**通过 API 创建，且处于**启用**状态。

---

## 自提点

基础路径：`/api/v2/pickup-point`

### 自提点对象字段

| 字段 | 类型 | 说明 |
|------|-----|----------|
| `id` | number | 内部 ID |
| `code` | string | 自提点编码（在你方集成范围内唯一） |
| `name` | string | 名称 |
| `address` | string | 地址 |
| `city` | string | 城市 |
| `phone` | string | 电话 |
| `workingTime` | string | 营业时间 |
| `active` | boolean | 是否启用 |
| `createdAt` | datetime | 创建时间（ISO-8601） |
| `updatedAt` | datetime | 更新时间（ISO-8601） |

---

### 创建自提点

```http
POST https://mobile.tezber.kz/api/v2/pickup-point
X-Api-Token: <token>
Content-Type: application/json
```

**请求：**

```json
{
  "code": "NEO-001",
  "name": "NEO ПВЗ Абая",
  "address": "ул. Абая 1",
  "city": "Алматы",
  "phone": "[电话示例已隐藏]",
  "workingTime": "09:00-21:00"
}
```

| 字段 | 必填 |
|------|:------------:|
| `code` | 是 |
| `name` | 是 |
| `address` | 否 |
| `city` | 否 |
| `phone` | 否 |
| `workingTime` | 否 |

**响应：** `201 Created`

```json
{
  "id": 1,
  "code": "NEO-001",
  "name": "NEO ПВЗ Абая",
  "address": "ул. Абая 1",
  "city": "Алматы",
  "phone": "[电话示例已隐藏]",
  "workingTime": "09:00-21:00",
  "active": true,
  "createdAt": "2026-07-01T10:00:00+05:00",
  "updatedAt": "2026-07-01T10:00:00+05:00"
}
```

---

### 自提点列表

```http
GET https://mobile.tezber.kz/api/v2/pickup-point
GET https://mobile.tezber.kz/api/v2/pickup-point?active=true
GET https://mobile.tezber.kz/api/v2/pickup-point?active=false
X-Api-Token: <token>
```

| 参数 | 说明 |
|----------|----------------------------------------------------------------------------|
| `active` | `true` - 仅启用的；`false` - 仅停用的；不传则返回全部 |

**响应：** `200 OK` - 自提点对象数组

---

### 更新自提点

```http
PUT https://mobile.tezber.kz/api/v2/pickup-point/{code}
X-Api-Token: <token>
Content-Type: application/json
```

**请求**（仅传需要修改的字段）：

```json
{
  "name": "NEO ПВЗ Абая (обновлено)",
  "address": "ул. Абая 2",
  "city": "Алматы",
  "phone": "[电话示例已隐藏]",
  "workingTime": "10:00-22:00"
}
```

**响应：** `200 OK`

---

### 停用自提点

```http
PATCH https://mobile.tezber.kz/api/v2/pickup-point/{code}/deactivate
X-Api-Token: <token>
```

停用后该自提点不再可供新用户选择。

**响应：** `200 OK` - 返回 `"active": false` 的对象

---

## 用户

基础路径：`/api/v2/users`

所有请求均使用**客户手机号**——格式需与创建时一致。

### 用户对象字段

| 字段 | 类型 | 说明 |
|------|-----|---------------------------------------------------------------------------|
| `phone` | string | 客户手机号 |
| `name` | string | 名 |
| `surname` | string | 姓 |
| `iin` | string | ИИН（哈萨克斯坦个人身份号） |
| `proxyId` | string | 你方客户编码 |
| `systemId` | number \| null | 用于绑定包裹的 ID。`null` 表示仍在处理中，请稍后重新查询 |
| `pickupPoint` | string | 自提点编码 |
| `stationCreated` | boolean | `true` - 客户已在配送系统中绑定到自提点 |

---

### 创建用户

```http
POST https://mobile.tezber.kz/api/v2/users
X-Api-Token: <token>
Content-Type: application/json
```

**请求：**

```json
{
  "phone": "87001234567",
  "name": "Иван",
  "surname": "Иванов",
  "iin": "123456789012",
  "proxyId": "NEO-CLIENT-001",
  "pickupPoint": "NEO-001"
}
```

| 字段 | 必填 | 说明 |
|------|:------------:|----------|
| `phone` | 是 | 客户手机号 |
| `name` | 是 | 名 |
| `surname` | 是 | 姓 |
| `iin` | 是 | ИИН |
| `proxyId` | 是 | 你方客户唯一编码 |
| `pickupPoint` | 是 | 已启用的自提点编码 |

使用相同手机号重复请求，将返回已存在的客户。

**响应：** `201 Created`

```json
{
  "phone": "87001234567",
  "name": "Иван",
  "surname": "Иванов",
  "iin": "123456789012",
  "proxyId": "NEO-CLIENT-001",
  "systemId": 123456,
  "pickupPoint": "NEO-001",
  "stationCreated": true
}
```

如果 `systemId` 为 `null` 或 `stationCreated` 为 `false`，请在几分钟后重新调用查询接口。

---

### 查询用户

```http
GET https://mobile.tezber.kz/api/v2/users/{phone}
X-Api-Token: <token>
```

`{phone}` - 客户手机号，例如 `87001234567`。

**响应：** `200 OK` - 用户对象

---

### 更换用户自提点

```http
PATCH https://mobile.tezber.kz/api/v2/users/{phone}/pickup-point
X-Api-Token: <token>
Content-Type: application/json
```

**请求：**

```json
{
  "pickupPoint": "NEO-002"
}
```

更换自提点后，在配送系统完成更新之前，`stationCreated` 字段可能变为 `false`。

**响应：** `200 OK` - 用户对象

---

## 包裹

基础路径：`/api/v2/orders`

如果包裹属于你方客户（按合作方的 `clientType` 判断），你可以将其标记为**已取件**（`issued`）。

### 标记包裹为已取件

```http
PATCH https://mobile.tezber.kz/api/v2/orders/{trackNumber}/issue
X-Api-Token: <token>
```

`{trackNumber}` - 包裹在 Tezber 中的运单号（与 webhook `CREATE_ORDER` / `UPDATE_STATUS` 中推送的一致）。

**响应：** `200 OK`

```json
{
  "trackNumber": "TB123456789",
  "status": "issued"
}
```

| 状态码 | 场景 |
|-----|-------|
| `200` | 状态设置成功，或包裹此前已是已取件状态（幂等） |
| `400` | 运单号为空 |
| `401` | Token 无效 |
| `404` | 包裹不存在或不属于你方合作方 |
| `409` | 包裹已处于其他终态 |

调用成功后，包裹在 Tezber 中变为终态 `issued`。对于此次调用，Tezber **不会**回推 `UPDATE_STATUS` webhook——因为该状态由合作方发起。

---

### 获取包裹照片

```http
GET https://mobile.tezber.kz/api/v2/orders/{trackNumber}/photo
X-Api-Token: <token>
```

`{trackNumber}` - 包裹运单号（例如 `[订单编号已隐藏]`）。

除中国仓照片外，响应中还包含包裹在 Tezber 中的数据：重量、当前状态、所属客户的 `proxyId`、目的自提点以及状态历史。状态历史仅包含设置的新状态及其时间（不含前一个状态）。如果运单已在中国仓但尚未进入 Tezber，照片会正常返回，订单相关字段则为 `null` / 空数组。

**响应：** `200 OK`

```json
{
  "trackNumber": "[订单编号已隐藏]",
  "photo": "https://api-jiyun-v3.haiouoms.com/storage/admin/134319291716702051_LBCDUB.jpg",
  "photos": [
    "https://api-jiyun-v3.haiouoms.com/storage/admin/134319291716702051_LBCDUB.jpg"
  ],
  "weight": "0.5",
  "status": "at_pick_up_point",
  "proxyId": "NEO-CLIENT-001",
  "pickupPoint": "NEO-001",
  "statusHistory": [
    {
      "status": "new",
      "statusAt": "2026-03-01T10:00:00+05:00"
    },
    {
      "status": "in_storage_china",
      "statusAt": "2026-03-02T14:20:00+05:00"
    },
    {
      "status": "at_pick_up_point",
      "statusAt": "2026-03-10T09:15:00+05:00"
    }
  ]
}
```

| 字段 | 类型 | 说明 |
|------|-----|----------|
| `trackNumber` | string | 运单号 |
| `photo` | string \| null | 主照片的完整 URL |
| `photos` | string[] | 包裹全部照片（完整 URL） |
| `weight` | string \| null | 重量，kg |
| `status` | string \| null | 包裹当前状态（见[包裹状态](#包裹状态)） |
| `proxyId` | string \| null | 包裹所属客户在你方的编码（来自 `POST /api/v2/users`） |
| `pickupPoint` | string \| null | 包裹目的自提点编码 |
| `statusHistory` | object[] | 状态历史，按时间顺序排列（由旧到新） |
| `statusHistory[].status` | string | 设置的新状态 |
| `statusHistory[].statusAt` | datetime | 状态设置时间（ISO-8601） |

| 状态码 | 场景 |
|-----|-------|
| `200` | 找到照片 |
| `400` | 运单号为空 |
| `401` | Token 无效 |
| `404` | 包裹或照片不存在 |
| `502` | 请求中国仓时出错 |

典型场景：客户发来运单号 → 你获取仓库照片（`GET .../photo`）进行核对 → 如有需要，创建绑定申请（`POST /api/v2/parcel-claims`）。

---

## 客户运单认领申请

基础路径：`/api/v2/parcel-claims`

当客户提供了一个在其账户中尚不存在的包裹运单号（或需要重新绑定）时，合作方可创建**包裹认领申请**。申请将提交至 Tezber 审核。

创建申请前，建议先获取**中国仓照片**（`GET /api/v2/orders/{trackNumber}/photo`），以便客户/运营人员直观核对包裹。

### 创建包裹认领申请

```http
POST https://mobile.tezber.kz/api/v2/parcel-claims
X-Api-Token: <token>
Content-Type: multipart/form-data
```

| 字段 | 类型 | 必填 | 说明 |
|------|-----|:------------:|----------|
| `trackNumber` | string | 是 | 包裹运单号 |
| `proxyId` | string | 是 | 你方客户的 `proxyId`（与创建用户时一致） |
| `file` | file | 否 | 客户提供的照片（申请附件，不要与仓库照片混淆） |

**响应：** `201 Created`

```json
{
  "id": 42,
  "createdAt": "2026-09-03T10:00:00+05:00",
  "updatedAt": "2026-09-03T10:00:00+05:00",
  "trackNumber": "[订单编号已隐藏]",
  "status": "PENDING",
  "adminComment": null,
  "reviewedByUsername": null,
  "reviewedAt": null,
  "photoUrl": null,
  "attemptsCount": 1,
  "applicantId": 1001,
  "applicantUsername": "87001234567",
  "applicantFullName": "Иван Иванов",
  "proxySkladId": "NEO-CLIENT-001",
  "parcelFound": true,
  "parcelCurrentStatus": "new",
  "parcelAssignedToSomeoneElse": false
}
```

| 字段 | 说明 |
|------|----------|
| `status` | `PENDING` - 已找到运单，等待审核；`NOT_FOUND` - 提交申请时 Tezber 中未找到该运单；`APPROVED` / `REJECTED` - 审核员的决定 |
| `parcelFound` | 响应时系统中是否找到该包裹 |
| `parcelAssignedToSomeoneElse` | 是否已绑定到其他客户 |
| `photoUrl` | **申请中**照片的 URL（如果你上传了 `file`），不是仓库照片 |
| `attemptsCount` | 该客户针对此运单提交申请的次数 |

| 状态码 | 场景 |
|-----|-------|
| `201` | 申请已创建 / 已更新 |
| `400` | 缺少 `trackNumber` / `proxyId`，或文件上传出错 |
| `401` | Token 无效 |
| `404` | 你方合作方下不存在该 `proxyId` 对应的客户 |

**cURL 示例：**

```bash
curl -X POST "https://mobile.tezber.kz/api/v2/parcel-claims" \
  -H "X-Api-Token: <token>" \
  -F "trackNumber=[订单编号已隐藏]" \
  -F "proxyId=NEO-CLIENT-001" \
  -F "file=@/path/to/client-photo.jpg"
```

不附带客户照片：

```bash
curl -X POST "https://mobile.tezber.kz/api/v2/parcel-claims" \
  -H "X-Api-Token: <token>" \
  -F "trackNumber=[订单编号已隐藏]" \
  -F "proxyId=NEO-CLIENT-001"
```

**结合仓库照片使用：**

```bash
# 1) 获取中国仓照片（完整 URL）
curl "https://mobile.tezber.kz/api/v2/orders/[订单编号已隐藏]/photo" \
  -H "X-Api-Token: <token>"

# 2) 提交运单绑定到客户的申请
curl -X POST "https://mobile.tezber.kz/api/v2/parcel-claims" \
  -H "X-Api-Token: <token>" \
  -F "trackNumber=[订单编号已隐藏]" \
  -F "proxyId=NEO-CLIENT-001"
```

---

## 出站 Webhook

（由 Tezber 推送至合作方）

当你方客户的包裹被创建或状态发生变化时，Tezber 会**主动推送**通知到你的服务器。  
合作方**无需**调用 Tezber 来获取这些事件——只需在自己一侧**接收**两个 webhook。

### 合作方需要做什么

1. **在自己的服务器上搭建两个 HTTP endpoint**（两种类型可共用一个 URL，但建议分开）：
   - **CREATE_ORDER** endpoint - 包裹创建；
   - **UPDATE_STATUS** endpoint - 状态变更。

2. **向 Tezber 团队提供**每个 endpoint 的：
   - `webhook_url` - 完整 URL（例如 `https://api.partner.kz/tezber/order`）；
   - `token` - 密钥 Token，Tezber 会将其放在 `X-Api-Token` 请求头中传递。

3. **在服务器端实现 Token 校验**：
   - Tezber 的每个请求都包含 `X-Api-Token` 请求头；
   - Token 错误或缺失时，返回 `401 Unauthorized`；
   - Tezber 不发送用户名/密码，只发送该请求头。

4. **提前创建客户**：通过 `POST /api/v2/users` 创建，并使用唯一的 `proxyId`。  
   在 webhook 中，客户**仅通过 `proxyId`** 识别，而非手机号。

5. **处理 JSON 请求体**（格式见下文），并返回 **`200 OK`** 或 **`201 Created`**。  
   收到成功响应（HTTP 2xx）后，Tezber 会立即将该次推送标记为已送达（`is_order_send` / `is_status_send = true`）。  
   如果 API 不可用或响应不是 2xx，Tezber 会通过 scheduler 重新推送（每批 50 条，每 2 分钟一次）。

---

### 两个 Token——切勿混淆

| Token | 使用方 | 方向 |
|-------|----------------|-------------|
| Tezber 合作方 API Token | 合作方 | 合作方 → Tezber（`/api/v2/...`） |
| Webhook Token（配置中的 `token`） | Tezber | Tezber → 合作方（你的 endpoint） |

这是**不同**的两个值。Webhook Token 由你自行设定，并在接入集成时提供给 Tezber。

---

### Tezber 请求的通用格式

```http
POST <你的 webhook_url>
X-Api-Token: <你的 webhook token>
Content-Type: application/json
```

请求方法始终为 **`POST`**。事件类型由请求到达的 **URL** 决定（CREATE_ORDER 或 UPDATE_STATUS），而不是由 JSON 中的字段决定。

---

### Webhook 1：CREATE_ORDER

**触发时机：** Tezber 中为你此前通过 API 注册的客户（`proxyId` + 你方合作方的 `clientType`）创建了新包裹。

**你方需要做的：**
- 根据 `proxyId` 找到客户；
- 以 `trackNumber` 创建/登记包裹；
- 保存初始的 `status`、`qty`、`weight`、`pickupPoint`。

**请求体：**

```json
{
  "proxyId": "NEO-CLIENT-001",
  "trackNumber": "TB123456789",
  "status": "new",
  "createdAt": "2026-07-01T10:00:00+05:00",
  "qty": "1",
  "weight": "0.5",
  "pickupPoint": "NEO-001"
}
```

| 字段 | 类型 | 说明 |
|------|-----|----------|
| `proxyId` | string | 你方客户编码（来自 `POST /api/v2/users`） |
| `trackNumber` | string | 包裹在 Tezber 中的运单号 |
| `status` | string | 当前状态（见[包裹状态](#包裹状态)） |
| `createdAt` | datetime | 包裹在 Tezber 中的创建时间（ISO-8601） |
| `qty` | string | 数量 |
| `weight` | string | 重量，kg |
| `pickupPoint` | string | 客户的自提点编码 |

**成功响应：**

```http
HTTP/1.1 200 OK
```

---

### Webhook 2：UPDATE_STATUS

**触发时机：** 你方客户的包裹在 Tezber 中发生状态变更（仓库、配送、取件等）。

**你方需要做的：**
- 根据 `trackNumber`（或 `proxyId` + `trackNumber` 组合）找到包裹；
- 将状态更新为 `status` 中传入的值；
- 遇到终态 `issued` 时，在你方系统中关闭该包裹。

**请求体：**

```json
{
  "proxyId": "NEO-CLIENT-001",
  "trackNumber": "TB123456789",
  "status": "dispatched",
  "statusAt": "2026-07-02T12:30:00+05:00"
}
```

| 字段 | 类型 | 说明 |
|------|-----|----------|
| `proxyId` | string | 你方客户编码 |
| `trackNumber` | string | 包裹运单号 |
| `status` | string | 新状态 |
| `statusAt` | datetime | 状态在 Tezber 中的设置时间（ISO-8601） |

**成功响应：**

```http
HTTP/1.1 200 OK
```

---

### 入站请求示例（供合作方测试）

**CREATE_ORDER：**

```bash
curl -X POST "https://api.partner.kz/tezber/order" \
  -H "X-Api-Token: your-webhook-token" \
  -H "Content-Type: application/json" \
  -d '{
    "proxyId": "NEO-CLIENT-001",
    "trackNumber": "TB123456789",
    "status": "new",
    "qty": "1",
    "weight": "0.5",
    "pickupPoint": "NEO-001"
  }'
```

**UPDATE_STATUS：**

```bash
curl -X POST "https://api.partner.kz/tezber/status" \
  -H "X-Api-Token: your-webhook-token" \
  -H "Content-Type: application/json" \
  -d '{
    "proxyId": "NEO-CLIENT-001",
    "trackNumber": "TB123456789",
    "status": "dispatched"
  }'
```

---

### 上线前检查清单

- [ ] 已通过 `POST /api/v2/pickup-point` 创建自提点
- [ ] 客户通过 `POST /api/v2/users` 创建，且 `proxyId` 唯一
- [ ] 客户已获得 `systemId`（`stationCreated: true`）
- [ ] 两个 HTTPS endpoint 已搭建并可从公网访问
- [ ] URL 和 webhook Token 已提供给 Tezber 团队
- [ ] endpoint 已校验 `X-Api-Token`
- [ ] CREATE_ORDER 能在合作方侧创建包裹
- [ ] UPDATE_STATUS 能按 `trackNumber` 更新状态
- [ ] 成功时返回 `200` / `201`

---

## 接收中国仓集包袋

Tezber（china-stockhold）每小时向合作方推送一次已打包完成、且 `marketplace` 与合作方代码一致（例如 `NEO`）的集包袋。

合作方需搭建接收集包袋的 HTTPS endpoint，并向 Tezber 团队提供：
- `api_base_url` — 合作方 API 的基础 URL
- `bags_path` — 接收集包袋接口的路径（默认 `/bags`）
- `bags_status_path` — 集包袋状态接口的路径（默认 `/bags/status`）
- `outbound_token` — 用于 `X-Api-Token` 请求头的 Token

### 合作方 Endpoint

```http
POST {api_base_url}{bags_path}
X-Api-Token: <outbound_token>
Content-Type: application/json
```

示例：`POST https://api.partner.kz/bags`

### 请求体

集包袋信息 + 袋内包裹运单号列表。

```json
{
  "sn": "SN-001",
  "name": "BAG-NEO-001",
  "marketplace": "NEO",
  "station": "MIX",
  "tag": "TO SHOP",
  "weight": "12.5",
  "boxCount": 10,
  "partyNumber": 3,
  "tracks": [
    "TB123456789",
    "TB987654321"
  ]
}
```

| 字段 | 类型 | 说明 |
|------|-----|----------|
| `sn` | string | 集包袋内部 SN |
| `name` | string | 集包袋编号 / 名称 |
| `marketplace` | string | 合作方 marketplace（`NEO` 等） |
| `station` | string | 站点 |
| `tag` | string | 集包袋标签 |
| `weight` | string | 重量 |
| `boxCount` | number | 件数 / 包裹数 |
| `partyNumber` | number | 批次号 |
| `tracks` | string[] | 袋内包裹运单号 |

### 响应

| 状态码 | 场景 |
|-----|-------|
| `200` / `201` | 集包袋已接收 |
| `409` | 集包袋已存在（Tezber 视为成功，不再重试） |
| `401` | `X-Api-Token` 无效 |
| `4xx` / `5xx` | 出错——Tezber 将在下一个整点批次重试 |

### cURL 示例

```bash
curl -X POST "https://api.partner.kz/bags" \
  -H "X-Api-Token: your-outbound-token" \
  -H "Content-Type: application/json" \
  -d '{
    "sn": "SN-001",
    "name": "BAG-NEO-001",
    "marketplace": "NEO",
    "weight": "12.5",
    "tracks": ["TB123456789", "TB987654321"]
  }'
```

### 合作方检查清单

- [ ] 已搭建 `POST {bags_path}`（默认 `/bags`）
- [ ] 已校验 `X-Api-Token`
- [ ] 已保存集包袋及 `tracks` 列表
- [ ] 幂等：相同 `sn`/`name` 重复推送 → 返回 `200` 或 `409`
- [ ] `api_base_url`、`bags_path`、`outbound_token` 已提供给 Tezber

### 集包袋状态 Endpoint

Tezber 按 SN 向合作方推送集包袋状态。

合作方需搭建：

```http
POST {api_base_url}{bags_status_path}
X-Api-Token: <outbound_token>
Content-Type: application/json
```

默认：`POST https://api.partner.kz/bags/status`

### 请求体（集包袋列表）

```json
{
  "bags": [
    {
      "sn": "SN-001",
      "status": "DISPATCHED",
      "statusAt": "2026-07-23T14:30:00"
    },
    {
      "sn": "SN-002",
      "status": "LOADED",
      "statusAt": "2026-07-23T15:00:00"
    }
  ]
}
```

| 字段 | 类型 | 说明 |
|------|-----|----------|
| `bags` | array | 状态更新列表 |
| `bags[].sn` | string | 集包袋 SN |
| `bags[].status` | string | TMS 中的集包袋状态（`BagStatus`，见下文） |
| `bags[].statusAt` | datetime | 状态设置时间 |

### cURL 示例

```bash
curl -X POST "https://api.partner.kz/bags/status" \
  -H "X-Api-Token: your-outbound-token" \
  -H "Content-Type: application/json" \
  -d '{
    "bags": [
      {
        "sn": "SN-001",
        "status": "DISPATCHED",
        "statusAt": "2026-07-23T14:30:00"
      }
    ]
  }'
```

---

## 集包袋状态

状态与 TMS 中的 `BagStatus` 枚举一致（大小写相同：`UPPER_SNAKE_CASE`）。

| 代码 | 中文 | 英文 | 俄文 |
|-----|----|----|----|
| `CREATED` | 已创建 | Created | Создан |
| `RECEIVED` | 已接收 | Received | Получен |
| `DEPARTURE_ZONED` | 在发货区 | Departure zoned | В зоне отправления |
| `LOADED` | 已装载 | Loaded | Загружен |
| `DISPATCHED` | 已发出 | Dispatched | Отправлен |
| `TRANSIT_RECEIVED` | 中转站已接收 | Received at transit | Получен на транзите |
| `TRANSIT_ZONED` | 在中转区 | In transit zone | В зоне на транзите |
| `LOADED_TRANSIT` | 已装载转运 | Loaded to transit | Загружен в транзит |
| `TRANSIT_DISPATCHED` | 已从中转站发出 | Dispatched from transit | Отправлен с транзита |
| `TRANSIT_CUSTOMS_EXPORT_COMPLETED` | 出口清关完成 | Export customs completed | Затаможка завершена |
| `TRANSIT_CUSTOMS_IMPORT_COMPLETED` | 进口清关完成 | Import customs completed | Растаможка завершена |
| `TERMINAL_RECEIVED` | 终端已接收 | Received at terminal | Получен на терминале |
| `TERMINAL_ZONED` | 在终端区域 | In terminal zone | В зоне терминала |
| `TERMINAL_ISSUED` | 已交付 | Issued | Выдан |

状态时间始终通过 `statusAt` 字段，与 `sn`、`status` 一同传递。

---

## 包裹状态

在出站 webhook（`CREATE_ORDER`、`UPDATE_STATUS`）中，`status` 字段里的空格会被替换为下划线：例如 `in transit in china` → `in_transit_in_china`，`guangzhou warehouse` → `guangzhou_warehouse`。

| 代码 | 说明 | 终态 |
|-----|----------|:---------:|
| `new` | 已受理（中国） | |
| `guangzhou_warehouse` | 已从承运商仓库发出 | |
| `in_transit_in_china` | 中国境内运输中 | |
| `received`            | 已到仓签收 | |
| `dispatched`          | 已发出 | |
| `on_the_way_to_point` | 正在运往自提点 | |
| `at_pick_up_point`    | 待取件 | |
| `issued`              | 已取件 | 是 |

---

## 响应码

| 状态码 | 说明 |
|-----|----------|
| `200` | 成功 |
| `201` | 已创建 |
| `400` | 数据不正确或自提点未启用 |
| `401` | Token 无效 |
| `404` | 未找到 |
| `409` | 冲突：自提点编码重复、`proxyId`/手机号已被占用，或集包袋已接收 |

---

## 集成流程

### 入站 API（合作方 → Tezber）

```
1. POST /api/v2/pickup-point                    → 创建自提点
2. POST /api/v2/users                           → 用 proxyId 创建客户，获取 systemId
3. GET  /api/v2/users/87001234567               → 必要时检查 systemId
4. PATCH /api/v2/users/87001234567/pickup-point → 更换客户自提点（如需要）
5. GET   /api/v2/orders/[订单编号已隐藏]/photo → 获取仓库照片（核对运单）
6. POST  /api/v2/parcel-claims                → 客户运单认领申请
7. PATCH /api/v2/orders/TB123456789/issue     → 标记包裹为已取件
```

### 出站 Webhook（Tezber → 合作方）

```
8. 合作方搭建 CREATE_ORDER endpoint       → 向 Tezber 提供 URL 和 token
9. 合作方搭建 UPDATE_STATUS endpoint      → 向 Tezber 提供 URL 和 token
10. Tezber 推送 CREATE_ORDER               → 客户包裹创建时
11. Tezber 推送 UPDATE_STATUS              → 包裹每次状态变更时
```

### 接收集包袋（china-stockhold → 合作方）

```
12. 合作方搭建 POST /bags                 → 提供 api_base_url、bags_path、outbound_token
13. Tezber 每小时推送 marketplace=合作方 的集包袋
14. 合作方搭建 POST /bags/status          → 提供 bags_status_path
15. Tezber 推送集包袋状态（sn + status + statusAt）
```

### cURL 示例

**创建自提点：**

```bash
curl -X POST "https://mobile.tezber.kz/api/v2/pickup-point" \
  -H "X-Api-Token: <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "NEO-001",
    "name": "NEO ПВЗ",
    "address": "ул. Абая 1",
    "city": "Алматы",
    "phone": "[电话示例已隐藏]",
    "workingTime": "09:00-21:00"
  }'
```

**创建用户：**

```bash
curl -X POST "https://mobile.tezber.kz/api/v2/users" \
  -H "X-Api-Token: <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "87001234567",
    "name": "Иван",
    "surname": "Иванов",
    "iin": "123456789012",
    "proxyId": "NEO-CLIENT-001",
    "pickupPoint": "NEO-001"
  }'
```

**查询用户：**

```bash
curl "https://mobile.tezber.kz/api/v2/users/87001234567" \
  -H "X-Api-Token: <token>"
```

**更换自提点：**

```bash
curl -X PATCH "https://mobile.tezber.kz/api/v2/users/87001234567/pickup-point" \
  -H "X-Api-Token: <token>" \
  -H "Content-Type: application/json" \
  -d '{"pickupPoint": "NEO-002"}'
```

**启用中的自提点列表：**

```bash
curl "https://mobile.tezber.kz/api/v2/pickup-point?active=true" \
  -H "X-Api-Token: <token>"
```

**停用自提点：**

```bash
curl -X PATCH "https://mobile.tezber.kz/api/v2/pickup-point/NEO-001/deactivate" \
  -H "X-Api-Token: <token>"
```

**获取包裹仓库照片：**

```bash
curl "https://mobile.tezber.kz/api/v2/orders/[订单编号已隐藏]/photo" \
  -H "X-Api-Token: <token>"
```

**创建客户运单认领申请：**

```bash
curl -X POST "https://mobile.tezber.kz/api/v2/parcel-claims" \
  -H "X-Api-Token: <token>" \
  -F "trackNumber=[订单编号已隐藏]" \
  -F "proxyId=NEO-CLIENT-001"
```

**标记包裹为已取件：**

```bash
curl -X PATCH "https://mobile.tezber.kz/api/v2/orders/TB123456789/issue" \
  -H "X-Api-Token: <token>"
```

---

## 接口汇总

### Tezber API（由你调用）

| 方法 | URL | 说明 |
|-------|-----|----------|
| `POST` | `/api/v2/pickup-point` | 创建自提点 |
| `GET` | `/api/v2/pickup-point` | 自提点列表 |
| `GET` | `/api/v2/pickup-point?active=true` | 仅启用的自提点 |
| `PUT` | `/api/v2/pickup-point/{code}` | 更新自提点 |
| `PATCH` | `/api/v2/pickup-point/{code}/deactivate` | 停用自提点 |
| `POST` | `/api/v2/users` | 创建用户 |
| `GET` | `/api/v2/users/{phone}` | 查询用户 |
| `PATCH` | `/api/v2/users/{phone}/pickup-point` | 更换用户自提点 |
| `GET` | `/api/v2/orders/{trackNumber}/photo` | 中国仓包裹照片、重量、状态、所属客户、自提点及状态历史 |
| `POST` | `/api/v2/parcel-claims` | 客户运单认领申请 |
| `PATCH` | `/api/v2/orders/{trackNumber}/issue` | 标记包裹为已取件 |

**调用 Tezber 的请求头：** `X-Api-Token: <你的合作方 API token>`

### 合作方 Webhook（Tezber 调用你）

| 事件 | 方法 | URL | 说明 |
|---------|-------|-----|----------|
| `CREATE_ORDER` | `POST` | 你的 `webhook_url` | 包裹已创建 |
| `UPDATE_STATUS` | `POST` | 你的 `webhook_url` | 包裹状态已变更 |
| 接收集包袋 | `POST` | `{api_base_url}{bags_path}` | 中国仓集包袋（`/bags`） |
| 集包袋状态 | `POST` | `{api_base_url}{bags_status_path}` | 集包袋状态（`/bags/status`） |

**Webhook / 接收集包袋的请求头：** `X-Api-Token: <你的 outbound token>`

---

如有集成相关问题，请联系 Tezber 技术支持。

## 同期可观察评论（当前正文）

### 评论 231641

创建：2026-09-24T09:01:22.064Z；更新：2026-09-24T09:01:22.064Z。

[原评论](https://gitlab.parsec.com.cn/umay/doc-and-issues/-/issues/3090#note_231641)

需客户提供TOKEN,以及测试环境接口域名

## 固定版本代码关联候选


未核对完整实现；没有路径关联时，不代表需求不存在或已经实现。
