Creative Lab — 键帽 API
将一张原始照片分两个阶段转换为全彩定制机械键盘键帽:prototype(原型) 阶段会根据你输入的照片生成
一张“成品键帽”设计效果图。在确认该效果图之后,build(构建) 阶段会在一次运行中将其转换为
带贴图的 3D 键帽模型——白模生成、在标定的默认姿态上自动就位与切割、全模型上色,
以及最终组装,均在同一个构建任务内完成。这两个阶段通过 input_task_id
与 candidate_id 关联在一起。
POST /openapi/creative-lab/keycap/v1/prototypePOST /openapi/creative-lab/keycap/v1/build
这两个 POST endpoint 均需要付费 subscription 套餐。免费套餐账户发起的请求将被拒绝,
并返回 402 Payment Required。
创建键帽原型任务
根据源照片生成成品键帽设计渲染图。任务结果携带一个 image_urls 数组(成品键帽的展示渲染图)和一个对应的 candidate_ids 数组;两者都只包含一个条目。如果结果不是你想要的,可以再次调用此 endpoint 来获取另一张渲染图——每次调用都是单独计费的。将 candidate_id 与原型任务 ID 一起传给构建 endpoint。
有关响应结构,请参阅
键帽原型任务对象。
参数
- Name
- image_url
- Type
- string
- 必选
- Description
供 Meshy 转换为键帽设计图片的源照片。我们目前支持
.jpg、.jpeg、.png和.webp格式。格式是通过解码图片数据来检测的,而不是根据 URL 的文件扩展名——没有扩展名的 URL,或会重定向的 URL,只要字节能解码为受支持的格式即可正常使用。系统会跟随 HTTP 重定向。EXIF 方向信息会被规范化,因此旋转过的手机照片会按其看起来的方向被使用。
限制条件:每边至少
32像素,总像素数最多178,956,970,下载后大小最多20,000,000字节。对于 data URI,该限制适用于解码后的字节数,因此源文件本身可以达到该大小上限——base64 文本会大约多出三分之一,这会影响你的请求体大小,但不影响此项限制。data URI 必须声明image/*内容类型和;base64。提供图片的方式有两种:
- 可公开访问的 URL:可从公共互联网访问的 URL。
- Data URI:图片的 base64 编码 data URI。data URI 示例:
data:image/jpeg;base64,<your base64-encoded image data>。
- Name
- name
- Type
- string
- Description
用于显示目的的可选任务名称。最多 100 个字符。
- Name
- remove_background
- Type
- boolean
- 默认值 false
- Description
设置为
true时,image_urls中返回的展示渲染图是已移除背景的透明 RGBA PNG,因此你可以将其合成到任意背景上。此设置仅适用于展示渲染图。构建 endpoint 所使用的候选项不受影响,因此无论如何设置,3D 结果都是相同的。
返回值
响应的 result 属性包含新创建的键帽原型任务的任务 id。轮询获取任务 endpoint 或订阅流式接口,直到任务达到 SUCCEEDED 状态,然后取出 candidate_ids 中的条目,将其与任务 ID 一起传给构建 endpoint。
失败模式
- Name
400 - Bad Request- Description
请求无法被接受。常见原因:
- 缺少参数:
image_url是必填项。 - 图片格式无效:提供的
image_url不是受支持的格式(.jpg、.jpeg、.png、.webp)。 - 图片尺寸超出范围:图片过小、超过最大文件大小,或超过最大像素数。
- URL 无法访问:无法下载
image_url(404 或 timeout)。 - Data URI 无效:base64 字符串格式有误。
- 内容被标记:输入图片被 NSFW moderation 标记。
- 缺少参数:
- Name
401 - Unauthorized- Description
Authentication 失败。请检查你的 API key。
- Name
402 - Payment Required- Description
该账户处于免费计划中(创建任务需要付费计划),或 credits 不足。
- Name
403 - Forbidden- Description
输入图片被知识产权 moderation 标记。
- Name
429 - Too Many Requests- Description
你已超出速率限制。
- Name
500 - Internal Server Error- Description
发生了意外的服务器端错误——例如内容审核服务不可用、暂存输入图片失败,或任务无法创建。在这种情况下不会创建任务,因此重试是安全的。
Request
# 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"
}
创建键帽构建任务
从一个成功的原型任务及其某个候选方案生成最终的带贴图 3D 键帽模型。单个构建任务会端到端运行整个流程——根据所选设计生成白模、使用经过校准的默认姿态自动将其放置并裁切到键帽底座上(无需交互式调整)、全模型上色,以及最终装配与导出。构建通常需要 3–7 分钟,在多个构建并发运行时会更接近上限。 响应结构请参阅键帽构建任务对象。
参数
- Name
- input_task_id
- Type
- string
- 必选
- Description
通过同一个 OpenAPI endpoint 创建的原型任务的任务 ID。该原型必须由同一个 Meshy 账户创建,必须已到达
SUCCEEDED状态,并且必须至少产生一个候选方案。通过 webapp 创建的原型任务不被接受——构建 endpoint 仅接受由
POST /openapi/creative-lab/keycap/v1/prototype生成的原型任务,任何其他来源都会被拒绝并返回404。
- Name
- candidate_id
- Type
- string
- 必选
- Description
要构建的候选方案,取自成功的原型任务的
candidate_ids数组。必须属于该任务;任何其他值都会被拒绝并返回400。
- Name
- name
- Type
- string
- Description
可选的任务名称,用于显示目的。最多 100 个字符。
options
可选的 geometry 调整。每个字段都有经过校准的默认值——只需发送你想要覆盖的字段。
- 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-headmesh 的包围盒。
- Name
- vertical_offset_mm
- Type
- number
- 默认值 0
- Description
在头部安置到底座之前施加的垂直偏移量,以毫米为单位。范围:
[-5, 5]。
返回值
响应的 result 属性包含新创建的键帽构建任务的任务 id。轮询获取任务 endpoint 或订阅流,直到任务到达 SUCCEEDED,然后从 model_urls.glb 和 model_urls.obj_zip 下载产物。
GLB 和 OBJ 压缩包均以真实世界毫米比例导出,采用 Y 轴向上的坐标系,且键帽正面朝向 +Z。
失败模式
- Name
400 - Bad Request- Description
请求不可接受。常见原因:
- 缺少参数:
input_task_id和candidate_id是必需的。 - 无效的 UUID:
input_task_id不是有效的 UUID。 - 父任务未成功:所引用的原型任务尚未到达
SUCCEEDED。 - 没有候选方案:原型任务成功但未产生任何候选方案。
- 未知的候选方案:
candidate_id不是输入任务的候选方案之一。 - 参数超出范围:
options中的某个字段超出了其允许的范围或枚举集合。
- 缺少参数:
- Name
401 - Unauthorized- Description
身份验证失败。请检查你的 API key。
- Name
402 - Payment Required- Description
该账户处于免费计划(创建任务需要付费计划)或 credits 不足。
- Name
404 - Not Found- Description
所引用的原型任务不存在、属于其他用户,或是通过 webapp 创建的(只有 API 模式的原型任务才能链接到构建)。
- Name
429 - Too Many Requests- Description
你已超出速率限制。
- Name
500 - Internal Server Error- Description
发生了意外的服务器端错误——例如内容 moderation 服务不可用、暂存输入图像失败,或无法创建任务。这种情况下不会创建任何任务,因此重试是安全的。
Request
# 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"
}
获取 Keycap 任务
根据有效的任务 id 获取原型(prototype)或构建(build)任务。URL 路径必须与任务所处的阶段匹配——通过 /prototype/:id 获取的构建任务会返回 404,反之亦然。
有关响应结构,请参阅 Keycap 原型任务对象 和 Keycap 构建任务对象。
参数
- Name
- id
- Type
- path
- Description
要获取的 keycap 任务的唯一标识符。
返回
响应包含 keycap 任务对象。其结构取决于所请求的具体阶段。
Request
# 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=***"
}
}
删除 Keycap 任务
取消一个 keycap 任务。如果任务仍处于 PENDING 状态,则会退还创建时消耗的
credits。已经处于 IN_PROGRESS 状态的任务会被取消但不予退款(worker 可能已经在
消耗资源)。已经达到终态(SUCCEEDED、FAILED、CANCELED)的任务无法取消。
URL 路径必须与任务所处的阶段相匹配 —— 对 /prototype/:buildId 执行
DELETE 会返回 404。
路径参数
- Name
- id
- Type
- path
- Description
要取消的 keycap 任务的唯一标识符。
返回值
成功时返回 204 No Content,响应体为空。
失败模式
- Name
400 - Bad Request- Description
该任务已处于终态,无法取消。
- Name
404 - Not Found- Description
该任务不存在、属于其他用户,或其所处阶段与 URL 路径不匹配。
- Name
500 - Internal Server Error- Description
取消过程中发生了意外的服务器端错误。该任务可能已被取消,也可能未被取消 —— 请在重试前重新读取以确认。
Request
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).
流式获取 Keycap 任务
通过 Server-Sent Events(SSE)流式获取 keycap 任务的实时更新。
URL 路径必须与任务所处的阶段匹配 —— 在
/prototype/:buildId/stream 处打开流会发出一个带有
status_code: 404 的 event: error payload,随后关闭该流。
参数
- Name
- id
- Type
- path
- Description
要进行流式传输的 keycap 任务的唯一标识符。
返回
以 Server-Sent Events 的形式返回一个由
Keycap Prototype
或 Keycap Build 任务对象组成的流。
对于 PENDING 或 IN_PROGRESS 状态的任务,响应流中将只包含必要的
progress 和 status 字段。
Request
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.
// For PENDING or IN_PROGRESS tasks, the response stream will not include all fields.
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=***"
}
}
List Keycap Tasks
获取单个阶段中你的 keycap 任务的分页列表。URL 路径决定了阶段——/prototype 返回原型(prototype)任务;/build
返回构建(build)任务。另一个阶段的任务不会包含在任何一个响应中。
路径参数
- Name
- stage
- Type
- path
- 必选
- Description
prototype或build。该集合只返回阶段与 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 时返回
keycap 原型任务对象,
列出 /build 时返回
keycap 构建任务对象。
Request
# 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"
]
}
]
键帽原型任务对象
键帽原型任务(Keycap Prototype Task)对象是 Meshy 用于跟踪的一个工作单元,用于根据源照片生成一张成品键帽设计图。该阶段的输出会通过 input_task_id 和 candidate_id 串联到构建阶段。
属性
- Name
- id
- Type
- string
- Description
任务的唯一标识符。虽然我们在实现细节上使用 k-可排序的 UUID 作为任务 id,但你不应对 id 的格式做任何假设。
- Name
- type
- Type
- string
- Description
任务的类型。此值为
creative-lab-keycap-prototype。
- Name
- name
- Type
- string
- Description
创建任务时提供的任务名称。如果未提供名称,则为空字符串。
- Name
- status
- Type
- string
- Description
任务的状态。可能的取值为
PENDING、IN_PROGRESS、SUCCEEDED、FAILED、CANCELED之一。
- Name
- progress
- Type
- integer
- Description
任务的进度。如果任务尚未开始,此属性为
0。任务成功后,此值将变为100。
- Name
- created_at
- Type
- timestamp
- Description
任务创建时的时间戳,单位为毫秒。
时间戳表示自 1970 年 1 月 1 日 UTC 起经过的毫秒数,遵循 RFC 3339
标准。 例如,格林尼治标准时间 2023 年 9 月 1 日星期五中午 12:00:00 表示为1693569600000。这适用于 Meshy API 中的所有时间戳。
- 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
前置任务的数量。
此字段的值仅在任务状态为
PENDING时才有意义。
- Name
- task_error
- Type
- object
- Description
失败任务的错误详情。完整的
task_error对象参考请参见 Errors。
- Name
- consumed_credits
- Type
- integer
- Description
此任务消耗的 credits 数量。达到
SUCCEEDED状态的任务将按该阶段的全额收费。从未成功创建的任务(请求时出现4xx,包括 moderation 拒绝)完全不收费。达到FAILED状态的任务返回0——费用将被退还,包括异步 moderation 拦截的情况。通过DELETE取消任务仅在任务仍为PENDING状态时退款;已处于IN_PROGRESS状态的任务仍会被收费,因为相应的算力已经消耗。
- Name
- image_urls
- Type
- array of strings
- Description
成品键帽设计渲染图的可下载 URL——即该候选项作为成品键帽的效果图。仅包含一个条目;
image_urls[i]对应于candidate_ids[i]。在任务达到SUCCEEDED之前为空。该 URL 仅用于展示;构建 endpoint 使用的是candidate_ids,而非这些 URL。其 URL 生命周期与model_urls相同:经过签名、无需Authorization请求头、在expires_at之前有效,且在重新读取任务时保持不变。
- Name
- candidate_ids
- Type
- array of strings
- Description
不透明的候选项标识符,与
image_urls一一对应。请将与你所选设计相匹配的条目作为构建请求的candidate_id传入。请勿对这些 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"
]
}
键帽构建任务对象
键帽构建任务对象是 Meshy 用于跟踪的一个工作单元,用来根据成功的原型任务和选定的候选方案生成最终的带 texture 3D 键帽。单次构建会运行完整的流水线——白模生成、自动落座与切割、上色、装配以及导出。
属性
- Name
- id
- Type
- string
- Description
任务的唯一标识符。
- Name
- type
- Type
- string
- Description
任务的类型。其值为
creative-lab-keycap-build。
- Name
- name
- Type
- string
- Description
创建任务时提供的任务名称。如果未提供名称,则为空字符串。
- Name
- status
- Type
- string
- Description
任务的状态。可能的值为
PENDING、IN_PROGRESS、SUCCEEDED、FAILED、CANCELED之一。
- 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
此任务消耗的 credits 数量。达到
SUCCEEDED状态的任务将按其阶段收取全额费用。从未成功创建的任务(请求时返回4xx,包括 moderation 拒绝)完全不收费。达到FAILED状态的任务返回0——费用会被退还,包括异步 moderation 拦截的情况。通过DELETE取消任务仅在任务仍处于PENDING状态时才会退款;已处于IN_PROGRESS状态的任务仍会被收费,因为相关工作已经耗费。
- Name
- model_urls
- Type
- object
- Description
生成的模型文件的可下载 URL。GLB 和 OBJ 压缩包均以真实世界的毫米级比例、Y 轴朝上导出,键帽正面朝向 +Z 方向。mesh 分别命名为
keycap-head和keycap-base;当底座回退为图案填充时,还会存在第三个 meshkeycap-base-interior,用于表示卡柱空腔。请勿假定一定只有两个 mesh。这些是签名 URL:获取时无需携带
Authorization请求头。它们在expires_at(即finished_at之后 3 天)之前一直有效,在此期间重新读取任务将返回相同的 URL,而不是重新签名的 URL。请在此之前自行下载并保存这些文件——过期的链接无法刷新。- Name
glb- Type
- string
- Description
最终带 texture 的
model.glb的可下载 URL。
- Name
obj_zip- Type
- string
- Description
指向包含
model.obj、model.mtl以及其 MTL 实际引用的 texture PNG 文件的压缩包的可下载 URL。纯色底座只提供keycap-head.png;带图案的底座还会提供keycap-base.png。
- Name
- process_image_urls
- Type
- object
- Description
按种类分类的中间过程图像的可下载 URL。与
model_urls具有相同的 URL 生命周期:已签名、无需Authorization请求头、在expires_at之前有效,并且在重新读取任务时保持不变。目前会输出以下种类:head_design— 构建所使用的所选候选方案的设计图(始终存在)。composite— 所选候选方案的成品键帽展示渲染图(在可用时存在)。base_canvas— 绘制完成的键帽底座画布(在可用时存在)。
请将该键集合视为开放式的;未来可能会新增种类,且不会构成破坏性变更。
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=***"
}
}
端到端示例
完整流程:从一张照片创建原型,轮询直到状态变为
SUCCEEDED,从 candidate_ids 中选择一个候选项,使用该候选项创建构建任务,
轮询构建任务直到状态变为 SUCCEEDED,然后从 model_urls 下载 GLB
和 OBJ 压缩包。
该示例以编程方式选择了第一个候选项。在实际集成中,你应当将 image_urls
中的条目展示给最终用户,让他们进行选择;所选的索引与 candidate_ids 一一对应。
Complete flow
#!/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"