創意工坊 — 鍵帽 API

把你的照片變成全彩客製機械鍵盤鍵帽。整個流程分兩段:prototype 用源照片 生成 1 張「成品鍵帽」設計效果圖,確認後 build 一條龍生成帶貼圖的 3D 鍵帽模型 —— 白模生成、按校準好的預設姿態自動落座與切割、整體上色、組裝導出 全部在一個 build 任務內完成。兩段通過 input_task_idcandidate_id 串聯。

  • POST /openapi/creative-lab/keycap/v1/prototype
  • POST /openapi/creative-lab/keycap/v1/build

POST/openapi/creative-lab/keycap/v1/prototype

建立鍵帽 Prototype 任務

從源照片生成 1 張成品鍵帽設計效果圖。任務結果攜帶 image_urls 陣列(成品鍵帽的展示渲染圖)以及與之平行的 candidate_ids 陣列,各含 1 項。 若效果不滿意,可再次呼叫本介面重新生成(每次呼叫單獨計費)。把圖片展示 給用戶挑選後,將對應的 candidate_id 與 prototype 任務 ID 一起傳給 build 端點。響應結構詳見 Prototype 任務物件

參數

  • Name
    image_url
    Type
    string
    必選
    Description

    提供給 Meshy 用於生成鍵帽設計圖的源照片。目前支援 .jpg.jpeg.png.webp 格式。

    格式由解碼圖片資料判定,不看 URL 的檔案副檔名 —— 沒有副檔名、或會發生轉址的 URL 都可以,只要位元組能解碼成受支援的格式。HTTP 轉址會被跟隨。EXIF 方向會被正規化,所以手機拍的旋轉照片會按看起來的方向使用。

    限制:每邊至少 32 像素、總像素不超過 178,956,970、下載後不超過 20,000,000 位元組。data URI 的上限按 base64 解碼後的位元組計算,所以源檔案本身可以達到該上限 —— 變大約三分之一的是 base64 文字,那影響的是請求體大小,不是這個上限。data URI 必須宣告 image/* 內容類型與 ;base64

    可通過兩種方式提供圖片:

    • 公網可存取 URL:可從公開網路存取的 URL。
    • Data URI:圖片的 base64 編碼 data URI,範例:data:image/jpeg;base64,<your base64-encoded image data>
  • Name
    name
    Type
    string
    Description

    選填的任務名稱,僅用於顯示。最長 100 個字元。

返回值

響應的 result 欄位返回新建立的鍵帽 prototype 任務的 id。輪詢 查詢任務 或訂閱 流式更新 直到任務狀態變為 SUCCEEDED,再從 candidate_ids 中選定一個候選, 連同任務 ID 一起傳給 build 端點

失敗情形

  • Name
    400 - Bad Request
    Description

    請求不可接受。常見原因:

    • 缺少參數image_url 為必填。
    • 圖片格式不支援image_url 不是受支援的格式(.jpg.jpeg.png.webp)。
    • 圖片尺寸超限:圖片過小、超出最大檔案體積或超出最大像素數。
    • URL 無法存取image_url 下載失敗(404 或逾時)。
    • Data URI 無效:base64 字串格式錯誤。
    • 內容被標記:輸入圖片被 NSFW 審核標記。
  • Name
    401 - Unauthorized
    Description

    鑑權失敗。請檢查你的 API key。

  • Name
    402 - Payment Required
    Description

    帳號處於免費方案(建立任務需要付費方案),或積分不足。

  • Name
    403 - Forbidden
    Description

    輸入圖片被智慧財產權審核標記。

  • Name
    429 - Too Many Requests
    Description

    超出速率限制。

  • Name
    500 - Internal Server Error
    Description

    伺服器端發生未預期的錯誤,例如內容審核服務不可用、輸入圖片暫存失敗,或任務建立失敗。此時不會建立任務,可安全重試。

Request

POST
/openapi/creative-lab/keycap/v1/prototype
# 第一段:生成 1 張成品鍵帽設計效果圖
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype \
  -X POST \
  -H "Authorization: Bearer ${YOUR_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
    "image_url": "<your publicly accessible image url or base64-encoded data URI>"
  }'

Response

{
  "result": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef"
}

POST/openapi/creative-lab/keycap/v1/build

建立鍵帽 Build 任務

從一個已成功的 prototype 任務及其選定候選生成最終的帶貼圖 3D 鍵帽模型。 單個 build 任務一條龍跑完整條流水線 —— 用選定設計圖生成白模、按校準好的 預設姿態自動落座並切割到鍵帽底座(無需互動調整)、整體上色、最終組裝導出。 一次 build 通常需要 3–7 分鐘,多個 build 並發時接近上限。響應結構詳見 Build 任務物件

參數

  • Name
    input_task_id
    Type
    string
    必選
    Description

    通過本 OpenAPI 端點建立的 prototype 任務 ID。該 prototype 必須由同一個 Meshy 帳號建立、已達到 SUCCEEDED 狀態,且至少產出一個候選。

    通過網頁版建立的 prototype 任務不被接受 —— build 端點只接受由 POST /openapi/creative-lab/keycap/v1/prototype 產出的 prototype 任務,其他來源一律返回 404

  • Name
    candidate_id
    Type
    string
    必選
    Description

    要構建的候選,取自已成功 prototype 任務的 candidate_ids 陣列。必須是該任務的候選之一,否則返回 400

  • Name
    name
    Type
    string
    Description

    選填的任務名稱,僅用於顯示。最長 100 個字元。

options

選填的幾何調節參數。每個欄位都有校準好的預設值 —— 只發送需要覆蓋的欄位即可。

  • Name
    base_model
    Type
    string
    預設值 cherry-mx-1x1-r1
    Description

    構建所用的鍵帽底座。目前唯一可用值為 cherry-mx-1x1-r1 —— 標準 Cherry MX 高度的 1u 鍵帽。後續計劃擴充 3–5 種主流標準尺寸;不支援自訂尺寸。

  • Name
    head_size_mm
    Type
    number
    預設值 23
    Description

    雕塑頭部的目標尺寸,單位毫米:頭部的最長邊會被縮放到該數值。範圍:[10, 40]。超過約 32.9 的取值可能會被下調,以確保頭部仍符合底座的保護性尺寸上限,因此實際交付的最長邊可能小於請求值。目前任務物件不會回傳實際採用的取值 —— 如需確認真正拿到的尺寸,請量下載模型裡 keycap-head 網格的邊界框。

  • Name
    vertical_offset_mm
    Type
    number
    預設值 0
    Description

    頭部落座到底座前施加的垂直偏移,單位毫米。範圍:[-5, 5]

返回值

響應的 result 欄位返回新建立的鍵帽 build 任務的 id。輪詢 查詢任務 或訂閱 流式更新 直到任務狀態變為 SUCCEEDED,再從 model_urls.glbmodel_urls.obj_zip 下載產物。

失敗情形

  • Name
    400 - Bad Request
    Description

    請求不可接受。常見原因:

    • 缺少參數input_task_idcandidate_id 為必填。
    • UUID 無效input_task_id 不是合法的 UUID。
    • 父任務未成功:引用的 prototype 任務尚未達到 SUCCEEDED
    • 沒有候選:prototype 任務雖成功但未產出候選。
    • 候選不存在candidate_id 不是該 prototype 任務的候選之一。
    • 參數超出範圍options 中某欄位超出允許範圍或列舉集合。
  • Name
    401 - Unauthorized
    Description

    鑑權失敗。請檢查你的 API key。

  • Name
    402 - Payment Required
    Description

    帳號處於免費方案(建立任務需要付費方案),或積分不足。

  • Name
    404 - Not Found
    Description

    引用的 prototype 任務不存在、屬於其他用戶,或由網頁版建立(只有 API 模式的 prototype 任務才能串聯 build)。

  • Name
    429 - Too Many Requests
    Description

    超出速率限制。

  • Name
    500 - Internal Server Error
    Description

    伺服器端發生未預期的錯誤,例如內容審核服務不可用、輸入圖片暫存失敗,或任務建立失敗。此時不會建立任務,可安全重試。

Request

POST
/openapi/creative-lab/keycap/v1/build
# 第二段:把選定候選構建成 3D 鍵帽
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/build \
  -X POST \
  -H "Authorization: Bearer ${YOUR_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
    "input_task_id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef",
    "candidate_id": "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b",
    "options": {
      "base_model": "cherry-mx-1x1-r1",
      "head_size_mm": 23,
      "vertical_offset_mm": 0
    }
  }'

Response

{
  "result": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af"
}

GET/openapi/creative-lab/keycap/v1/(prototype|build)/:id

查詢鍵帽任務

通過有效的任務 id 查詢 prototype 或 build 任務。URL 路徑必須與任務所屬 階段匹配 —— 通過 /prototype/:id 查詢 build 任務會返回 404,反之亦然。

響應結構詳見 Prototype 任務物件Build 任務物件

參數

  • Name
    id
    Type
    path
    Description

    要查詢的鍵帽任務的唯一識別碼。

返回值

響應包含鍵帽任務物件,具體結構取決於所查詢的階段。

Request

GET
/openapi/creative-lab/keycap/v1/prototype/019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef
# Prototype
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype/019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef \
  -H "Authorization: Bearer ${YOUR_API_KEY}"

# Build
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/build/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af \
  -H "Authorization: Bearer ${YOUR_API_KEY}"

Prototype Response

{
  "id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef",
  "type": "creative-lab-keycap-prototype",
  "name": "",
  "status": "SUCCEEDED",
  "progress": 100,
  "created_at": 1753142456000,
  "started_at": 1753142460000,
  "finished_at": 1753142516000,
  "expires_at": 1753401716000,
  "preceding_tasks": 0,
  "task_error": null,
  "consumed_credits": 12,
  "image_urls": [
    "https://assets.meshy.ai/***/design-1.png?Expires=***"
  ],
  "candidate_ids": [
    "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b"
  ]
}

Build Response

{
  "id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af",
  "type": "creative-lab-keycap-build",
  "name": "",
  "status": "SUCCEEDED",
  "progress": 100,
  "created_at": 1753142600000,
  "started_at": 1753142610000,
  "finished_at": 1753143050000,
  "expires_at": 1753402250000,
  "preceding_tasks": 0,
  "task_error": null,
  "consumed_credits": 50,
  "model_urls": {
    "glb": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model.glb?Expires=***",
    "obj_zip": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model-obj.zip?Expires=***"
  },
  "process_image_urls": {
    "head_design": "https://assets.meshy.ai/***/head-design.png?Expires=***",
    "composite": "https://assets.meshy.ai/***/composite.png?Expires=***",
    "base_canvas": "https://assets.meshy.ai/***/base-canvas.png?Expires=***"
  }
}

DELETE/openapi/creative-lab/keycap/v1/(prototype|build)/:id

刪除鍵帽任務

取消一個鍵帽任務。若任務仍處於 PENDING,建立時消耗的積分將退還;已進入 IN_PROGRESS 的任務會被取消但不退積分(worker 可能已經在消耗資源);已到達 終態(SUCCEEDEDFAILEDCANCELED)的任務無法取消。

URL 路徑必須與任務所屬階段匹配 —— 對 /prototype/:buildId 執行 DELETE 會返回 404

路徑參數

  • Name
    id
    Type
    path
    Description

    要取消的鍵帽任務的唯一識別碼。

返回值

成功時返回 204 No Content,響應體為空。

失敗情形

  • Name
    400 - Bad Request
    Description

    任務已處於終態,無法取消。

  • Name
    404 - Not Found
    Description

    任務不存在、屬於其他用戶,或所屬階段與 URL 路徑不匹配。

  • Name
    500 - Internal Server Error
    Description

    取消過程中伺服器端發生未預期的錯誤。任務可能已取消也可能未取消,重試前請重新讀取任務確認狀態。

Request

DELETE
/openapi/creative-lab/keycap/v1/prototype/019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef
curl --request DELETE \
  --url https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype/019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef \
  -H "Authorization: Bearer ${YOUR_API_KEY}"

Response

// 成功時返回 204 No Content(空響應體)。

GET/openapi/creative-lab/keycap/v1/(prototype|build)/:id/stream

流式訂閱鍵帽任務

通過 Server-Sent Events(SSE)即時訂閱鍵帽任務的狀態更新。URL 路徑必須與 任務所屬階段匹配 —— 在 /prototype/:buildId/stream 上開啟流會發出一條 event: errorstatus_code: 404)後關閉。

參數

  • Name
    id
    Type
    path
    Description

    要訂閱的鍵帽任務的唯一識別碼。

返回值

以 Server-Sent Events 形式返回 Prototype 任務物件Build 任務物件 的流。對 PENDINGIN_PROGRESS 的任務,流中只包含必要的 progressstatus 欄位。

Request

GET
/openapi/creative-lab/keycap/v1/build/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/stream
curl -N https://api.meshy.ai/openapi/creative-lab/keycap/v1/build/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/stream \
-H "Authorization: Bearer ${YOUR_API_KEY}"

Response Stream

// error 事件範例(階段不匹配或任務不存在)
event: error
data: {
  "status_code": 404,
  "message": "Task not found"
}

// message 事件範例(任務進度)。
// 對 PENDING 或 IN_PROGRESS 的任務,流中不會包含全部欄位。
event: message
data: {
  "id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af",
  "progress": 0,
  "status": "PENDING"
}

event: message
data: {
  "id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af",
  "type": "creative-lab-keycap-build",
  "status": "SUCCEEDED",
  "progress": 100,
  "created_at": 1753142600000,
  "started_at": 1753142610000,
  "finished_at": 1753143050000,
  "expires_at": 1753402250000,
  "task_error": null,
  "consumed_credits": 50,
  "model_urls": {
    "glb": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model.glb?Expires=***",
    "obj_zip": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model-obj.zip?Expires=***"
  },
  "process_image_urls": {
    "head_design": "https://assets.meshy.ai/***/head-design.png?Expires=***"
  }
}

GET/openapi/creative-lab/keycap/v1/(prototype|build)

列出鍵帽任務

分頁列出你在單一階段下的鍵帽任務。URL 路徑決定階段 —— /prototype 只返回 prototype 任務;/build 只返回 build 任務。兩個響應都不會包含另一階段的任務。

路徑參數

  • Name
    stage
    Type
    path
    必選
    Description

    prototypebuild。集合只返回與 URL 匹配階段的任務 —— 請求 /prototype 永遠不會返回 build 任務,反之亦然。

查詢參數

  • Name
    page_num
    Type
    integer
    預設值 1
    Description

    分頁頁碼。

  • Name
    page_size
    Type
    integer
    預設值 10
    Description

    每頁條數上限。最大允許 100 條。

  • Name
    sort_by
    Type
    string
    預設值 -created_at
    Description

    排序欄位。可用值:

    • +created_at:按建立時間升序。
    • -created_at:按建立時間降序。

返回值

返回對應階段任務物件的分頁列表 —— 列出 /prototype 時為 Prototype 任務物件,列出 /build 時為 Build 任務物件

Request

GET
/openapi/creative-lab/keycap/v1/prototype
# 列出 prototype 任務
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype?page_size=10 \
  -H "Authorization: Bearer ${YOUR_API_KEY}"

# 列出 build 任務
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/build?page_size=10 \
  -H "Authorization: Bearer ${YOUR_API_KEY}"

Response (List Prototype Tasks)

[
  {
    "id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef",
    "type": "creative-lab-keycap-prototype",
    "name": "",
    "status": "SUCCEEDED",
    "progress": 100,
    "created_at": 1753142456000,
    "started_at": 1753142460000,
    "finished_at": 1753142516000,
    "expires_at": 1753401716000,
    "preceding_tasks": 0,
    "task_error": null,
    "consumed_credits": 12,
    "image_urls": [
      "https://assets.meshy.ai/***/design-1.png?Expires=***"
    ],
    "candidate_ids": [
      "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b"
    ]
  }
]

Prototype 任務物件

鍵帽 Prototype 任務物件是 Meshy 追蹤的一個工作單元,用於從源照片生成 1 張 成品鍵帽設計效果圖。此階段的產出通過 input_task_idcandidate_id 串聯進 build 階段

屬性

  • Name
    id
    Type
    string
    Description

    任務的唯一識別碼。實作細節上我們使用 k-sortable UUID 作為任務 id,但你不應對 id 的格式做任何假設。

  • Name
    type
    Type
    string
    Description

    任務類型。取值為 creative-lab-keycap-prototype

  • Name
    name
    Type
    string
    Description

    建立任務時提供的任務名稱。未提供時為空字串。

  • Name
    status
    Type
    string
    Description

    任務狀態。取值為 PENDINGIN_PROGRESSSUCCEEDEDFAILEDCANCELED 之一。

  • Name
    progress
    Type
    integer
    Description

    任務進度。任務尚未開始時為 0;任務成功後為 100

  • Name
    created_at
    Type
    timestamp
    Description

    任務建立時間的時間戳,單位毫秒。

  • Name
    started_at
    Type
    timestamp
    Description

    任務開始時間的時間戳,單位毫秒。任務尚未開始時為 0

  • Name
    finished_at
    Type
    timestamp
    Description

    任務結束時間的時間戳,單位毫秒。任務尚未結束時為 0

  • Name
    expires_at
    Type
    timestamp
    Description

    任務結果過期時間的時間戳,單位毫秒。

  • Name
    preceding_tasks
    Type
    integer
    Description

    排在前面的任務數量。

  • Name
    task_error
    Type
    object
    Description

    失敗任務的錯誤詳情。完整的 task_error 物件參考見 Errors

  • Name
    consumed_credits
    Type
    integer
    Description

    此任務消耗的積分數。進入 SUCCEEDED 的任務按該階段全額計費。從未被建立的任務(請求時即回傳 4xx,包括內容審核拒絕)完全不計費。進入 FAILED 的任務回傳 0 —— 費用會退還,非同步的內容審核攔截也一樣。透過 DELETE 取消僅在任務仍為 PENDING 時退款;已進入 IN_PROGRESS 的任務不退款,因為算力已經花掉了。

  • Name
    image_urls
    Type
    array of strings
    Description

    成品鍵帽設計效果圖的下載 URL —— 展示該候選做成成品鍵帽後的效果。陣列僅含 1 項,image_urls[i] 對應 candidate_ids[i]。任務達到 SUCCEEDED 前為空陣列。該 URL 僅用於展示;build 端點消費的是 candidate_ids,而不是這些 URL。URL 生命週期與 model_urls 相同:簽名連結、不需要 Authorization 標頭、有效至 expires_at,重複讀取任務時保持不變。

  • Name
    candidate_ids
    Type
    array of strings
    Description

    image_urls 平行的不透明候選識別碼。把你選中設計對應的條目作為 build 請求的 candidate_id 傳入。不要對這些 id 的格式做任何假設。

Prototype 任務物件範例

{
  "id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef",
  "type": "creative-lab-keycap-prototype",
  "name": "",
  "status": "SUCCEEDED",
  "progress": 100,
  "created_at": 1753142456000,
  "started_at": 1753142460000,
  "finished_at": 1753142516000,
  "expires_at": 1753401716000,
  "preceding_tasks": 0,
  "task_error": null,
  "consumed_credits": 12,
  "image_urls": [
    "https://assets.meshy.ai/***/design-1.png?Expires=***"
  ],
  "candidate_ids": [
    "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b"
  ]
}

Build 任務物件

鍵帽 Build 任務物件是 Meshy 追蹤的一個工作單元,用於從已成功的 prototype 任務及選定候選生成最終的帶貼圖 3D 鍵帽。單個 build 一條龍跑完整條流水線 —— 白模生成、自動落座切割、上色、組裝、導出。

屬性

  • Name
    id
    Type
    string
    Description

    任務的唯一識別碼。

  • Name
    type
    Type
    string
    Description

    任務類型。取值為 creative-lab-keycap-build

  • Name
    name
    Type
    string
    Description

    建立任務時提供的任務名稱。未提供時為空字串。

  • Name
    status
    Type
    string
    Description

    任務狀態。取值為 PENDINGIN_PROGRESSSUCCEEDEDFAILEDCANCELED 之一。

  • Name
    progress
    Type
    integer
    Description

    任務進度。任務尚未開始時為 0;任務成功後為 100

  • Name
    created_at
    Type
    timestamp
    Description

    任務建立時間的時間戳,單位毫秒。

  • Name
    started_at
    Type
    timestamp
    Description

    任務開始時間的時間戳,單位毫秒。

  • Name
    finished_at
    Type
    timestamp
    Description

    任務結束時間的時間戳,單位毫秒。

  • Name
    expires_at
    Type
    timestamp
    Description

    任務結果過期時間的時間戳,單位毫秒。

  • Name
    preceding_tasks
    Type
    integer
    Description

    排在前面的任務數量。僅當狀態為 PENDING 時有意義。

  • Name
    task_error
    Type
    object
    Description

    失敗任務的錯誤詳情。完整的 task_error 物件參考見 Errors

  • Name
    consumed_credits
    Type
    integer
    Description

    此任務消耗的積分數。進入 SUCCEEDED 的任務按該階段全額計費。從未被建立的任務(請求時即回傳 4xx,包括內容審核拒絕)完全不計費。進入 FAILED 的任務回傳 0 —— 費用會退還,非同步的內容審核攔截也一樣。透過 DELETE 取消僅在任務仍為 PENDING 時退款;已進入 IN_PROGRESS 的任務不退款,因為算力已經花掉了。

  • Name
    model_urls
    Type
    object
    Description

    生成模型產物的下載 URL。GLB 與 OBJ 產物均按真實毫米尺度導出,座標系為 Y 軸向上,鍵帽正面朝向 +Z。網格命名為 keycap-headkeycap-base;當底座回退為圖案填充時,還會多出第三個網格 keycap-base-interior(軸孔內壁)。請勿假設固定為兩個網格。

    這些是簽名連結:請求時不要Authorization 標頭。它們在 expires_at 之前有效,也就是 finished_at 之後 3 天;在這個窗口內重複讀取任務會拿到完全相同的連結,而不是重新簽名的新連結。請在此之前自行下載並保存檔案 —— 過期的連結無法刷新。

    • Name
      glb
      Type
      string
      Description

      最終帶貼圖 model.glb 的下載 URL。

    • Name
      obj_zip
      Type
      string
      Description

      zip 包的下載 URL,內含 model.objmodel.mtl,以及 MTL 實際引用的貼圖 PNG。純色底座僅含 keycap-head.png;帶圖案的底座還會包含 keycap-base.png

  • Name
    process_image_urls
    Type
    object
    Description

    過程圖的下載 URL,按 kind 作為鍵。URL 生命週期與 model_urls 相同:簽名連結、不需要 Authorization 標頭、有效至 expires_at,重複讀取任務時保持不變。目前會出現的 kind:

    • head_design —— build 實際消費的選定候選設計圖(始終存在)。
    • composite —— 選定候選的成品鍵帽展示渲染圖(存在時返回)。
    • base_canvas —— 上色後的鍵帽底座畫布(存在時返回)。

    請把鍵集合視為開放集合;後續可能在不破壞相容的前提下新增 kind。

Build 任務物件範例

{
  "id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af",
  "type": "creative-lab-keycap-build",
  "name": "",
  "status": "SUCCEEDED",
  "progress": 100,
  "created_at": 1753142600000,
  "started_at": 1753142610000,
  "finished_at": 1753143050000,
  "expires_at": 1753402250000,
  "preceding_tasks": 0,
  "task_error": null,
  "consumed_credits": 50,
  "model_urls": {
    "glb": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model.glb?Expires=***",
    "obj_zip": "https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model-obj.zip?Expires=***"
  },
  "process_image_urls": {
    "head_design": "https://assets.meshy.ai/***/head-design.png?Expires=***",
    "composite": "https://assets.meshy.ai/***/composite.png?Expires=***",
    "base_canvas": "https://assets.meshy.ai/***/base-canvas.png?Expires=***"
  }
}

端到端完整範例

完整流程:用照片建立 prototype,輪詢到 SUCCEEDED,從 candidate_ids 中選定一個候選,用它建立 build,輪詢 build 到 SUCCEEDED,最後從 model_urls 下載 GLB 與 OBJ 包。

範例中程式化地選擇了第一個候選。實際接入時應把 image_urls 裡的那一項 展示給最終用戶挑選;選中的索引與 candidate_ids 一一對應。

Complete flow

POST
/openapi/creative-lab/keycap/v1
#!/usr/bin/env bash
set -euo pipefail

# 需要 curl 與 jq。把 IMAGE_PATH 指向本機照片,或把 IMAGE_URL 指向公網圖片:
#   export MESHY_API_KEY=msy_...
#   export IMAGE_PATH=./portrait.jpg          # or: export IMAGE_URL=https://...
: "${MESHY_API_KEY:?export MESHY_API_KEY first}"
if [[ -z "${IMAGE_PATH:-}" && -z "${IMAGE_URL:-}" ]]; then
  echo "export IMAGE_PATH (local file) or IMAGE_URL (public url) first" >&2
  exit 1
fi

BASE="https://api.meshy.ai/openapi/creative-lab/keycap/v1"
AUTH="Authorization: Bearer $MESHY_API_KEY"

# api METHOD URL [curl 參數...] -> 印出回應體,失敗時回傳非 0。
# 注意這裡不用 -f/--fail:它會把回應體丟掉,而原因只出現在回應體裡。
api() {
  local method=$1 url=$2 out http_code body
  shift 2
  out=$(curl --silent --show-error --max-time 60 --write-out $'\n%{http_code}' \
    -X "$method" "$url" -H "$AUTH" "$@") || return 1
  http_code=${out##*$'\n'}
  body=${out%$'\n'*}
  if ((http_code >= 400)); then
    echo "HTTP $http_code for $url: $body" >&2
    return 1
  fi
  printf '%s' "$body"
}

# 每個任務各有自己的 40 分鐘預算。
poll() {
  local kind=$1 id=$2 delay=5 task_status deadline
  deadline=$(($(date +%s) + 2400))
  while :; do
    if (($(date +%s) >= deadline)); then
      echo "gave up waiting for $kind $id" >&2
      return 1
    fi
    task_status=$(api GET "$BASE/$kind/$id" | jq -r '.status')
    echo "$kind: $task_status"
    case "$task_status" in
    SUCCEEDED) return 0 ;;
    FAILED | CANCELED) return 1 ;;
    esac
    sleep "$delay"
    delay=$((delay * 2 > 30 ? 30 : delay * 2))
  done
}

# 把請求體寫進檔案。base64 data URI 絕對不能出現在命令列或匯出的環境變數裡 ——
# 任何真實尺寸的照片都會超過作業系統的參數長度上限。
BODY=$(mktemp)
trap 'rm -f "$BODY"' EXIT
if [[ -n "${IMAGE_PATH:-}" ]]; then
  # 宣告真實型別:介面支援 JPEG、PNG、WebP。
  case "$(printf '%s' "${IMAGE_PATH##*.}" | tr 'A-Z' 'a-z')" in
    png) MIME=image/png ;;
    webp) MIME=image/webp ;;
    *) MIME=image/jpeg ;;
  esac
  {
    printf '{"image_url":"data:%s;base64,' "$MIME"
    base64 <"$IMAGE_PATH" | tr -d '\n'
    printf '"}'
  } >"$BODY"
else
  printf '{"image_url":"%s"}' "$IMAGE_URL" >"$BODY"
fi

# 1. 建立 prototype 任務
PROTO_ID=$(api POST "$BASE/prototype" \
  -H 'Content-Type: application/json' --data-binary @"$BODY" | jq -r '.result')

# 2. 等待設計效果圖
poll prototype "$PROTO_ID"

# 3. 選一個候選(這裡取第一個;生產環境應把 image_urls 展示給使用者選)
CANDIDATE_ID=$(api GET "$BASE/prototype/$PROTO_ID" | jq -r '.candidate_ids[0]')

# 4. 建立 build 任務
jq -n --arg p "$PROTO_ID" --arg c "$CANDIDATE_ID" \
  '{input_task_id: $p, candidate_id: $c}' >"$BODY"
BUILD_ID=$(api POST "$BASE/build" \
  -H 'Content-Type: application/json' --data-binary @"$BODY" | jq -r '.result')

# 5. 等待模型(build 通常需要 3-7 分鐘)
poll build "$BUILD_ID"

# 6. 下載產物。這些是簽名連結:不需要 Authorization 標頭,
#    任務完成後 3 天內有效。
TASK=$(api GET "$BASE/build/$BUILD_ID")
curl --silent --show-error --fail --max-time 900 \
  -o keycap.glb "$(jq -r '.model_urls.glb' <<<"$TASK")"
curl --silent --show-error --fail --max-time 900 \
  -o keycap-obj.zip "$(jq -r '.model_urls.obj_zip' <<<"$TASK")"
echo "Done: keycap.glb + keycap-obj.zip"