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

# /v1/files/upload_url

> 获取一个预签名的文件上传 URL，客户端可以直接使用该 URL 将文件上传到对象存储服务（如 COS、GCS）。适用于大文件上传或客户端直传场景，避免文件数据经过应用服务器中转。返回的 upload_url 包含签名信息，客户端需使用指定的 HTTP method 将文件 PUT/POST 到该 URL。

## 使用指南

通过预签名 URL 上传文件分为两步：先获取上传 URL，再使用该 URL 直接上传文件到对象存储。

### 第一步：获取预签名上传 URL

调用 `/v1/files/upload_url` 接口，传入文件路径，获取带签名的上传 URL。

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://model-api.skyengine.com.cn/v1/files/upload_url" \
    -H "Authorization: Bearer <API-KEY>" \
    -H "Content-Type: application/json" \
    -d '{
      "path": "my_files/test.mp4",
      "storage_provider": "COS"
    }'
  ```

  ```python Python theme={null}
  import requests

  API_KEY = "<API-KEY>"
  BASE_URL = "https://model-api.skyengine.com.cn/v1"

  def get_upload_url(file_path, storage_provider="COS"):
      """
      第一步：获取预签名上传 URL
      """
      url = f"{BASE_URL}/files/upload_url"
      headers = {
          "Authorization": f"Bearer {API_KEY}",
          "Content-Type": "application/json"
      }
      payload = {
          "path": file_path,
          "storage_provider": storage_provider
      }

      response = requests.post(url, headers=headers, json=payload)

      if response.status_code == 200:
          result = response.json()
          print(f"上传URL: {result['upload_url']}")
          print(f"HTTP方法: {result['method']}")
          print(f"文件路径: {result['path']}")
          print(f"访问URL: {result['visit_url']}")
          return result
      else:
          print(f"错误: {response.status_code} - {response.text}")
          return None
  ```

  ```javascript JavaScript theme={null}
  const API_KEY = "<API-KEY>";
  const BASE_URL = "https://model-api.skyengine.com.cn/v1";

  async function getUploadUrl(filePath, storageProvider = "COS") {
    const response = await fetch(`${BASE_URL}/files/upload_url`, {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${API_KEY}`,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        path: filePath,
        storage_provider: storageProvider
      })
    });

    if (response.ok) {
      const result = await response.json();
      console.log("上传URL:", result.upload_url);
      console.log("HTTP方法:", result.method);
      console.log("文件路径:", result.path);
      console.log("访问URL:", result.visit_url);
      return result;
    } else {
      console.error("错误:", response.status, await response.text());
      return null;
    }
  }
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"encoding/json"
  	"fmt"
  	"io"
  	"net/http"
  )

  const (
  	apiKey  = "<API-KEY>"
  	baseURL = "https://model-api.skyengine.com.cn/v1"
  )

  type UploadURLRequest struct {
  	Path            string `json:"path"`
  	StorageProvider string `json:"storage_provider"`
  }

  type UploadURLResponse struct {
  	UploadURL string `json:"upload_url"`
  	Method    string `json:"method"`
  	Path      string `json:"path"`
  	VisitURL  string `json:"visit_url"`
  }

  func getUploadURL(filePath, storageProvider string) (*UploadURLResponse, error) {
  	reqBody, _ := json.Marshal(UploadURLRequest{
  		Path:            filePath,
  		StorageProvider: storageProvider,
  	})

  	req, _ := http.NewRequest("POST", baseURL+"/files/upload_url", bytes.NewReader(reqBody))
  	req.Header.Set("Authorization", "Bearer "+apiKey)
  	req.Header.Set("Content-Type", "application/json")

  	resp, err := http.DefaultClient.Do(req)
  	if err != nil {
  		return nil, err
  	}
  	defer resp.Body.Close()

  	body, _ := io.ReadAll(resp.Body)
  	var result UploadURLResponse
  	json.Unmarshal(body, &result)

  	fmt.Printf("上传URL: %s\n", result.UploadURL)
  	fmt.Printf("HTTP方法: %s\n", result.Method)
  	return &result, nil
  }
  ```
</CodeGroup>

**返回示例：**

```json theme={null}
{
  "upload_url": "https://bucket.cos.ap-guangzhou.myqcloud.com/my_files/test.mp4?sign=xxx",
  "method": "PUT",
  "path": "cos://bucket.cos.ap-guangzhou.myqcloud.com/my_files/test.mp4",
  "visit_url": "https://bucket.cos.ap-guangzhou.myqcloud.com/my_files/test.mp4"
}
```

### 第二步：使用预签名 URL 上传文件

拿到 `upload_url` 和 `method` 后，使用对应的 HTTP 方法将文件内容直接上传到该 URL。

<CodeGroup>
  ```bash cURL theme={null}
  # 使用第一步返回的 upload_url 和 method 上传文件
  curl -X PUT "<upload_url>" \
    --upload-file ./test.mp4
  ```

  ```python Python theme={null}
  def upload_file(local_file_path, upload_url, method="PUT"):
      """
      第二步：使用预签名 URL 上传文件
      """
      with open(local_file_path, "rb") as f:
          file_data = f.read()

      response = requests.request(method, upload_url, data=file_data)

      if response.status_code in [200, 201]:
          print("文件上传成功！")
          return True
      else:
          print(f"上传失败: {response.status_code} - {response.text}")
          return False


  # 完整流程示例
  if __name__ == "__main__":
      # 第一步：获取上传 URL
      result = get_upload_url("my_files/test.mp4")

      if result:
          # 第二步：上传文件
          upload_file("./test.mp4", result["upload_url"], result["method"])
          print(f"文件访问地址: {result['visit_url']}")
  ```

  ```javascript JavaScript theme={null}
  async function uploadFile(localFilePath, uploadUrl, method = "PUT") {
    const fs = require("fs");
    const fileData = fs.readFileSync(localFilePath);

    const response = await fetch(uploadUrl, {
      method: method,
      body: fileData
    });

    if (response.ok) {
      console.log("文件上传成功！");
      return true;
    } else {
      console.error("上传失败:", response.status, await response.text());
      return false;
    }
  }

  // 完整流程示例
  async function main() {
    // 第一步：获取上传 URL
    const result = await getUploadUrl("my_files/test.mp4");

    if (result) {
      // 第二步：上传文件
      await uploadFile("./test.mp4", result.upload_url, result.method);
      console.log("文件访问地址:", result.visit_url);
    }
  }

  main();
  ```

  ```go Go theme={null}
  func uploadFile(localFilePath, uploadURL, method string) error {
  	fileData, err := os.ReadFile(localFilePath)
  	if err != nil {
  		return fmt.Errorf("读取文件失败: %v", err)
  	}

  	req, _ := http.NewRequest(method, uploadURL, bytes.NewReader(fileData))
  	resp, err := http.DefaultClient.Do(req)
  	if err != nil {
  		return fmt.Errorf("上传失败: %v", err)
  	}
  	defer resp.Body.Close()

  	if resp.StatusCode == 200 || resp.StatusCode == 201 {
  		fmt.Println("文件上传成功！")
  		return nil
  	}

  	body, _ := io.ReadAll(resp.Body)
  	return fmt.Errorf("上传失败: %d - %s", resp.StatusCode, string(body))
  }

  func main() {
  	// 第一步：获取上传 URL
  	result, err := getUploadURL("my_files/test.mp4", "COS")
  	if err != nil {
  		fmt.Println("获取上传URL失败:", err)
  		return
  	}

  	// 第二步：上传文件
  	err = uploadFile("./test.mp4", result.UploadURL, result.Method)
  	if err != nil {
  		fmt.Println(err)
  		return
  	}
  	fmt.Printf("文件访问地址: %s\n", result.VisitURL)
  }
  ```
</CodeGroup>

<Note>
  预签名 URL 有时效限制，获取后请尽快完成文件上传。上传完成后，可通过返回的 `visit_url` 访问文件，或使用 `path` 字段在其他 API 中引用该文件。
</Note>


## OpenAPI

````yaml POST /v1/files/upload_url
openapi: 3.1.0
info:
  title: TokenOps AI API
  description: TokenOps AI API 提供了强大的AI服务能力，包括聊天对话、Gemini模型集成等功能。
  license:
    name: MIT
  version: 1.0.0
servers:
  - url: https://model-api.skyengine.com.cn
    description: TokenOps AI API 生产环境
security: []
paths:
  /v1/files/upload_url:
    post:
      summary: 获取文件上传URL
      description: >-
        获取一个预签名的文件上传 URL，客户端可以直接使用该 URL 将文件上传到对象存储服务（如
        COS、GCS）。适用于大文件上传或客户端直传场景，避免文件数据经过应用服务器中转。返回的 upload_url
        包含签名信息，客户端需使用指定的 HTTP method 将文件 PUT/POST 到该 URL。
      operationId: getUploadURL
      requestBody:
        required: true
        description: 获取上传 URL 的请求参数，需指定文件上传路径，可选指定存储提供商和区域。
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GetUploadURLRequest'
      responses:
        '200':
          description: 获取上传URL成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetUploadURLResponse'
              examples:
                cos_example:
                  summary: COS 存储上传URL
                  value:
                    upload_url: >-
                      https://bucket.cos.ap-guangzhou.myqcloud.com/example/test.mp4?sign=xxx
                    method: PUT
                    path: >-
                      cos://bucket.cos.ap-guangzhou.myqcloud.com/example/test.mp4
                    visit_url: >-
                      https://bucket.cos.ap-guangzhou.myqcloud.com/example/test.mp4
        '400':
          description: 请求参数错误
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: API Key 认证失败
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - bearerAuth: []
components:
  schemas:
    GetUploadURLRequest:
      type: object
      required:
        - path
      properties:
        path:
          type: string
          description: 文件上传路径，不能超过 255 个字符
          maxLength: 255
          example: my_files/test.mp4
        storage_provider:
          type: string
          description: 存储提供商，默认为 COS（腾讯云对象存储）
          default: COS
          example: COS
        region:
          type: string
          description: 存储区域，可选参数。COS 默认为 ap-guangzhou
          example: ap-guangzhou
    GetUploadURLResponse:
      type: object
      required:
        - upload_url
        - method
        - path
        - visit_url
      properties:
        upload_url:
          type: string
          description: 预签名的文件上传 URL，客户端使用该 URL 直接上传文件到对象存储。URL 包含签名信息，有效期有限
          example: >-
            https://bucket.cos.ap-guangzhou.myqcloud.com/my_files/test.mp4?sign=xxx
        method:
          type: string
          description: 上传文件时使用的 HTTP 方法
          example: PUT
        path:
          type: string
          description: 文件的存储路径标识，COS 使用 cos:// 协议前缀，GCS 使用 tokenops:// 协议前缀
          example: cos://bucket.cos.ap-guangzhou.myqcloud.com/my_files/test.mp4
        visit_url:
          type: string
          description: 文件上传成功后的访问 URL
          example: https://bucket.cos.ap-guangzhou.myqcloud.com/my_files/test.mp4
    ErrorResponse:
      type: object
      properties:
        error:
          $ref: '#/components/schemas/Status'
          description: 错误信息
    Status:
      type: object
      properties:
        code:
          type: integer
          description: 错误代码
        message:
          type: string
          description: 错误消息
        details:
          type: array
          description: 错误详情
          items:
            type: object
            additionalProperties: true
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        API-Key 鉴权。所有 API 请求都应在 `Authorization` HTTP Header 中包含您的 API-Key，格式为
        `Bearer {API_KEY}`

````