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

# 工作流程

> 从服务请求创建到图片上传和验证的分步流程。

## 分步实施

<Steps>
  <Step title="创建服务请求">
    当物品准备好进行认证时，创建一个服务请求。这将提供所选物品类别的具体图片要求。

    **API 参考：** [`POST /api/v2/sr`](/api-reference#tag/Service-Requests/operation/initiate-service-request)

    **必需标头：**

    ```javascript theme={null}
    const headers = {
      'Authorization': 'Bearer leo_xxxxxxxxx',      // 您的 API 密钥
      'Content-Type': 'application/json'
    };
    ```

    **请求数据：**

    * **服务 UUID**（可选）：合作伙伴服务标识符。如果省略，将根据您的组织和物品类型自动解析。
    * **物品分类体系**：来自分类体系映射的类别、类型、品牌 UUID
    * **外部 ID**（可选）：用于关联的内部物品标识符

    <CodeGroup>
      ```javascript HTTP theme={null}
      const response = await fetch('https://api.legitmark.com/api/v2/sr', {
        method: 'POST',
        headers,
        body: JSON.stringify({
          // service 可选 - 如果省略将自动解析
          external_id: 'your-internal-ref-123',
          item: {
            category: 'category-uuid',
            type: 'type-uuid',
            brand: 'brand-uuid',
          }
        })
      });
      ```

      ```typescript SDK theme={null}
      const { sr } = await legitmark.sr.create({
        // service 可选 - 如果省略将自动解析
        external_id: 'your-internal-ref-123',
        item: {
          category: 'category-uuid',
          type: 'type-uuid',
          brand: 'brand-uuid',
        },
      });
      ```
    </CodeGroup>

    **依赖项：**

    * 分类体系映射已配置（参见[分类体系](/cn/partner/taxonomy)）
  </Step>

  <Step title="获取图片要求">
    检索物品类别所需的具体图片面。这会告诉您需要拍摄哪些照片。

    **API 参考：** [`GET /api/v2/sr/{sr_uuid}`](/api-reference#tag/Service-Requests/operation/get-service-request) 带查询参数

    使用 `requirements=true` 和 `sides=true` 获取服务请求以获得完整的图片要求：

    <CodeGroup>
      ```javascript HTTP theme={null}
      const response = await fetch(
        `https://api.legitmark.com/api/v2/sr/${srUuid}?requirements=true&sides=true&item=true`,
        { headers }
      );
      const { sr } = await response.json();

      // sr.requirements 包含面组和必需/可选面
      for (const group of sr.requirements.side_groups) {
        for (const side of group.sides) {
          console.log(`${side.name}: ${side.required ? '必需' : '可选'}`);
        }
      }
      ```

      ```typescript SDK theme={null}
      const { sr } = await legitmark.sr.getWithRequirements(srUuid);

      console.log(`必需照片: ${sr.requirements?.total_required}`);

      for (const group of sr.requirements?.side_groups || []) {
        for (const side of group.sides) {
          console.log(`${side.name}: ${side.required ? '必需' : '可选'}`);
        }
      }
      ```
    </CodeGroup>

    **响应数据：**

    * **面组** - 按组组织的图片要求
    * **必需面** - 认证必须的图片
    * **可选面** - 增强认证的附加图片
    * **模板图片** - 每个所需角度的视觉指南

    **图片要求：**

    * **格式：** JPG/JPEG/PNG
    * **尺寸：** 最小 600 x 600 像素
    * **文件大小：** 每张图片最大 5 MB
    * **质量：** 清晰、光线充足、对焦准确的图片
  </Step>

  <Step title="上传图片">
    使用 Legitmark 的安全 CDN 系统上传图片。对于每个必需面，获取签名 URL 并直接上传到 S3。

    **API 参考：** 媒体管理端点

    * [`GET https://asset.legitmark.com/intent`](/api-reference/media-management/generate-upload-url) - 获取预签名上传 URL
    * [`PUT /{presigned-url}`](/api-reference/media-management/upload-image) - 直接 S3 上传

    **上传流程：**

    1. **获取上传 URL**，使用查询参数：`sr`（服务请求 UUID）和 `side`（带文件扩展名的面 UUID）
    2. **直接上传**到预签名 S3 URL，使用 PUT 请求和二进制数据

    <CodeGroup>
      ```javascript HTTP theme={null}
      // 步骤 1：获取预签名上传 URL
      const intentResponse = await fetch(
        `https://asset.legitmark.com/intent?sr=${srUuid}&side=${sideUuid}.jpg`,
        { headers }
      );
      const { url: presignedUrl } = await intentResponse.json();

      // 步骤 2：上传二进制图片数据到预签名 URL
      await fetch(presignedUrl, {
        method: 'PUT',
        body: imageFile,
        headers: { 'Content-Type': 'image/jpeg' }
      });
      ```

      ```typescript SDK theme={null}
      // 从文件路径上传
      await legitmark.images.uploadForSide(srUuid, sideUuid, './photo.jpg');

      // 或从缓冲区上传
      await legitmark.images.uploadForSide(srUuid, sideUuid, imageBuffer);
      ```
    </CodeGroup>
  </Step>

  <Step title="检查进度">
    在提交之前验证所有必需图片已上传。

    使用 `sides=true` 获取服务请求以获取当前进度，包括已上传的必需和可选图片数量：

    <CodeGroup>
      ```javascript HTTP theme={null}
      const response = await fetch(
        `https://api.legitmark.com/api/v2/sr/${srUuid}?sides=true`,
        { headers }
      );
      const { sr } = await response.json();

      const progress = sr.sides.progress;
      console.log(`已上传: ${progress.current_required}/${progress.total_required}`);
      console.log(`准备提交: ${progress.met}`);
      ```

      ```typescript SDK theme={null}
      const progress = await legitmark.sr.getProgress(srUuid);

      console.log(`已上传: ${progress.current_required}/${progress.total_required}`);
      console.log(`准备提交: ${progress.met}`);
      ```
    </CodeGroup>

    **进度响应：**

    ```json theme={null}
    {
      "current_required": 2,
      "total_required": 2,
      "current_optional": 1,
      "total_optional": 3,
      "met": true
    }
    ```

    当 `met` 为 `true` 时，所有必需图片已上传，服务请求可以提交。
  </Step>

  <Step title="提交认证">
    一旦进度要求满足，将服务请求提交给专家进行认证。

    **API 参考：** [`POST /api/v2/sr/{sr_uuid}/submit`](/api-reference#tag/Service-Requests/operation/submit-service-request)

    <CodeGroup>
      ```javascript HTTP theme={null}
      const response = await fetch(
        `https://api.legitmark.com/api/v2/sr/${srUuid}/submit`,
        { method: 'POST', headers }
      );
      const { sr } = await response.json();
      console.log(`已提交！状态: ${sr.state.primary}/${sr.state.supplement}`);
      ```

      ```typescript SDK theme={null}
      const progress = await legitmark.sr.getProgress(srUuid);

      if (progress.met) {
        const { sr } = await legitmark.sr.submit(srUuid);
        console.log(`已提交！状态: ${sr.state.primary}/${sr.state.supplement}`);
      }
      ```
    </CodeGroup>

    **提交后流程：**

    1. **质量控制审核**：图片和数据验证
    2. **认证审核**：专家进行认证
    3. **结果通知**：每个阶段的 Webhook 更新（参见[状态](/cn/partner/service-request-states)）
  </Step>
</Steps>

## 实施模式

### 错误处理

使用 SDK 的内置重试功能或实施您自己的逻辑来处理临时故障：

<CodeGroup>
  ```javascript HTTP theme={null}
  async function createServiceRequest(itemData) {
    const maxRetries = 3;
    let lastError;

    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        const response = await fetch('https://api.legitmark.com/api/v2/sr', {
          method: 'POST',
          headers,
          body: JSON.stringify(itemData)
        });

        if (!response.ok) {
          const error = await response.json();
          throw new Error(`服务请求失败: ${error.message}`);
        }

        return await response.json();
      } catch (error) {
        lastError = error;
        if (attempt < maxRetries) {
          await new Promise(r => setTimeout(r, 1000 * attempt)); // 指数退避
        }
      }
    }
    
    throw lastError;
  }
  ```

  ```typescript SDK theme={null}
  // SDK 自动处理重试
  const { sr } = await legitmark.sr.create(itemData, {
    retry: {
      maxRetries: 3,
      backoffMs: 1000,
    }
  });
  ```
</CodeGroup>

### 批量图片上传

```javascript theme={null}
async function uploadAllImages(srUuid, imagesToUpload) {
  const uploadPromises = imagesToUpload.map(async ({ sideUuid, imageFile }) => {
    // 获取预签名 URL
    const intentRes = await fetch(
      `https://asset.legitmark.com/intent?sr=${srUuid}&side=${sideUuid}.jpg`,
      { headers }
    );
    const { url } = await intentRes.json();

    // 上传图片
    await fetch(url, {
      method: 'PUT',
      body: imageFile,
      headers: { 'Content-Type': 'image/jpeg' }
    });

    return { sideUuid, success: true };
  });

  return Promise.all(uploadPromises);
}
```

## 最佳实践

### 售前优化

* **缓存图片要求**用于常用类别
* **客户端验证图片**在存储前
* **压缩图片**同时保持质量标准

### 上传优化

* **使用并行上传**处理多张图片
* **实施重试逻辑**处理失败的上传
* **显示上传进度**给用户
* **验证上传完成**后再继续

## 后续步骤

工作流程实施完成后：

1. **设置** [Webhooks](/cn/webhook-reference/introduction) - Webhook 通知和状态更新处理
2. **测试端到端**工作流程与示例物品
3. **监控**认证处理和成功率
