lowpoly 將於 2026年10月30日 下線。 請在這些日期前切換模型,以免請求出錯。 查看所有棄用資訊

Creative Lab 鍵帽 API

透過兩個階段,將一張照片變成機械鍵盤的全彩客製化鍵帽。原型任務根據照片產生成品鍵帽的圖像。構建任務會將該圖像轉換為帶紋理的 3D 鍵帽模型。它會將原型任務的 ID 作為 input_task_id,並將圖像的候選 ID 作為 candidate_id。

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

兩個 POST 端點都需要付費方案。免費方案帳戶發出的請求將返回 402。


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

建立 Keycap prototype 任務

根據一張照片生成一張成品鍵帽的圖像。任務的 image_urls 中儲存該圖像,candidate_ids 中儲存其 ID,二者各有一筆記錄。如果你不喜歡這個設計,可以再建立一個 prototype 任務。Meshy 會對每個 prototype 任務單獨收費。

要建構 3D 鍵帽,請將此任務的 ID 作為 input_task_id 傳給 build endpoint,並將 candidate_ids 中的那筆記錄作為 candidate_id 傳入。有關該任務各欄位的說明,請參閱Keycap prototype 任務物件。

Request

POST
/openapi/creative-lab/keycap/v1/prototype
# Stage 1: generate a finished-keycap design render
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"
}

參數

  • Name
    image_url
    Type
    string
    必選
    Description

    要轉換為鍵帽設計的照片,可以是公開可存取的 URL,或是一個 data URI(data:image/jpeg;base64,<your base64-encoded image data>)。

    圖片必須是 JPG、JPEG、PNG 或 WebP 檔案,且不超過 20 MB(20,000,000 位元組)。每條邊至少為 32 像素,圖片總像素數最多為 178,956,970。超出這些限制的圖片會回傳 400。

    Meshy 會根據圖像資料來偵測格式,而非依據 URL 中的副檔名。沒有副檔名的 URL 也可以正常運作,且 Meshy 會跟隨 HTTP 重新導向。Meshy 會套用 EXIF 方向資訊,因此旋轉過的手機照片會依照其實際顯示的方向呈現。

    data URI 必須使用 base64 編碼,並帶有圖像類型,例如 data:image/png;base64,...,且解碼後的圖像必須是 JPEG、PNG 或 WebP 格式。20 MB 的限制適用於解碼後的圖像,因此 base64 文字本身可能會大約再大三分之一。

  • Name
    name
    Type
    string
    Description

    任務的名稱,最多 100 個字元。該名稱會在任務的 name 欄位中回傳。超出長度限制會回傳 400。

  • Name
    remove_background
    Type
    boolean
    預設值 false
    Description

    是否從 prototype 圖像中移除背景。設為 true 會回傳一張透明的 RGBA PNG,這樣你就可以將鍵帽放置在任意背景之上。如果 Meshy 無法移除背景,它會回傳帶有原背景的圖像,任務仍然會成功。

    無論如何,build 階段用於生成 3D 效果的頭部設計都會保留其背景。build 階段會根據 image_urls 中的圖像來繪製鍵帽底座,如果你傳送了 true,則不帶其背景。build 階段會將該圖像以 process_image_urls.composite 的形式回傳。

回傳值

result 欄位儲存新建立的 prototype 任務的 ID。取得該任務或對其進行串流取得,直到 status 變為 SUCCEEDED。然後將該 ID 作為 input_task_id 傳給 build endpoint,並將 candidate_ids 中的那筆記錄作為 candidate_id 傳入。

失敗情形

  • Name
    400 - Bad Request
    Description

    請求無法執行。例如:

    • 缺少 image_url。
    • 圖像不是 JPG、JPEG、PNG 或 WebP 檔案。
    • 圖像過小、超過 20 MB,或超過最大像素數限制。
    • Meshy 無法下載該圖像,例如因為該 URL 回傳 404 或逾時。
    • data URI 不是有效的 base64 編碼。
    • 該圖像被標記為 NSFW(不適宜內容)。

    錯誤訊息會說明具體發現的問題。修正請求後再重新傳送。

  • Name
    401 - Unauthorized
    Description

    API 金鑰缺失或無效。請檢查 Authorization 請求標頭。

  • Name
    402 - Payment Required
    Description

    以下情況之一適用:

    • 帳戶的積分不足。
    • 該 API 金鑰、工作區或成員已達到其積分上限。
    • 該帳戶處於免費方案。

    請檢查你的積分和方案,然後重試。

  • Name
    403 - Forbidden
    Description

    你的團隊已開啟IP 過濾功能,且 Meshy 將該圖像標記為涉及第三方智慧財產權。請傳送你擁有使用權利的圖像。

  • Name
    429 - Too Many Requests
    Description

    已達到以下限制之一:

    • 你傳送的請求數超過了速率限制所允許的數量。請等待幾秒後重試。請參閱速率限制。
    • 排隊或正在執行的任務過多。請等待部分任務完成後再重試。
    • 在沒有剩餘積分的無限制方案下,你已達到可在無積分情況下執行的任務數量上限。請等待某個任務完成,或增加積分。
  • Name
    500 - Internal Server Error
    Description

    Meshy 遇到了伺服器錯誤,例如由於內容審核(moderation)或智慧財產權檢查未能執行,或 Meshy 無法儲存該圖像。Meshy 不會建立該任務,並會退還其已扣除的任何積分。請重試該請求。


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

創建 Keycap build 任務

根據一個成功的 prototype 任務及其候選項之一,生成帶貼圖的 3D keycap。相關欄位請參閱 Keycap build 任務物件。

一個 build 任務會執行每一個步驟。它先根據設計生成一個 3D 模型並為其上色,然後以經過校準的預設姿態將模型嵌入並裁切到 keycap 底座上,因此你無需手動調整。最後,它會組裝 keycap 並匯出檔案。一次 build 通常需要 3 到 7 分鐘。

Request

POST
/openapi/creative-lab/keycap/v1/build
# Stage 2: build the chosen candidate into a 3D keycap
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"
}

參數

  • Name
    input_task_id
    Type
    string
    必選
    Description

    要建構的 prototype 任務的 ID。它必須是你的帳戶透過 POST /openapi/creative-lab/keycap/v1/prototype 創建的任務,且狀態為 SUCCEEDED。

    如果 ID 不是你透過 API 創建的 Keycap prototype 任務之一,將返回 404,這也包括在網頁應用程式中創建的 prototype。

  • Name
    candidate_id
    Type
    string
    必選
    Description

    要建構的候選項,來自 prototype 任務的 candidate_ids 陣列。如果值不在該陣列中,將返回 400。

  • Name
    name
    Type
    string
    Description

    任務的名稱,最多 100 個字元。它會在任務的 name 欄位中返回。名稱過長將返回 400。

options

可選的 geometry 設定。每個欄位都有經過校準的預設值,因此只需傳送你想更改的欄位。

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

    用於建構的 keycap 底座。目前唯一可用的值是 cherry-mx-1x1-r1,即標準的 Cherry MX profile 1u keycap。不支援自訂尺寸,其他任何值都會返回 400。

  • Name
    head_size_mm
    Type
    number
    預設值 23
    Description

    頭部沿其最長維度的尺寸,單位為毫米,範圍為 10 到 40。Meshy 會縮放頭部,使其最長維度與該值匹配。超出範圍的值將返回 400。

    當值大於約 32.9 時,Meshy 可能會縮小尺寸,以使頭部符合底座的保護性占用面積限制。此時頭部生成的結果可能會比你要求的更小。任務物件不會返回 Meshy 實際套用的尺寸。要檢查該尺寸,請測量模型中 keycap-head mesh 的包圍盒。

  • Name
    vertical_offset_mm
    Type
    number
    預設值 0
    Description

    在 Meshy 將頭部嵌入底座之前對其施加的垂直偏移量,單位為毫米,範圍為 -5 到 5。超出範圍的值將返回 400。

回傳值

result 欄位保存新 build 任務的 ID。取得任務或對其進行串流傳輸,直到 status 為 SUCCEEDED。然後從 model_urls.glb 下載 GLB 檔案,並從 model_urls.obj_zip 下載 OBJ 壓縮包。

失敗模式

  • Name
    400 - Bad Request
    Description

    請求無法執行。例如:

    • input_task_id 缺失或不是有效的任務 ID。
    • prototype 任務的狀態不是 SUCCEEDED。如果仍在執行,請等待後重試。如果已失敗或被取消,請創建一個新的 prototype 任務。
    • prototype 任務成功了,但沒有候選項。請創建一個新的 prototype 任務。
    • candidate_id 缺失,或不在 prototype 任務的 candidate_ids 中。請從該陣列中傳送一個值。
    • options 中的某個欄位超出範圍,或 base_model 不是可用的值。

    錯誤訊息會說明發現的具體問題。

  • Name
    401 - Unauthorized
    Description

    API 金鑰缺失或無效。請檢查 Authorization 請求標頭。

  • Name
    402 - Payment Required
    Description

    以下情況之一適用:

    • 帳戶沒有足夠的積分。
    • 該 API 金鑰、工作區或成員已達到其積分限額。
    • 帳戶處於免費方案。

    請檢查你的積分和方案,然後重試。

  • Name
    404 - Not Found
    Description

    input_task_id 與你的帳戶透過 API 創建的任何 Keycap prototype 任務都不匹配。在網頁應用程式中創建的 prototype 同樣會返回 404。請傳送來自 prototype 創建回應中的 result ID。

  • Name
    429 - Too Many Requests
    Description

    達到以下限制之一:

    • 你傳送的請求數超過了速率限制所允許的數量。請等待幾秒後重試。參見速率限制。
    • 你排隊或正在執行的任務過多。請等待部分任務完成後重試。
    • 在沒有積分的無限制方案下,你達到了在沒有積分時可執行的任務數量上限。請等待某個任務完成,或增加積分。
  • Name
    500 - Internal Server Error
    Description

    由於伺服器錯誤,Meshy 無法創建任務。Meshy 會退還其已扣除的所有積分。請重試該請求。


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

取得 Keycap 任務

返回一個 prototype 或 build 任務。路徑必須與任務所處的階段相符。透過 /prototype/:id 請求 build 任務會回傳 404,透過 /build/:id 請求 prototype 任務同樣會回傳 404。

欄位說明請參閱 Keycap prototype 任務物件 和 Keycap build 任務物件。

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=***"
  }
}

參數

  • Name
    id
    Type
    path
    Description

    建立回應中返回的任務 ID。

回傳值

prototype 任務物件 或 build 任務物件,具體取決於路徑中指定的階段。

失敗情況

  • Name
    400 - Bad Request
    Description

    id 不是一個有效的任務 ID。請傳送建立回應中返回的 result ID。

  • Name
    403 - Forbidden
    Description

    你的團隊已開啟 IP Filtering,並且 Meshy 偵測到該 prototype 任務的圖片涉及第三方智慧財產權問題。Build 任務以及 Enterprise 方案團隊不會遇到此錯誤。請使用你擁有使用權的圖片來建立 prototype 任務。

  • Name
    404 - Not Found
    Description

    你的帳戶下沒有該 ID 對應的 Keycap 任務,或者該任務所處的階段與路徑不符。請檢查 ID,並使用 /prototype 或 /build 來對應正確的任務。

  • Name
    500 - Internal Server Error
    Description

    Meshy 無法執行智慧財產權檢查。請重試該請求。


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

刪除 Keycap 任務

取消一個 Keycap 任務。取消 PENDING 任務會退還其積分。IN_PROGRESS 任務被取消時不會退款,因為工作程序已經開始處理它。已處於最終狀態(SUCCEEDED、FAILED 或 CANCELED)的任務無法取消。

路徑必須與任務所處的階段相符。例如,用 build 任務的 ID 對 /prototype/:id 執行 DELETE 會回傳 404。

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

// Returns 204 No Content on success (empty body).

路徑參數

  • Name
    id
    Type
    path
    Description

    要取消的任務的 ID。

回傳值

204 No Content,回應內容為空。

失敗情況

  • Name
    400 - Bad Request
    Description

    以下情況之一適用:

    • id 不是有效的任務 ID。請傳送建立回應中的 result ID。
    • 該任務已處於最終狀態(SUCCEEDED、FAILED 或 CANCELED),因此無法取消。
  • Name
    404 - Not Found
    Description

    你的帳戶下不存在該 ID 對應的 Keycap 任務,或任務所處的階段與路徑不符。請檢查 ID,並使用 /prototype 或 /build 來符合該任務。

  • Name
    500 - Internal Server Error
    Description

    Meshy 在取消任務時遇到了伺服器錯誤,因此該任務可能已取消,也可能未取消。請先取得任務以檢查其 status,然後再重試。


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

串流取得 Keycap 任務

以伺服器發送事件(SSE)的形式,串流取得 Keycap 任務的更新。路徑必須與任務所處的階段匹配。如果不匹配,例如在 /prototype/:id/stream 中使用 build 任務的 ID,串流會發送一個 status_code: 404 的 error 事件,然後關閉連線。

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 example (wrong stage or task not found)
event: error
data: {
  "status_code": 404,
  "message": "Task not found"
}

// Message event examples illustrate task progress.
// Every frame is the full task object; fields not yet populated are null / empty.
// The following PENDING frame is shortened to the fields that change.
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=***"
  }
}

參數

  • Name
    id
    Type
    path
    Description

    建立回應中返回的任務 ID。

返回值

一個由原型或建置任務物件組成的串流。每個事件都包含完整的任務物件,格式與取得 Keycap 任務返回的一致。當任務處於 PENDING 或 IN_PROGRESS 狀態時,其輸出欄位仍為空(null、[] 或 {}),且 finished_at 為 null。

如果IP 過濾功能攔截了任務的結果,串流會在該處發送一個 error 事件,其中的 status_code 與 get 請求所返回的一致。


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

取得 Keycap 任務列表

返回某一階段的 Keycap 任務列表,每次返回一頁。路徑決定階段:/prototype 僅返回 prototype 任務,/build 僅返回 build 任務。

Request

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

# List build tasks
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"
    ]
  }
]

路徑參數

  • Name
    stage
    Type
    path
    必選
    Description

    要列出的階段,prototype 或 build。

查詢參數

  • Name
    page_num
    Type
    integer
    預設值 1
    Description

    要返回的頁碼,範圍從 1 到 255。0 返回第一頁。超出 0 到 255 的值將返回 400。

  • Name
    page_size
    Type
    integer
    預設值 10
    Description

    每頁返回的任務數量,最多 100。101 到 255 之間的值將返回 100 個任務,0 使用預設值。超出 0 到 255 的值將返回 400。

  • Name
    sort_by
    Type
    string
    預設值 -created_at
    Description

    排序方式。

    可用值:

    • -created_at:最新的排在最前
    • +created_at:最舊的排在最前

返回值

一個陣列,包含與路徑中階段相符的prototype 任務物件或build 任務物件。


Keycap prototype 任務物件

一個 prototype 任務會根據照片生成一張成品鍵帽的圖像。要將該設計轉為 3D 鍵帽,請將該任務的 ID 作為 input_task_id 傳給 build endpoint,並將其 candidate_ids 中的對應條目作為 candidate_id 傳入。

Properties

Example Keycap Prototype Task Object

{
  "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"
  ]
}
  • Name
    id
    Type
    string
    Description

    任務 ID。請勿依賴其具體格式。

  • Name
    type
    Type
    string
    Description

    任務類型,恆為 creative-lab-keycap-prototype。

  • Name
    name
    Type
    string
    Description

    你在建立任務時傳送的 name;如果沒有傳送,則為 ""。

  • Name
    status
    Type
    string
    Description

    任務的狀態。

    可用取值:

    • PENDING:在佇列中等待
    • IN_PROGRESS:正在生成結果
    • SUCCEEDED:最終狀態,已生成結果
    • FAILED:最終狀態,失敗原因見 task_error
    • CANCELED:最終狀態,沒有結果
  • Name
    progress
    Type
    integer
    Description

    已完成工作的百分比,範圍從 0 到 100。任務開始前為 0,成功後為 100。

  • Name
    created_at
    Type
    timestamp
    Description

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

  • Name
    started_at
    Type
    timestamp
    Description

    某個 worker 開始處理該任務的時間,單位為 Unix 毫秒。在此之前為 null。

  • Name
    finished_at
    Type
    timestamp
    Description

    任務到達最終狀態的時間,單位為 Unix 毫秒。在此之前為 null。

  • Name
    expires_at
    Type
    timestamp
    Description

    任務結果過期的時間,單位為 Unix 毫秒。該時間為 finished_at 之後 3 天;在任務完成之前,為 created_at 之後 3 天。對於可無限期保留 API 結果的 Enterprise 帳戶,該時間約為 100 年之後。另見資產保留期。

  • Name
    preceding_tasks
    Type
    integer
    Description

    任務處於 PENDING 狀態時在佇列中的位置。1 表示該任務將是下一個開始的任務。任務離開佇列後為 0,在列表結果中也始終為 0。

  • Name
    task_error
    Type
    object
    Description

    任務失敗的原因。除非 status 為 FAILED,否則為 null。另見 Errors。

  • Name
    consumed_credits
    Type
    integer
    Description

    該任務在扣除任何退款後實際收取的積分數量。回傳錯誤的請求不會被扣費。失敗的任務為 0,因為 Meshy 會對其進行退款。取消任務僅在其處於 PENDING 狀態時才會退款。如果 Meshy 無法讀取扣費資訊,get 或 stream 回應會省略該欄位,而 list 請求會回傳 500。在這種情況下,請重試該請求。

  • Name
    image_urls
    Type
    array of strings
    Description

    成品鍵帽圖像的下載 URL。任務成功後,該陣列包含一個 URL;在此之前為空陣列。image_urls[i] 展示的是 candidate_ids[i] 所對應的候選結果。

    這些 URL 僅用於展示。build endpoint 接收的是 candidate_ids 中的某個條目,而不是 URL。這些是簽名 URL,取得時無需攜帶 Authorization 請求標頭。它們在 expires_at 之前始終有效,並且再次取得該任務會回傳相同的 URL。

  • Name
    candidate_ids
    Type
    array of strings
    Description

    候選結果的 ID,順序與 image_urls 相同。要建構某個候選結果,請在 build 請求中將其 ID 作為 candidate_id 傳送。請勿依賴這些 ID 的具體格式。


鍵帽建構任務物件

建構任務會根據一個成功的原型任務及其候選項之一,產生帶紋理的 3D 鍵帽。它會產生 3D 模型、為其上色、將其嵌入並裁切到鍵帽底座上,然後組裝並匯出鍵帽。

屬性

Example Keycap Build Task Object

{
  "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=***"
  }
}
  • Name
    id
    Type
    string
    Description

    任務 ID。請勿依賴其格式。

  • Name
    type
    Type
    string
    Description

    任務類型,始終為 creative-lab-keycap-build。

  • Name
    name
    Type
    string
    Description

    你建立任務時傳送的 name,如果未傳送則為 ""。

  • Name
    status
    Type
    string
    Description

    任務的狀態。

    可用值:

    • PENDING:在佇列中等待
    • IN_PROGRESS:正在產生結果
    • SUCCEEDED:最終狀態,附帶結果
    • FAILED:最終狀態,原因見 task_error
    • CANCELED:最終狀態,無結果
  • Name
    progress
    Type
    integer
    Description

    已完成工作的百分比,從 0 到 100。任務開始前為 0,成功後為 100。

  • Name
    created_at
    Type
    timestamp
    Description

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

  • Name
    started_at
    Type
    timestamp
    Description

    工作程序開始處理任務的時間,單位為 Unix 毫秒。在此之前為 null。

  • Name
    finished_at
    Type
    timestamp
    Description

    任務達到最終狀態的時間,單位為 Unix 毫秒。在此之前為 null。

  • Name
    expires_at
    Type
    timestamp
    Description

    任務結果過期的時間,單位為 Unix 毫秒。該時間為 finished_at 之後 3 天,或在任務完成前為 created_at 之後 3 天。對於會無限期保留 API 結果的企業帳戶,該時間約為 100 年後。參見資產保留期。

  • Name
    preceding_tasks
    Type
    integer
    Description

    任務處於 PENDING 狀態時在佇列中的位置。1 表示該任務將是下一個開始執行的任務。任務離開佇列後為 0,在列表結果中始終為 0。

  • Name
    task_error
    Type
    object
    Description

    任務失敗的原因。除非 status 為 FAILED,否則為 null。參見錯誤。

  • Name
    consumed_credits
    Type
    integer
    Description

    該任務在退款後實際扣除的積分數量。回傳錯誤的請求不會被扣費。失敗的任務為 0,因為 Meshy 會退還費用。僅當任務處於 PENDING 狀態時取消才會退款。如果 Meshy 無法讀取扣費資訊,get 或 stream 回應會省略該欄位,而 list 請求會回傳 500。遇到這種情況,請重試該請求。

  • Name
    model_urls
    Type
    object
    Description

    3D 模型的下載 URL。Meshy 匯出的 GLB 檔案和 OBJ 包按真實世界比例(以毫米為單位)、Y 軸朝上,鍵帽正面朝向 +Z 方向。

    該模型包含名為 keycap-head 和 keycap-base 的網格。當 Meshy 回退為底座使用圖案填充時,模型還會包含一個用於軸芯凹腔的 keycap-base-interior 網格。請勿假設模型一定只有兩個網格。

    這些是簽名 URL,因此擷取時無需攜帶 Authorization 請求標頭。它們在 expires_at 之前保持有效,在此之前再次擷取該任務會回傳相同的 URL。過期的 URL 無法續期,因此請在到期前下載並儲存檔案。

    • Name
      glb
      Type
      string
      Description

      帶紋理的 GLB 檔案 model.glb 的下載 URL。

    • Name
      obj_zip
      Type
      string
      Description

      OBJ 包的下載 URL,這是一個包含 model.obj、model.mtl 以及 model.mtl 所使用的 PNG 紋理的 ZIP 檔案。如果底座為純色,唯一的紋理是 keycap-head.png。如果底座帶有圖案,該 ZIP 檔案還會包含 keycap-base.png。

  • Name
    process_image_urls
    Type
    object
    Description

    建構過程各步驟產生圖片的下載 URL,按類型進行鍵值索引。與 model_urls 一樣,它們也是簽名 URL,因此擷取時無需攜帶 Authorization 請求標頭。它們在 expires_at 之前保持有效,再次擷取該任務會回傳相同的 URL。

    它可能包含以下鍵:

    • head_design:所選候選項的設計圖像,建構任務據此產生 3D 內容。始終存在。
    • composite:所選候選項完成後的鍵帽圖像,底座正是根據它繪製而成。可能缺失。
    • base_canvas:繪製完成的鍵帽底座。可能缺失。

    Meshy 可能會新增鍵,因此遇到不認識的鍵請直接忽略。


端到端範例

此範例會執行整個流程:

  1. 根據照片建立一個 prototype 任務。
  2. 取得任務,直到其 status 為 SUCCEEDED。
  3. 從 candidate_ids 中選取一個候選項。
  4. 使用該候選項建立一個 build 任務。
  5. 取得 build 任務,直到其 status 為 SUCCEEDED。
  6. 從 model_urls 下載 GLB 檔案和 OBJ 壓縮檔。

此範例選擇了第一個候選項。在您的應用程式中,可以向使用者展示 image_urls 項目,讓他們自行選擇。所選圖片在 image_urls 中的索引,就是其 ID 在 candidate_ids 中的索引。

Complete flow

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

# Requires curl and jq. Point IMAGE_PATH at a local photo, or IMAGE_URL at a public one:
#   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 args...] -> prints the response body, non-zero on failure.
# Note we do not use -f/--fail: it discards the body, and the body is the only
# place the reason appears.
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"
}

# Each task gets its own 40-minute budget.
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
}

# Build the request body in a file. A base64 data URI must never go on the
# command line or into an exported variable - a photo of any real size will
# exceed the OS argument limit.
BODY=$(mktemp)
trap 'rm -f "$BODY"' EXIT
if [[ -n "${IMAGE_PATH:-}" ]]; then
  # Declare the real type: the API accepts JPEG, PNG and 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. Create the prototype task
PROTO_ID=$(api POST "$BASE/prototype" \
  -H 'Content-Type: application/json' --data-binary @"$BODY" | jq -r '.result')

# 2. Wait for the design render
poll prototype "$PROTO_ID"

# 3. Pick a candidate (first one here; show image_urls to a user in production)
CANDIDATE_ID=$(api GET "$BASE/prototype/$PROTO_ID" | jq -r '.candidate_ids[0]')

# 4. Create the build task
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. Wait for the model (a build usually takes 3-7 minutes)
poll build "$BUILD_ID"

# 6. Download the artifacts. These are signed URLs: no Authorization header,
#    and they stay valid for 3 days after the task finishes.
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"