Creative Lab — Keycap API

แปลงภาพถ่ายต้นฉบับให้เป็นแป้นพิมพ์คีย์แคปแบบสีเต็มรูปแบบสำหรับคีย์บอร์ดแบบกลไก ใน 2 ขั้นตอน: prototype จะสร้างภาพเรนเดอร์การออกแบบ "คีย์แคปที่เสร็จสมบูรณ์" จากภาพถ่ายที่คุณนำเข้ามา เมื่อคุณยืนยันภาพเรนเดอร์นั้นแล้ว build จะแปลงให้เป็น โมเดลคีย์แคป 3 มิติที่มีเทกซ์เจอร์ในการรันเพียงครั้งเดียว — การสร้างโมเดลสีขาว การจัดวางและ การตัดอัตโนมัติบนท่าทางเริ่มต้นที่ผ่านการปรับเทียบแล้ว การลงสีทั้งโมเดล และ การประกอบขั้นสุดท้ายทั้งหมดเกิดขึ้นภายในงานสร้างโมเดลเดียว ทั้งสองขั้นตอนเชื่อมโยงกัน ผ่าน input_task_id และ candidate_id

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

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

สร้าง Keycap Prototype Task

สร้างภาพ render ของดีไซน์ keycap ที่เสร็จสมบูรณ์จากภาพถ่ายต้นฉบับ ผลลัพธ์ของ task จะมี array image_urls (ภาพ render สำหรับแสดงผลของ keycap ที่เสร็จสมบูรณ์) และ array candidate_ids ที่คู่กัน โดยทั้งสอง array จะมีรายการเดียว เรียก endpoint นี้อีกครั้งเพื่อขอ render อื่นหากผลลัพธ์ยังไม่ตรงกับที่ต้องการ — แต่ละการเรียกจะถูกเรียกเก็บเงินแยกกัน ส่ง candidate_id พร้อมกับ prototype task ID ไปยัง build endpoint ดูรูปแบบของ response ได้ที่ The Keycap Prototype Task Object

พารามิเตอร์

  • Name
    image_url
    Type
    string
    จำเป็น
    Description

    ภาพถ่ายต้นฉบับที่ให้ Meshy แปลงเป็นภาพดีไซน์ keycap ปัจจุบันเรารองรับรูปแบบ .jpg, .jpeg, .png, และ .webp

    รูปแบบไฟล์จะถูกตรวจสอบจากการถอดรหัสข้อมูลภาพ ไม่ใช่ จากนามสกุลไฟล์ใน URL — URL ที่ไม่มีนามสกุล หรือ URL ที่มีการ redirect ก็ใช้งานได้ตราบใดที่ไบต์สามารถถอดรหัสเป็นรูปแบบที่รองรับ ระบบจะติดตาม HTTP redirect ให้ ทิศทางของภาพ (EXIF orientation) จะถูกปรับให้เป็นปกติ ดังนั้นภาพถ่ายจากโทรศัพท์ที่หมุนไว้จะถูกใช้งานตามที่แสดงผลจริง

    ข้อจำกัด: ด้านแต่ละด้านอย่างน้อย 32 พิกเซล รวมทั้งหมดไม่เกิน 178,956,970 พิกเซล และไม่เกิน 20,000,000 ไบต์เมื่อดาวน์โหลดแล้ว สำหรับ Data URI ข้อจำกัดจะใช้กับไบต์ที่ถอดรหัสแล้ว ดังนั้นไฟล์ต้นฉบับเองอาจมีขนาดได้ถึงขนาดนั้น — เป็นข้อความ base64 ที่มีขนาดใหญ่กว่าประมาณหนึ่งในสาม ซึ่งมีผลต่อ request body ของคุณ ไม่ใช่ต่อข้อจำกัดนี้ Data URI ต้องระบุ content type เป็น image/* และ ;base64

    มีสองวิธีในการระบุภาพ:

    • URL ที่เข้าถึงได้แบบสาธารณะ: URL ที่สามารถเข้าถึงได้จากอินเทอร์เน็ตสาธารณะ
    • Data URI: Data URI ของภาพที่เข้ารหัสแบบ base64 ตัวอย่างของ Data URI: data:image/jpeg;base64,<your base64-encoded image data>
  • Name
    name
    Type
    string
    Description

    ชื่อ task ที่ไม่บังคับสำหรับการแสดงผล สูงสุด 100 ตัวอักษร

  • Name
    remove_background
    Type
    boolean
    ค่าเริ่มต้น false
    Description

    เมื่อตั้งค่าเป็น true ภาพ render สำหรับแสดงผลที่ส่งกลับใน image_urls จะเป็น PNG แบบ RGBA โปร่งใสที่ลบพื้นหลังออกแล้ว ทำให้คุณสามารถนำไปประกอบกับพื้นหลังใดก็ได้

    ผลนี้จะมีผลกับภาพ render สำหรับแสดงผลเท่านั้น candidate ที่ build endpoint ใช้จะไม่ได้รับผลกระทบ ดังนั้นผลลัพธ์ 3D จะเหมือนกันไม่ว่าจะเลือกค่าใด

ผลลัพธ์ที่ได้รับ

พร็อพเพอร์ตี้ result ของ response จะมี id ของ keycap prototype task ที่สร้างขึ้นใหม่ ให้ทำการ poll ที่ endpoint Get a Task หรือ subscribe ที่ stream จนกว่า task จะมีสถานะ SUCCEEDED จากนั้นนำรายการจาก candidate_ids พร้อมกับ task ID ไปส่งยัง build endpoint

รูปแบบความล้มเหลว

  • Name
    400 - Bad Request
    Description

    คำขอไม่สามารถยอมรับได้ สาเหตุที่พบบ่อย:

    • ขาดพารามิเตอร์: ต้องระบุ image_url
    • รูปแบบภาพไม่ถูกต้อง: image_url ที่ระบุไม่ใช่รูปแบบที่รองรับ (.jpg, .jpeg, .png, .webp)
    • ขนาดภาพอยู่นอกช่วงที่กำหนด: ภาพมีขนาดเล็กเกินไป เกินขนาดไฟล์สูงสุด หรือเกินจำนวนพิกเซลสูงสุด
    • URL ไม่สามารถเข้าถึงได้: ไม่สามารถดาวน์โหลด image_url ได้ (404 หรือ timeout)
    • Data URI ไม่ถูกต้อง: สตริง base64 มีรูปแบบผิดพลาด
    • เนื้อหาถูกตั้งค่าสถานะ: ภาพที่ป้อนเข้ามาถูกตั้งค่าสถานะโดยระบบ moderation เนื้อหา NSFW
  • Name
    401 - Unauthorized
    Description

    การยืนยันตัวตนล้มเหลว โปรดตรวจสอบ API คีย์ของคุณ

  • Name
    402 - Payment Required
    Description

    บัญชีนี้อยู่ในแพ็กเกจฟรี (ต้องใช้แพ็กเกจแบบชำระเงินเพื่อสร้าง task) หรือมีเครดิตไม่เพียงพอ

  • Name
    403 - Forbidden
    Description

    ภาพที่ป้อนเข้ามาถูกตั้งค่าสถานะโดยระบบ moderation ด้านทรัพย์สินทางปัญญา

  • Name
    429 - Too Many Requests
    Description

    คุณส่งคำขอเกินการจำกัดอัตราที่กำหนดไว้

  • Name
    500 - Internal Server Error
    Description

    เกิดข้อผิดพลาดที่ไม่คาดคิดฝั่งเซิร์ฟเวอร์ — ตัวอย่างเช่น บริการ moderation เนื้อหาไม่พร้อมใช้งาน การเตรียมภาพที่ป้อนเข้ามาล้มเหลว หรือไม่สามารถสร้าง task ได้ ในกรณีนี้จะไม่มีการสร้าง task ขึ้น ดังนั้นการลองใหม่จึงปลอดภัย

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

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

Create a Keycap Build Task

สร้างโมเดล keycap 3D ที่มีพื้นผิวสมบูรณ์จาก prototype task ที่สำเร็จแล้วและหนึ่งใน candidate ของมัน build task เดียวจะรันทั้งไปป์ไลน์แบบ end to end — การสร้าง white-model จากดีไซน์ที่เลือก, การจัดวางและตัดอัตโนมัติลงบน keycap base โดยใช้ท่าทางค่าเริ่มต้นที่ได้รับการปรับเทียบไว้ (ไม่ต้องปรับแต่งแบบโต้ตอบ), การลงสีทั้งโมเดล และการประกอบและส่งออกขั้นสุดท้าย โดยทั่วไป build จะใช้เวลา 3–7 นาที โดยจะเข้าใกล้ช่วงเวลาสูงสุดเมื่อมี build หลายรายการทำงานพร้อมกัน ดูรูปแบบของการตอบกลับได้ที่ The Keycap Build Task Object

พารามิเตอร์

  • Name
    input_task_id
    Type
    string
    จำเป็น
    Description

    รหัสของ task ของ prototype ที่สร้างขึ้นผ่านเอนด์พอยต์ OpenAPI เดียวกันนี้ prototype นี้ต้องถูกสร้างโดยบัญชี Meshy เดียวกัน ต้องมีสถานะถึง SUCCEEDED แล้ว และต้องสร้าง candidate อย่างน้อยหนึ่งรายการ

    prototype task ที่สร้างผ่าน webapp จะไม่ ได้รับการยอมรับ — เอนด์พอยต์ build จะยอมรับเฉพาะ prototype task ที่สร้างจาก POST /openapi/creative-lab/keycap/v1/prototype เท่านั้น และจะปฏิเสธแหล่งที่มาอื่นใดด้วย 404

  • Name
    candidate_id
    Type
    string
    จำเป็น
    Description

    candidate ที่จะนำมา build โดยนำมาจากอาร์เรย์ candidate_ids ของ prototype task ที่สำเร็จแล้ว ต้องเป็นของ task นั้นเท่านั้น ค่าอื่นใดจะถูกปฏิเสธด้วย 400

  • Name
    name
    Type
    string
    Description

    ชื่อ task ที่ไม่บังคับสำหรับใช้แสดงผล สูงสุด 100 ตัวอักษร

options

การปรับแต่งจีออเมทรีที่ไม่บังคับ ทุกฟิลด์มีค่าเริ่มต้นที่ได้รับการปรับเทียบไว้แล้ว — ให้ส่งเฉพาะฟิลด์ที่ต้องการเปลี่ยนแปลงเท่านั้น

  • Name
    base_model
    Type
    string
    ค่าเริ่มต้น cherry-mx-1x1-r1
    Description

    keycap base ที่จะนำมา build ปัจจุบันมีค่าเดียวที่ใช้ได้คือ cherry-mx-1x1-r1 — keycap 1u โปรไฟล์ Cherry MX มาตรฐาน มีแผนจะเพิ่มขนาดมาตรฐานที่ใช้ทั่วไปอีก 3–5 ขนาด ส่วนขนาดที่กำหนดเองยังไม่รองรับ

  • Name
    head_size_mm
    Type
    number
    ค่าเริ่มต้น 23
    Description

    ขนาดเป้าหมายของหัวที่ปั้นขึ้น หน่วยเป็นมิลลิเมตร: มิติที่ยาวที่สุดจะถูกปรับสเกลให้ตรงกับค่านี้ ช่วงค่า: [10, 40] ค่าที่สูงกว่าประมาณ 32.9 อาจถูกลดลงเพื่อให้หัวยังคงพอดีกับขีดจำกัดพื้นที่ป้องกันของฐาน ดังนั้นมิติที่ยาวที่สุดที่ได้จริงอาจเล็กกว่าค่าที่ร้องขอ ค่าที่นำไปใช้จริงในปัจจุบันยังไม่ถูกส่งกลับมาใน task object — หากต้องการยืนยันขนาดที่ได้รับจริง ให้วัดกล่องขอบเขตของเมช keycap-head ในโมเดลที่ดาวน์โหลดมา

  • Name
    vertical_offset_mm
    Type
    number
    ค่าเริ่มต้น 0
    Description

    ค่าออฟเซ็ตแนวตั้งที่นำไปใช้กับหัวก่อนจะนำไปวางบนฐาน หน่วยเป็นมิลลิเมตร ช่วงค่า: [-5, 5]

ค่าที่ส่งกลับ

พร็อพเพอร์ตี้ result ของการตอบกลับจะมี id ของ task การ build keycap ที่สร้างขึ้นใหม่ ให้ทำการ poll เอนด์พอยต์ Get a Task หรือ subscribe ไปที่ stream จนกว่า task จะมีสถานะเป็น SUCCEEDED จากนั้นจึงดาวน์โหลด artifact จาก model_urls.glb และ model_urls.obj_zip

รูปแบบความล้มเหลว

  • Name
    400 - Bad Request
    Description

    คำขอไม่สามารถยอมรับได้ สาเหตุทั่วไป:

    • ขาดพารามิเตอร์: ต้องมี input_task_id และ candidate_id
    • UUID ไม่ถูกต้อง: input_task_id ไม่ใช่ UUID ที่ถูกต้อง
    • task ต้นทางยังไม่สำเร็จ: prototype task ที่อ้างอิงยังไม่มีสถานะถึง SUCCEEDED
    • ไม่มี candidate: prototype task สำเร็จแล้วแต่ไม่ได้สร้าง candidate ใดๆ
    • candidate ไม่รู้จัก: candidate_id ไม่ใช่หนึ่งใน candidate ของ input task นั้น
    • options เกินขอบเขต: หนึ่งในฟิลด์ของ options มีค่าอยู่นอกช่วงหรือชุดค่า enum ที่อนุญาต
  • Name
    401 - Unauthorized
    Description

    การยืนยันตัวตนล้มเหลว โปรดตรวจสอบ API คีย์ของคุณ

  • Name
    402 - Payment Required
    Description

    บัญชีนี้อยู่ในแพ็กเกจฟรี (จำเป็นต้องมีแพ็กเกจแบบชำระเงินเพื่อสร้าง task) หรือมีเครดิตไม่เพียงพอ

  • Name
    404 - Not Found
    Description

    prototype task ที่อ้างอิงไม่มีอยู่ เป็นของผู้ใช้รายอื่น หรือถูกสร้างผ่าน webapp (มีเพียง prototype task ในโหมด API เท่านั้นที่สามารถต่อยอดไปเป็น build ได้)

  • Name
    429 - Too Many Requests
    Description

    คุณได้เกินการจำกัดอัตราของคุณแล้ว

  • Name
    500 - Internal Server Error
    Description

    เกิดข้อผิดพลาดที่ไม่คาดคิดฝั่งเซิร์ฟเวอร์ — ตัวอย่างเช่น บริการ content-moderation ไม่พร้อมใช้งาน การเตรียมภาพอินพุตล้มเหลว หรือไม่สามารถสร้าง task ได้ ในกรณีนี้จะไม่มีการสร้าง task ใดๆ ดังนั้นสามารถลองใหม่ได้อย่างปลอดภัย

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

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

Retrieve a Keycap Task

ดึงข้อมูลงาน prototype หรือ build โดยระบุ task id ที่ถูกต้อง URL path ต้องตรงกับขั้นตอนของงาน — หากงาน build ถูกเรียกผ่าน /prototype/:id จะได้รับ 404 และในทางกลับกันก็เช่นกัน

ดูรูปแบบการตอบกลับได้ที่ The Keycap Prototype Task Object และ The Keycap Build Task Object

พารามิเตอร์

  • Name
    id
    Type
    path
    Description

    ตัวระบุที่ไม่ซ้ำกันสำหรับงาน keycap ที่ต้องการดึงข้อมูล

ค่าที่ส่งกลับ

การตอบกลับจะประกอบด้วยอ็อบเจ็กต์งาน keycap รูปแบบขึ้นอยู่กับ ขั้นตอนที่ร้องขอ

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

ลบงาน Keycap

ยกเลิกงาน keycap หากงานยังอยู่ในสถานะ PENDING เครดิตที่ถูกใช้ไป ในขณะสร้างงานจะถูกคืนกลับ งานที่อยู่ในสถานะ IN_PROGRESS แล้วจะถูกยกเลิกโดยไม่มีการคืนเครดิต (เนื่องจาก worker อาจกำลังใช้ แหล่งข้อมูลอยู่แล้ว) งานที่ไปถึงสถานะสุดท้ายแล้ว (SUCCEEDED, FAILED, CANCELED) จะไม่สามารถยกเลิกได้

เส้นทาง URL ต้องตรงกับขั้นตอน (stage) ของงานนั้น ๆ — การเรียก DELETE ที่ /prototype/:buildId จะคืนค่า 404

พารามิเตอร์เส้นทาง (Path Parameters)

  • Name
    id
    Type
    path
    Description

    รหัสเฉพาะของงาน keycap ที่ต้องการยกเลิก

ผลลัพธ์ที่ได้รับ

คืนค่า 204 No Content เมื่อสำเร็จ พร้อม body ที่ว่างเปล่า

รูปแบบความล้มเหลว

  • 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

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

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

สตรีมข้อมูลงาน Keycap Task

สตรีมข้อมูลอัปเดตแบบเรียลไทม์สำหรับงาน keycap ผ่าน Server-Sent Events (SSE) เส้นทาง URL ต้องตรงกับขั้นตอนของงาน — การเปิดสตรีมที่ /prototype/:buildId/stream จะส่งเพย์โหลด event: error เพียงรายการเดียวที่มี status_code: 404 แล้วปิดสตรีม

พารามิเตอร์

  • Name
    id
    Type
    path
    Description

    ตัวระบุเฉพาะสำหรับงาน keycap ที่ต้องการสตรีม

ค่าที่ส่งกลับ

ส่งกลับสตรีมของอ็อบเจ็กต์งาน Keycap Prototype หรือ Keycap Build ในรูปแบบ Server-Sent Events แต่ละเฟรมจะมีอ็อบเจ็กต์งานฉบับสมบูรณ์ของขั้นตอนนั้น ๆ — ในรูปแบบเดียวกับที่ เอนด์พอยต์ Get ส่งกลับ — ดังนั้นในขณะที่งานยังอยู่ในสถานะ PENDING หรือ IN_PROGRESS ฟิลด์ผลลัพธ์ต่าง ๆ จะยังไม่ถูกกำหนดค่า (null, [] หรือ {}) และ finished_at จะเป็น null

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 PENDING frame below is abbreviated 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=***"
  }
}

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

List Keycap Tasks

ดึงรายการงาน keycap ของคุณแบบแบ่งหน้าสำหรับสเตจเดียว พาธ URL จะเป็นตัวเลือกสเตจ — /prototype จะส่งคืนงานต้นแบบ (prototype); /build จะส่งคืนงานสร้าง (build) งานจากอีกสเตจหนึ่งจะไม่ถูกรวมอยู่ในการตอบกลับ ใด ๆ ทั้งสองแบบ

Path Parameters

  • Name
    stage
    Type
    path
    จำเป็น
    Description

    เป็นได้ทั้ง prototype หรือ build คอลเลกชันจะส่งคืนเฉพาะงาน ที่มีสเตจตรงกับ URL — การเรียก /prototype จะไม่ส่งคืนงาน build เลย และในทางกลับกันก็เช่นกัน

Query Parameters

  • 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: เรียงตามเวลาที่สร้างจากมากไปน้อย

Returns

ส่งคืนรายการแบบแบ่งหน้าของอ็อบเจ็กต์งานเฉพาะสเตจ — อาจเป็น อ็อบเจ็กต์งานต้นแบบ keycap เมื่อดึงรายการจาก /prototype หรือ อ็อบเจ็กต์งานสร้าง keycap เมื่อ ดึงรายการจาก /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"
    ]
  }
]

The Keycap Prototype Task Object

Keycap Prototype Task object คือหน่วยงานที่ Meshy คอยติดตามเพื่อสร้าง รูปภาพดีไซน์คีย์แคปฉบับสมบูรณ์ หนึ่งภาพจากภาพถ่ายต้นฉบับ ผลลัพธ์ของขั้นตอนนี้จะถูกส่งต่อไปยัง ขั้นตอนการ build ผ่านทาง input_task_id ร่วมกับ candidate_id

พร็อพเพอร์ตี้

  • Name
    id
    Type
    string
    Description

    ตัวระบุที่ไม่ซ้ำกันสำหรับ task แม้ว่าในทางปฏิบัติเราจะใช้ k-sortable UUID เป็น task id แต่คุณไม่ควรตั้งสมมติฐานใดๆ เกี่ยวกับรูปแบบของ id นี้

  • Name
    type
    Type
    string
    Description

    ประเภทของ task ค่านี้คือ creative-lab-keycap-prototype

  • Name
    name
    Type
    string
    Description

    ชื่อ task ที่ระบุไว้ตอนสร้าง task เป็นสตริงว่างหากไม่ได้ระบุชื่อไว้

  • Name
    status
    Type
    string
    Description

    สถานะของ task ค่าที่เป็นไปได้คือ PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED

  • Name
    progress
    Type
    integer
    Description

    progress ของ task หาก task ยังไม่ได้เริ่ม พร็อพเพอร์ตี้นี้จะเป็น 0 เมื่อ task สำเร็จแล้ว ค่านี้จะกลายเป็น 100

  • Name
    created_at
    Type
    timestamp
    Description

    ไทม์สแตมป์ของเวลาที่สร้าง task หน่วยเป็นมิลลิวินาที

  • Name
    started_at
    Type
    timestamp
    Description

    ไทม์สแตมป์ของเวลาที่ task เริ่มทำงาน หน่วยเป็นมิลลิวินาที หาก task ยังไม่ได้เริ่ม พร็อพเพอร์ตี้นี้จะเป็น 0

  • Name
    finished_at
    Type
    timestamp
    Description

    ไทม์สแตมป์ของเวลาที่ task เสร็จสิ้น หน่วยเป็นมิลลิวินาที หาก task ยังไม่เสร็จสิ้น พร็อพเพอร์ตี้นี้จะเป็น 0

  • Name
    expires_at
    Type
    timestamp
    Description

    ไทม์สแตมป์ของเวลาที่ผลลัพธ์ของ task จะหมดอายุ หน่วยเป็นมิลลิวินาที

  • Name
    preceding_tasks
    Type
    integer
    Description

    จำนวนของ task ที่อยู่ก่อนหน้า

  • Name
    task_error
    Type
    object
    Description

    รายละเอียดข้อผิดพลาดสำหรับ task ที่ล้มเหลว ดู ข้อผิดพลาด สำหรับข้อมูลอ้างอิงฉบับสมบูรณ์ของอ็อบเจ็กต์ task_error

  • Name
    consumed_credits
    Type
    integer
    Description

    จำนวนเครดิตที่ถูกใช้ไปโดย task นี้ task ที่มีสถานะถึง SUCCEEDED จะถูกเรียกเก็บเครดิตเต็มจำนวนสำหรับขั้นตอนนั้น ส่วน task ที่ไม่เคยถูกสร้างขึ้นเลย (เกิด 4xx ตอนที่ส่งคำขอ รวมถึงกรณีถูกปฏิเสธจาก moderation) จะไม่ถูกเรียกเก็บเครดิตเลย task ที่มีสถานะถึง FAILED จะคืนค่าเป็น 0 — เครดิตที่ถูกเรียกเก็บจะถูกคืนกลับ รวมถึงกรณีถูกบล็อกโดย moderation แบบ asynchronous การยกเลิกผ่าน DELETE จะคืนเครดิตให้ก็ต่อเมื่อ task ยังอยู่ในสถานะ PENDING เท่านั้น ส่วน task ที่เป็น IN_PROGRESS อยู่แล้วจะยังคงถูกเรียกเก็บเครดิต เนื่องจากงานได้ถูกใช้ไปแล้ว

  • Name
    image_urls
    Type
    array of strings
    Description

    URL สำหรับดาวน์โหลดภาพเรนเดอร์ดีไซน์คีย์แคปฉบับสมบูรณ์ — ลักษณะที่แคนดิเดตจะปรากฏเมื่อกลายเป็นคีย์แคปฉบับสมบูรณ์ มีเพียงหนึ่งรายการเท่านั้น โดย image_urls[i] จะสอดคล้องกับ candidate_ids[i] ค่านี้จะว่างเปล่าจนกว่า task จะมีสถานะเป็น SUCCEEDED URL นี้มีไว้สำหรับการแสดงผลเท่านั้น เอนด์พอยต์สำหรับ build จะใช้ candidate_ids ไม่ใช่ URL เหล่านี้ วงจรชีวิตของ URL เหมือนกับ model_urls คือ: มีการลงนาม ไม่ต้องใช้ header Authorization ใช้ได้จนถึง expires_at และคงที่เมื่ออ่าน task ซ้ำ

  • Name
    candidate_ids
    Type
    array of strings
    Description

    ตัวระบุแคนดิเดตแบบทึบ (opaque) ที่สอดคล้องกับ image_urls ให้ส่งรายการที่ตรงกับดีไซน์ที่คุณเลือกเป็น candidate_id ในคำขอ build ห้ามตั้งสมมติฐานใดๆ เกี่ยวกับรูปแบบของ id เหล่านี้

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"
  ]
}

The Keycap Build Task Object

Keycap Build Task object เป็นหน่วยงานที่ Meshy ใช้ติดตามการสร้างคีย์แคป 3D ที่มีเท็กซ์เจอร์สมบูรณ์จาก prototype task ที่สำเร็จแล้วและ candidate ที่เลือกไว้ การ build หนึ่งครั้งจะรัน pipeline ทั้งหมด ได้แก่ การสร้าง white-model, การจัดวางและตัดอัตโนมัติ, การลงสี, การประกอบ และการส่งออก

Properties

  • Name
    id
    Type
    string
    Description

    ตัวระบุที่ไม่ซ้ำกันสำหรับ task

  • Name
    type
    Type
    string
    Description

    ประเภทของ task ค่านี้คือ creative-lab-keycap-build

  • Name
    name
    Type
    string
    Description

    ชื่อ task ที่ระบุไว้ตอนสร้าง task เป็นสตริงว่างหากไม่ได้ระบุชื่อไว้

  • Name
    status
    Type
    string
    Description

    สถานะของ task ค่าที่เป็นไปได้คือค่าใดค่าหนึ่งจาก PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED

  • Name
    progress
    Type
    integer
    Description

    progress ของ task หาก task ยังไม่เริ่มทำงาน property นี้จะเป็น 0 เมื่อ task สำเร็จแล้ว ค่านี้จะกลายเป็น 100

  • Name
    created_at
    Type
    timestamp
    Description

    ไทม์สแตมป์ของเวลาที่สร้าง task หน่วยเป็นมิลลิวินาที

  • Name
    started_at
    Type
    timestamp
    Description

    ไทม์สแตมป์ของเวลาที่เริ่ม task หน่วยเป็นมิลลิวินาที

  • Name
    finished_at
    Type
    timestamp
    Description

    ไทม์สแตมป์ของเวลาที่ task เสร็จสิ้น หน่วยเป็นมิลลิวินาที

  • Name
    expires_at
    Type
    timestamp
    Description

    ไทม์สแตมป์ของเวลาที่ผลลัพธ์ของ task จะหมดอายุ หน่วยเป็นมิลลิวินาที

  • Name
    preceding_tasks
    Type
    integer
    Description

    จำนวน task ที่อยู่ก่อนหน้า มีความหมายเฉพาะเมื่อสถานะเป็น PENDING

  • Name
    task_error
    Type
    object
    Description

    รายละเอียดข้อผิดพลาดสำหรับ task ที่ล้มเหลว ดู ข้อผิดพลาด สำหรับข้อมูลอ้างอิงฉบับเต็มของ object task_error

  • Name
    consumed_credits
    Type
    integer
    Description

    จำนวนเครดิตที่ถูกใช้ไปโดย task นี้ task ที่มีสถานะถึง SUCCEEDED จะถูกเรียกเก็บเครดิตเต็มจำนวนสำหรับขั้นตอนของมัน ส่วน task ที่ไม่เคยถูกสร้างขึ้นเลย (เกิด 4xx ตอนที่ส่งคำขอ รวมถึงการถูกปฏิเสธจาก moderation) จะไม่ถูกเรียกเก็บเครดิตเลย task ที่มีสถานะถึง FAILED จะคืนค่าเป็น 0 — เครดิตที่ถูกเรียกเก็บจะถูกคืนเงิน รวมถึงกรณีถูก moderation บล็อกแบบ asynchronous ด้วย การยกเลิกผ่าน DELETE จะคืนเครดิตเฉพาะในขณะที่ task ยังเป็น PENDING เท่านั้น ส่วน task ที่เป็น IN_PROGRESS อยู่แล้วจะยังคงถูกเรียกเก็บเครดิต เนื่องจากงานได้ถูกใช้ไปแล้ว

  • Name
    model_urls
    Type
    object
    Description

    URL สำหรับดาวน์โหลด artifact ของโมเดลที่สร้างขึ้น ทั้ง GLB และชุด OBJ จะถูกส่งออกในสเกล มิลลิเมตรตามขนาดจริง (real-world), แกน Y เป็นด้านบน (Y-up) โดยด้านหน้าของคีย์แคปหันไปทาง +Z เมชจะถูกตั้งชื่อว่า keycap-head และ keycap-base; เมื่อฐาน (base) ตกไปใช้การเติมลวดลาย (pattern fill) แทน จะมีเมชที่สามคือ keycap-base-interior ปรากฏด้วยสำหรับช่องว่างของก้าน (stem cavity) อย่าตั้งสมมติฐานว่าจะมีเมชเพียงสองชิ้นเสมอไป

    URL เหล่านี้เป็น signed URL: ให้เรียกใช้งานโดยไม่ต้องใส่ header Authorization URL จะยังใช้งานได้จนถึง expires_at ซึ่งคือ 3 วันหลังจาก finished_at และการอ่าน task ซ้ำภายในช่วงเวลานั้นจะได้ URL เดิมกลับมา ไม่ใช่ URL ที่ signed ใหม่ ควรดาวน์โหลดและจัดเก็บไฟล์ด้วยตัวเองก่อนที่จะหมดเวลาดังกล่าว เนื่องจากไม่มีวิธีใดที่จะรีเฟรชลิงก์ที่หมดอายุแล้วได้

    • Name
      glb
      Type
      string
      Description

      URL สำหรับดาวน์โหลด model.glb ที่มีเท็กซ์เจอร์สมบูรณ์แล้ว

    • Name
      obj_zip
      Type
      string
      Description

      URL สำหรับดาวน์โหลดชุดไฟล์ zip ที่ประกอบด้วย model.obj, model.mtl และไฟล์ PNG ของเท็กซ์เจอร์ที่ไฟล์ MTL ของมันอ้างอิงถึงจริง ๆ ฐาน (base) ที่เป็นสีทึบจะมีเฉพาะ keycap-head.png ส่วนฐานที่มีลวดลาย (patterned) จะมี keycap-base.png ด้วย

  • Name
    process_image_urls
    Type
    object
    Description

    URL สำหรับดาวน์โหลดภาพขั้นตอนกลาง (intermediate process images) โดยจัดกลุ่มตามประเภท (kind) มี URL lifecycle เดียวกันกับ model_urls: เป็น signed URL, ไม่ต้องใส่ header Authorization, ใช้งานได้จนถึง expires_at และคงที่เมื่ออ่าน task ซ้ำ ประเภทที่ส่งออกในปัจจุบันได้แก่:

    • head_design — ภาพดีไซน์ของ candidate ที่ถูกเลือกซึ่งใช้ในการ build (มีอยู่เสมอ)
    • composite — ภาพเรนเดอร์แสดงคีย์แคปที่เสร็จสมบูรณ์ของ candidate ที่ถูกเลือก (มีเมื่อสามารถสร้างได้)
    • base_canvas — canvas ของฐานคีย์แคปที่ลงสีแล้ว (มีเมื่อสามารถสร้างได้)

    ควรถือว่าชุดคีย์นี้เปิดกว้างสำหรับการขยายเพิ่มเติม อาจมีการเพิ่มประเภทใหม่ ๆ โดยไม่ถือเป็นการเปลี่ยนแปลงที่ทำให้ใช้งานไม่ได้ (breaking change)

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

ตัวอย่างการทำงานแบบครบวงจร

กระบวนการทั้งหมด: สร้างต้นแบบ (prototype) จากรูปภาพ, โพลจนกว่าจะได้สถานะ SUCCEEDED, เลือกตัวเลือกจาก candidate_ids, สร้างงานสร้างโมเดล (build) ด้วย ตัวเลือกนั้น, โพลงานสร้างโมเดลจนกว่าจะได้สถานะ SUCCEEDED จากนั้นดาวน์โหลด GLB และ ชุด OBJ จาก model_urls

ตัวอย่างนี้จะเลือกตัวเลือก แรก โดยอัตโนมัติผ่านโปรแกรม ในการใช้งานจริง คุณควรแสดงรายการ image_urls ให้ผู้ใช้ปลายทางเห็นและ ให้พวกเขาเลือกเอง โดยดัชนีที่เลือกจะสอดคล้อง 1:1 กับ 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"