Creative Lab — Keycap API

Biến một bức ảnh nguồn thành một keycap bàn phím cơ tùy chỉnh đầy đủ màu sắc qua hai giai đoạn: prototype tạo ra bản render thiết kế "keycap hoàn thiện" từ ảnh đầu vào của bạn. Sau khi đã xác nhận bản render đó, build sẽ biến nó thành mô hình keycap 3D có texture chỉ trong một lần chạy — tạo mô hình trắng, tự động căn chỉnh vị trí và cắt gọt theo tư thế mặc định đã hiệu chuẩn, tô màu toàn bộ mô hình, và lắp ráp cuối cùng đều diễn ra trong một tác vụ build duy nhất. Hai giai đoạn được liên kết với nhau thông qua input_task_id cùng với candidate_id.

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

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

Tạo tác vụ Keycap Prototype

Tạo một bản render thiết kế keycap hoàn chỉnh từ ảnh nguồn. Kết quả của tác vụ mang theo một mảng image_urls (bản render hiển thị của keycap hoàn chỉnh) và một mảng candidate_ids song song; cả hai đều chỉ chứa một mục duy nhất. Gọi lại endpoint này để tạo một bản render khác nếu kết quả không như mong muốn — mỗi lần gọi được tính phí riêng. Truyền candidate_id cùng với ID của tác vụ prototype tới endpoint build. Tham khảo The Keycap Prototype Task Object để biết cấu trúc phản hồi.

Tham số

  • Name
    image_url
    Type
    string
    Bắt buộc
    Description

    Ảnh nguồn để Meshy chuyển đổi thành các ảnh thiết kế keycap. Hiện chúng tôi hỗ trợ các định dạng .jpg, .jpeg, .png, và .webp.

    Định dạng được phát hiện bằng cách giải mã dữ liệu ảnh, không dựa vào phần mở rộng tệp trong URL — một URL không có phần mở rộng, hoặc một URL chuyển hướng, vẫn hoạt động miễn là các byte giải mã được thành một định dạng được hỗ trợ. Các chuyển hướng HTTP sẽ được theo dõi. Hướng EXIF được chuẩn hóa, vì vậy một ảnh chụp từ điện thoại bị xoay sẽ được sử dụng đúng theo hướng hiển thị của nó.

    Giới hạn: ít nhất 32 pixel mỗi cạnh, tối đa 178,956,970 pixel tổng cộng, và tối đa 20,000,000 byte sau khi tải xuống. Đối với Data URI, giới hạn áp dụng cho các byte đã giải mã, vì vậy bản thân tệp nguồn có thể lên tới kích thước đó — chính văn bản base64 mới lớn hơn khoảng một phần ba, điều này ảnh hưởng đến nội dung yêu cầu (request body) của bạn, chứ không ảnh hưởng đến giới hạn này. Data URI phải khai báo kiểu nội dung image/*;base64.

    Có hai cách để cung cấp ảnh:

    • URL truy cập công khai: Một URL có thể truy cập được từ internet công cộng.
    • Data URI: Một Data URI của ảnh được mã hóa base64. Ví dụ về Data URI: data:image/jpeg;base64,<dữ liệu ảnh mã hóa base64 của bạn>.
  • Name
    name
    Type
    string
    Description

    Tên tác vụ tùy chọn dùng cho mục đích hiển thị. Tối đa 100 ký tự.

  • Name
    remove_background
    Type
    boolean
    mặc định false
    Description

    Khi đặt thành true, bản render hiển thị được trả về trong image_urls là một ảnh PNG RGBA trong suốt với nền đã được loại bỏ, để bạn có thể ghép nó lên bất kỳ nền nào.

    Điều này chỉ áp dụng cho bản render hiển thị. Candidate mà endpoint build sử dụng không bị ảnh hưởng, vì vậy kết quả 3D vẫn giống nhau trong cả hai trường hợp.

Giá trị trả về

Thuộc tính result của phản hồi chứa id của tác vụ của tác vụ keycap prototype vừa được tạo. Hãy poll endpoint Get a Task hoặc đăng ký stream cho đến khi tác vụ đạt trạng thái SUCCEEDED, sau đó lấy mục từ candidate_ids và truyền nó, cùng với ID của tác vụ, tới endpoint build.

Các chế độ lỗi

  • Name
    400 - Bad Request
    Description

    Yêu cầu không hợp lệ. Các nguyên nhân phổ biến:

    • Thiếu tham số: image_url là bắt buộc.
    • Định dạng ảnh không hợp lệ: image_url được cung cấp không phải là định dạng được hỗ trợ (.jpg, .jpeg, .png, .webp).
    • Kích thước ảnh nằm ngoài phạm vi cho phép: Ảnh quá nhỏ, vượt quá kích thước tệp tối đa, hoặc vượt quá số lượng pixel tối đa.
    • URL không thể truy cập: Không thể tải xuống image_url (404 hoặc timeout).
    • Data URI không hợp lệ: Chuỗi base64 bị lỗi định dạng.
    • Nội dung bị gắn cờ: Ảnh đầu vào bị gắn cờ bởi moderation nội dung nhạy cảm (NSFW).
  • Name
    401 - Unauthorized
    Description

    Xác thực thất bại. Vui lòng kiểm tra khóa API của bạn.

  • Name
    402 - Payment Required
    Description

    Tài khoản đang sử dụng gói miễn phí (cần có gói trả phí để tạo tác vụ) hoặc không đủ tín dụng.

  • Name
    403 - Forbidden
    Description

    Ảnh đầu vào bị gắn cờ bởi moderation sở hữu trí tuệ.

  • Name
    429 - Too Many Requests
    Description

    Bạn đã vượt quá giới hạn tốc độ.

  • Name
    500 - Internal Server Error
    Description

    Đã xảy ra lỗi phía máy chủ ngoài dự kiến — ví dụ: dịch vụ kiểm duyệt nội dung không khả dụng, việc tải tạm (staging) ảnh đầu vào thất bại, hoặc không thể tạo tác vụ. Trong trường hợp này, không có tác vụ nào được tạo, vì vậy việc thử lại là an toàn.

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

Tạo tác vụ Build Keycap

Tạo mô hình keycap 3D cuối cùng đã được phủ texture từ một tác vụ prototype đã thành công và một trong các candidate của nó. Một tác vụ build duy nhất chạy toàn bộ pipeline từ đầu đến cuối — tạo white-model từ thiết kế đã chọn, tự động đặt và cắt lên nền keycap bằng một tư thế mặc định đã được hiệu chỉnh (không cần điều chỉnh tương tác), tô màu toàn bộ mô hình, và lắp ráp cùng xuất file cuối cùng. Một lần build thường mất 3–7 phút, thiên về mức cao hơn khi có nhiều lượt build chạy đồng thời. Tham khảo The Keycap Build Task Object để biết cấu trúc phản hồi.

Tham số

  • Name
    input_task_id
    Type
    string
    Bắt buộc
    Description

    ID tác vụ của một tác vụ prototype được tạo qua cùng endpoint OpenAPI này. Prototype phải được tạo bởi cùng tài khoản Meshy, phải đã đạt trạng thái SUCCEEDED, và phải đã tạo ra ít nhất một candidate.

    Các tác vụ prototype được tạo qua webapp không được chấp nhận — endpoint build chỉ chấp nhận các tác vụ prototype được tạo bởi POST /openapi/creative-lab/keycap/v1/prototype và từ chối mọi nguồn khác với mã 404.

  • Name
    candidate_id
    Type
    string
    Bắt buộc
    Description

    Candidate cần build, lấy từ mảng candidate_ids của tác vụ prototype đã thành công. Phải thuộc về tác vụ đó; bất kỳ giá trị nào khác sẽ bị từ chối với mã 400.

  • Name
    name
    Type
    string
    Description

    Tên tác vụ tùy chọn để hiển thị. Tối đa 100 ký tự.

options

Tùy chỉnh hình học tùy chọn. Mỗi trường đều có giá trị mặc định đã được hiệu chỉnh — chỉ cần gửi những trường bạn muốn ghi đè.

  • Name
    base_model
    Type
    string
    mặc định cherry-mx-1x1-r1
    Description

    Nền keycap để build lên. Hiện tại giá trị duy nhất khả dụng là cherry-mx-1x1-r1 — một keycap 1u chuẩn profile Cherry MX. Dự kiến sẽ có thêm 3–5 kích thước chuẩn phổ biến khác; không hỗ trợ kích thước tùy chỉnh.

  • Name
    head_size_mm
    Type
    number
    mặc định 23
    Description

    Kích thước mục tiêu của phần đầu điêu khắc, tính bằng milimet: kích thước dài nhất của nó được scale theo giá trị này. Phạm vi: [10, 40]. Các giá trị lớn hơn khoảng 32.9 có thể bị giảm để phần đầu vẫn vừa với giới hạn diện tích bảo vệ của nền, do đó kích thước dài nhất được trả về có thể nhỏ hơn giá trị yêu cầu. Giá trị đã áp dụng hiện chưa được trả lại trong task object — nếu bạn cần xác nhận kích thước thực tế nhận được, hãy đo hộp bao của lưới keycap-head trong mô hình đã tải về.

  • Name
    vertical_offset_mm
    Type
    number
    mặc định 0
    Description

    Độ dịch chuyển theo phương thẳng đứng áp dụng cho phần đầu trước khi đặt lên nền, tính bằng milimet. Phạm vi: [-5, 5].

Kết quả trả về

Thuộc tính result của phản hồi chứa id tác vụ của tác vụ build keycap vừa được tạo. Poll endpoint Get a Task hoặc đăng ký stream cho đến khi tác vụ đạt trạng thái SUCCEEDED, sau đó tải các artifact từ model_urls.glbmodel_urls.obj_zip.

Các trường hợp lỗi

  • Name
    400 - Bad Request
    Description

    Yêu cầu không hợp lệ. Các nguyên nhân phổ biến:

    • Thiếu tham số: input_task_idcandidate_id là bắt buộc.
    • UUID không hợp lệ: input_task_id không phải là một UUID hợp lệ.
    • Tác vụ cha chưa thành công: Tác vụ prototype được tham chiếu chưa đạt trạng thái SUCCEEDED.
    • Không có candidate: Tác vụ prototype đã thành công nhưng không tạo ra candidate nào.
    • Candidate không xác định: candidate_id không phải là một trong các candidate của tác vụ đầu vào.
    • Options nằm ngoài phạm vi: Một trong các trường của options nằm ngoài phạm vi cho phép hoặc tập enum cho phép.
  • Name
    401 - Unauthorized
    Description

    Xác thực thất bại. Vui lòng kiểm tra khóa API của bạn.

  • Name
    402 - Payment Required
    Description

    Tài khoản đang dùng gói miễn phí (cần có gói trả phí để tạo tác vụ) hoặc không đủ tín dụng.

  • Name
    404 - Not Found
    Description

    Tác vụ prototype được tham chiếu không tồn tại, thuộc về người dùng khác, hoặc được tạo qua webapp (chỉ các tác vụ prototype ở chế độ API mới có thể nối tiếp sang build).

  • Name
    429 - Too Many Requests
    Description

    Bạn đã vượt quá giới hạn tốc độ.

  • Name
    500 - Internal Server Error
    Description

    Đã xảy ra lỗi phía máy chủ ngoài dự kiến — ví dụ dịch vụ moderation nội dung không khả dụng, việc staging ảnh đầu vào thất bại, hoặc tác vụ không thể được tạo. Trong trường hợp này không có tác vụ nào được tạo ra, vì vậy việc thử lại là an toàn.

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

Truy xuất một Tác vụ Keycap

Truy xuất một tác vụ prototype hoặc build với một id tác vụ hợp lệ. Đường dẫn URL phải khớp với giai đoạn của tác vụ — một tác vụ build được lấy qua /prototype/:id sẽ trả về 404, và ngược lại.

Tham khảo Đối tượng Tác vụ Keycap PrototypeĐối tượng Tác vụ Keycap Build để biết cấu trúc phản hồi.

Tham số

  • Name
    id
    Type
    path
    Description

    Định danh duy nhất cho tác vụ keycap cần truy xuất.

Giá trị trả về

Phản hồi chứa đối tượng tác vụ keycap. Cấu trúc phụ thuộc vào giai đoạn nào đã được yêu cầu.

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

Xóa một Keycap Task

Hủy một keycap task. Nếu task vẫn đang ở trạng thái PENDING, số tín dụng đã tiêu tốn tại thời điểm tạo sẽ được hoàn lại. Các task đã ở trạng thái IN_PROGRESS sẽ bị hủy nhưng không được hoàn tiền (worker có thể đã bắt đầu tiêu tốn tài nguyên). Các task đã đạt đến trạng thái cuối cùng (SUCCEEDED, FAILED, CANCELED) không thể bị hủy.

Đường dẫn URL phải khớp với giai đoạn của task — gọi DELETE trên /prototype/:buildId sẽ trả về 404.

Tham số đường dẫn

  • Name
    id
    Type
    path
    Description

    Định danh duy nhất của keycap task cần hủy.

Kết quả trả về

Trả về 204 No Content khi thành công với nội dung phản hồi trống.

Các trường hợp lỗi

  • Name
    400 - Bad Request
    Description

    Task đã ở trạng thái cuối cùng và không thể bị hủy.

  • Name
    404 - Not Found
    Description

    Task không tồn tại, thuộc về một người dùng khác, hoặc giai đoạn của nó không khớp với đường dẫn URL.

  • Name
    500 - Internal Server Error
    Description

    Đã xảy ra lỗi phía máy chủ ngoài dự kiến trong quá trình hủy. Task có thể đã bị hủy hoặc chưa — hãy đọc lại để xác nhận trước khi thử lại.

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

Truyền trực tuyến một tác vụ Keycap

Truyền trực tuyến các cập nhật theo thời gian thực cho một tác vụ keycap thông qua Server-Sent Events (SSE). Đường dẫn URL phải khớp với giai đoạn của tác vụ — mở một luồng tại /prototype/:buildId/stream sẽ phát ra một event: error duy nhất với status_code: 404 rồi đóng luồng lại.

Tham số

  • Name
    id
    Type
    path
    Description

    Định danh duy nhất của tác vụ keycap cần truyền trực tuyến.

Giá trị trả về

Trả về một luồng các đối tượng tác vụ Keycap Prototype hoặc Keycap Build dưới dạng Server-Sent Events. Mỗi khung dữ liệu đều mang toàn bộ đối tượng tác vụ cho giai đoạn đó — cùng cấu trúc mà endpoint Get trả về — vì vậy khi tác vụ đang ở trạng thái PENDING hoặc IN_PROGRESS, các trường đầu ra đơn giản là chưa được điền dữ liệu (null, [] hoặc {}) và finished_atnull.

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

Truy xuất một danh sách đã phân trang các tác vụ keycap của bạn cho một giai đoạn duy nhất. Đường dẫn URL chọn giai đoạn — /prototype trả về các tác vụ nguyên mẫu; /build trả về các tác vụ dựng. Các tác vụ từ giai đoạn còn lại không được bao gồm trong bất kỳ phản hồi nào.

Tham số đường dẫn

  • Name
    stage
    Type
    path
    Bắt buộc
    Description

    Hoặc prototype hoặc build. Tập hợp chỉ trả về các tác vụ có giai đoạn khớp với URL — việc lấy /prototype không bao giờ trả về các tác vụ dựng và ngược lại.

Tham số truy vấn

  • Name
    page_num
    Type
    integer
    mặc định 1
    Description

    Số trang cho việc phân trang.

  • Name
    page_size
    Type
    integer
    mặc định 10
    Description

    Giới hạn kích thước trang. Tối đa cho phép là 100 mục.

  • Name
    sort_by
    Type
    string
    mặc định -created_at
    Description

    Trường để sắp xếp theo. Các giá trị khả dụng:

    • +created_at: Sắp xếp theo thời gian tạo theo thứ tự tăng dần.
    • -created_at: Sắp xếp theo thời gian tạo theo thứ tự giảm dần.

Giá trị trả về

Trả về một danh sách đã phân trang của đối tượng tác vụ theo từng giai đoạn — hoặc đối tượng tác vụ nguyên mẫu keycap khi liệt kê /prototype hoặc đối tượng tác vụ dựng keycap khi liệt kê /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"
    ]
  }
]

Đối tượng Keycap Prototype Task

Đối tượng Keycap Prototype Task là một đơn vị công việc mà Meshy theo dõi để tạo ra một hình ảnh thiết kế keycap hoàn chỉnh từ một ảnh chụp nguồn. Đầu ra của giai đoạn này được nối chuỗi sang giai đoạn build thông qua input_task_id cùng với candidate_id.

Thuộc tính

  • Name
    id
    Type
    string
    Description

    Định danh duy nhất cho tác vụ. Mặc dù chúng tôi sử dụng UUID có thể sắp xếp theo k (k-sortable) làm chi tiết triển khai cho id tác vụ, bạn không nên đưa ra bất kỳ giả định nào về định dạng của id.

  • Name
    type
    Type
    string
    Description

    Loại của tác vụ. Giá trị là creative-lab-keycap-prototype.

  • Name
    name
    Type
    string
    Description

    Tên tác vụ được cung cấp khi tác vụ được tạo. Là chuỗi rỗng nếu không có tên nào được cung cấp.

  • Name
    status
    Type
    string
    Description

    Trạng thái của tác vụ. Các giá trị có thể là một trong các giá trị PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.

  • Name
    progress
    Type
    integer
    Description

    Tiến trình (progress) của tác vụ. Nếu tác vụ chưa bắt đầu, thuộc tính này sẽ là 0. Khi tác vụ đã thành công, giá trị này sẽ trở thành 100.

  • Name
    created_at
    Type
    timestamp
    Description

    Dấu thời gian khi tác vụ được tạo, tính bằng mili giây.

  • Name
    started_at
    Type
    timestamp
    Description

    Dấu thời gian khi tác vụ được bắt đầu, tính bằng mili giây. Nếu tác vụ chưa được bắt đầu, thuộc tính này sẽ là 0.

  • Name
    finished_at
    Type
    timestamp
    Description

    Dấu thời gian khi tác vụ hoàn tất, tính bằng mili giây. Nếu tác vụ chưa hoàn tất, thuộc tính này sẽ là 0.

  • Name
    expires_at
    Type
    timestamp
    Description

    Dấu thời gian khi kết quả tác vụ hết hạn, tính bằng mili giây.

  • Name
    preceding_tasks
    Type
    integer
    Description

    Số lượng tác vụ đứng trước.

  • Name
    task_error
    Type
    object
    Description

    Chi tiết lỗi cho các tác vụ thất bại. Xem Lỗi để biết tham chiếu đầy đủ về đối tượng task_error.

  • Name
    consumed_credits
    Type
    integer
    Description

    Số lượng tín dụng đã tiêu thụ bởi tác vụ này. Một tác vụ đạt trạng thái SUCCEEDED sẽ bị tính đầy đủ chi phí cho giai đoạn của nó. Một tác vụ chưa từng được tạo ra (một lỗi 4xx tại thời điểm yêu cầu, bao gồm cả việc bị từ chối bởi moderation) sẽ hoàn toàn không bị tính phí. Một tác vụ đạt trạng thái FAILED trả về 0 — khoản phí sẽ được hoàn lại, bao gồm cả trường hợp bị chặn bởi moderation không đồng bộ. Việc hủy thông qua DELETE chỉ hoàn tiền khi tác vụ vẫn đang ở trạng thái PENDING; một tác vụ đã ở trạng thái IN_PROGRESS vẫn sẽ bị tính phí, vì công việc đã được thực hiện.

  • Name
    image_urls
    Type
    array of strings
    Description

    URL có thể tải xuống của bản render thiết kế keycap hoàn chỉnh — thể hiện phương án ứng viên trông như thế nào khi trở thành một keycap hoàn chỉnh. Chỉ chứa một mục duy nhất; image_urls[i] tương ứng với candidate_ids[i]. Trống cho đến khi tác vụ đạt trạng thái SUCCEEDED. URL này chỉ dùng để hiển thị; endpoint build tiêu thụ candidate_ids, chứ không phải các URL này. Vòng đời URL giống như của model_urls: đã được ký, không có tiêu đề Authorization, có hiệu lực cho đến expires_at, và ổn định khi tác vụ được đọc lại.

  • Name
    candidate_ids
    Type
    array of strings
    Description

    Các định danh ứng viên không minh bạch (opaque), song song với image_urls. Truyền mục tương ứng với thiết kế bạn đã chọn làm candidate_id của yêu cầu build. Không đưa ra bất kỳ giả định nào về định dạng của các id này.

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

Đối tượng Keycap Build Task

Đối tượng Keycap Build Task là một đơn vị công việc được Meshy theo dõi để tạo ra keycap 3D đã phủ texture cuối cùng từ một prototype task đã thành công và một candidate được chọn. Một lần build sẽ chạy toàn bộ pipeline — tạo mô hình trắng (white-model), tự động canh khớp và cắt, tô màu, lắp ráp, và xuất file.

Thuộc tính

  • Name
    id
    Type
    string
    Description

    Định danh duy nhất cho task.

  • Name
    type
    Type
    string
    Description

    Loại của task. Giá trị là creative-lab-keycap-build.

  • Name
    name
    Type
    string
    Description

    Tên task được cung cấp khi task được tạo. Là chuỗi rỗng nếu không có tên nào được cung cấp.

  • Name
    status
    Type
    string
    Description

    Trạng thái của task. Các giá trị có thể là một trong PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.

  • Name
    progress
    Type
    integer
    Description

    progress của task. Nếu task chưa bắt đầu, thuộc tính này sẽ là 0. Khi task đã thành công, giá trị này sẽ trở thành 100.

  • Name
    created_at
    Type
    timestamp
    Description

    Dấu thời gian khi task được tạo, tính bằng mili giây.

  • Name
    started_at
    Type
    timestamp
    Description

    Dấu thời gian khi task được bắt đầu, tính bằng mili giây.

  • Name
    finished_at
    Type
    timestamp
    Description

    Dấu thời gian khi task được hoàn thành, tính bằng mili giây.

  • Name
    expires_at
    Type
    timestamp
    Description

    Dấu thời gian khi kết quả của task hết hạn, tính bằng mili giây.

  • Name
    preceding_tasks
    Type
    integer
    Description

    Số lượng các task đứng trước. Chỉ có ý nghĩa khi status là PENDING.

  • Name
    task_error
    Type
    object
    Description

    Chi tiết lỗi cho các task thất bại. Xem Lỗi để biết đầy đủ tham chiếu đối tượng task_error.

  • Name
    consumed_credits
    Type
    integer
    Description

    Số lượng tín dụng đã bị tiêu thụ bởi task này. Một task đạt trạng thái SUCCEEDED sẽ bị tính đầy đủ số tín dụng cho giai đoạn của nó. Một task không bao giờ được tạo ra (một lỗi 4xx tại thời điểm gửi yêu cầu, bao gồm cả việc bị từ chối do moderation) sẽ hoàn toàn không bị tính phí. Một task đạt trạng thái FAILED trả về 0 — khoản phí sẽ được hoàn lại, bao gồm cả trường hợp bị chặn bởi moderation không đồng bộ. Việc hủy qua DELETE chỉ hoàn tiền khi task vẫn đang ở trạng thái PENDING; một task đã ở trạng thái IN_PROGRESS vẫn sẽ bị tính phí, vì công việc đã được thực hiện.

  • Name
    model_urls
    Type
    object
    Description

    Các URL có thể tải xuống cho các sản phẩm mô hình được tạo ra. Cả gói GLB và OBJ đều được xuất theo tỷ lệ milimét thực tế, trục Y hướng lên, với mặt trước của keycap hướng về +Z. Các lưới được đặt tên là keycap-headkeycap-base; khi phần đế (base) chuyển sang dùng kiểu lấp đầy hoa văn (pattern fill), một lưới thứ ba keycap-base-interior cũng sẽ xuất hiện cho khoang chứa trục phím (stem cavity). Đừng giả định rằng luôn chỉ có đúng hai lưới.

    Đây là các URL đã được ký (signed URLs): hãy lấy chúng mà không cần header Authorization. Chúng vẫn còn hiệu lực cho đến expires_at, tức là 3 ngày sau finished_at, và việc đọc lại task trong khoảng thời gian đó sẽ trả về đúng cùng một URL thay vì một URL mới được ký. Hãy tự tải xuống và lưu trữ các tệp trước thời điểm đó — không có cách nào để làm mới một liên kết đã hết hạn.

    • Name
      glb
      Type
      string
      Description

      URL có thể tải xuống cho tệp model.glb đã phủ texture cuối cùng.

    • Name
      obj_zip
      Type
      string
      Description

      URL có thể tải xuống cho gói zip chứa model.obj, model.mtl, và các tệp PNG texture mà file MTL của nó thực sự tham chiếu tới. Một phần đế màu đơn sắc chỉ đi kèm keycap-head.png; một phần đế có hoa văn cũng sẽ đi kèm keycap-base.png.

  • Name
    process_image_urls
    Type
    object
    Description

    Các URL có thể tải xuống cho các hình ảnh quá trình xử lý trung gian, được đánh khóa theo loại (kind). Vòng đời URL giống với model_urls: đã được ký, không cần header Authorization, có hiệu lực đến expires_at, và ổn định khi task được đọc lại. Các loại (kind) hiện đang được tạo ra:

    • head_design — hình ảnh thiết kế của candidate được chọn mà quá trình build đã sử dụng (luôn có mặt).
    • composite — bản render hiển thị keycap hoàn thiện của candidate được chọn (có mặt khi khả dụng).
    • base_canvas — canvas phần đế keycap đã được vẽ (có mặt khi khả dụng).

    Hãy coi tập hợp các khóa (key) này là mở, có thể mở rộng; các loại (kind) mới có thể được thêm vào mà không gây ra thay đổi phá vỡ (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=***"
  }
}

Ví dụ đầy đủ từ đầu đến cuối

Quy trình hoàn chỉnh: tạo một prototype từ một bức ảnh, poll nó cho đến khi SUCCEEDED, chọn một candidate từ candidate_ids, tạo một build với candidate đó, poll build cho đến khi SUCCEEDED, sau đó tải xuống GLB và gói OBJ từ model_urls.

Ví dụ này chọn candidate đầu tiên một cách tự động. Trong một tích hợp thực tế, bạn nên hiển thị mục image_urls cho người dùng cuối và để họ lựa chọn; chỉ số được chọn sẽ ánh xạ 1:1 vào 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"