Creative Lab — 키캡 API

소스 사진을 두 단계에 걸쳐 풀 컬러 맞춤형 기계식 키보드 키캡으로 변환합니다. 프로토타입은 입력 사진에서 "완성된 키캡" 디자인 렌더를 생성합니다. 해당 렌더를 확인한 후, 빌드는 단일 실행에서 텍스처가 적용된 3D 키캡 모델로 변환합니다 — 화이트 모델 생성, 자동 배치 및 보정된 기본 자세에서의 절단, 전체 모델 색상화, 최종 조립이 모두 하나의 빌드 작업 내에서 이루어집니다. 두 단계는 input_task_idcandidate_id를 통해 연결됩니다.

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

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

키캡 프로토타입 작업 생성

소스 사진에서 완성된 키캡 디자인 렌더를 생성합니다. 작업 결과는 image_urls 배열(완성된 키캡의 디스플레이 렌더)과 병렬 candidate_ids 배열을 포함하며, 둘 다 단일 항목을 보유합니다. 원하는 결과가 아닐 경우 다른 렌더를 위해 이 엔드포인트를 다시 호출하세요 — 각 호출은 별도로 청구됩니다. candidate_id를 프로토타입 작업 ID와 함께 빌드 엔드포인트에 전달하세요. 응답 형식은 키캡 프로토타입 작업 객체를 참조하세요.

파라미터

  • Name
    image_url
    Type
    string
    필수
    Description

    Meshy가 키캡 디자인 이미지로 변환할 소스 사진입니다. 현재 .jpg, .jpeg, .png, .webp 형식을 지원합니다.

    형식은 URL의 파일 확장자가 아닌 이미지 데이터를 디코딩하여 감지됩니다 — 확장자가 없거나 리디렉션되는 URL도 바이트가 지원되는 형식으로 디코딩되면 작동합니다. HTTP 리디렉션이 따릅니다. EXIF 방향은 정규화되어, 회전된 휴대폰 사진도 보이는 그대로 사용됩니다.

    제한: 각 측면 최소 32 픽셀, 총 178,956,970 픽셀 이하, 다운로드 후 최대 20,000,000 바이트. 데이터 URI의 경우 제한은 디코딩된 바이트에 적용되므로 소스 파일 자체는 그 크기까지 가능 — base64 텍스트는 약 3분의 1 더 크며, 이는 요청 본문에 중요하지만 이 제한에는 해당되지 않습니다. 데이터 URI는 image/* 콘텐츠 타입과 ;base64를 선언해야 합니다.

    이미지를 제공하는 방법은 두 가지입니다:

    • 공개 접근 가능한 URL: 공용 인터넷에서 접근 가능한 URL.
    • 데이터 URI: 이미지의 base64 인코딩된 데이터 URI. 데이터 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로, 어떤 배경에도 합성할 수 있습니다.

    이는 디스플레이 렌더에만 적용됩니다. 빌드 엔드포인트가 사용하는 후보는 영향을 받지 않으므로 3D 결과는 동일합니다.

반환값

응답의 result 속성은 새로 생성된 키캡 프로토타입 작업의 작업 id를 포함합니다. 작업이 SUCCEEDED에 도달할 때까지 작업 가져오기 엔드포인트를 폴링하거나 스트림에 구독한 후, candidate_ids에서 항목을 가져와 작업 ID와 함께 빌드 엔드포인트에 전달하세요.

실패 모드

  • Name
    400 - Bad Request
    Description

    요청이 허용되지 않았습니다. 일반적인 원인:

    • 누락된 파라미터: image_url이 필요합니다.
    • 잘못된 이미지 형식: 제공된 image_url이 지원되지 않는 형식입니다(.jpg, .jpeg, .png, .webp).
    • 이미지 크기 범위 초과: 이미지가 너무 작거나 최대 파일 크기를 초과하거나 최대 픽셀 수를 초과합니다.
    • 접근할 수 없는 URL: image_url을 다운로드할 수 없습니다(404 또는 timeout).
    • 잘못된 데이터 URI: base64 문자열이 잘못되었습니다.
    • 콘텐츠 플래그됨: 입력 이미지가 NSFW moderation에 의해 플래그되었습니다.
  • Name
    401 - Unauthorized
    Description

    인증에 실패했습니다. API 키를 확인하세요.

  • Name
    402 - Payment Required
    Description

    계정이 무료 플랜에 있습니다(작업을 생성하려면 유료 플랜이 필요) 또는 크레딧이 부족합니다.

  • Name
    403 - Forbidden
    Description

    입력 이미지가 지적 재산 moderation에 의해 플래그되었습니다.

  • Name
    429 - Too Many Requests
    Description

    속도 제한을 초과했습니다.

  • Name
    500 - Internal Server Error
    Description

    예기치 않은 서버 측 오류가 발생했습니다 — 예를 들어 콘텐츠-moderation 서비스가 사용 불가하거나 입력 이미지 준비에 실패했거나 작업을 생성할 수 없었습니다. 이 경우 작업이 생성되지 않으므로 재시도가 안전합니다.

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

키캡 빌드 작업 생성

성공한 프로토타입 작업과 그 후보 중 하나로부터 최종 3D 텍스처 키캡 모델을 생성합니다. 단일 빌드 작업은 전체 파이프라인을 처음부터 끝까지 실행합니다 — 선택한 디자인으로부터 화이트 모델 생성, 캘리브레이션된 기본 포즈를 사용하여 키캡 베이스에 자동으로 배치 및 절단(상호작용 조정 불필요), 전체 모델 색칠, 최종 조립 및 내보내기. 빌드는 일반적으로 3–7분이 소요되며, 여러 빌드가 동시에 실행될 때 상한에 가까워집니다. 응답 형식은 키캡 빌드 작업 객체를 참조하세요.

파라미터

  • Name
    input_task_id
    Type
    string
    필수
    Description

    동일한 OpenAPI 엔드포인트를 통해 생성된 프로토타입 작업의 작업 ID입니다. 프로토타입은 동일한 Meshy 계정에 의해 생성되어야 하며, SUCCEEDED에 도달했으며 최소한 하나의 후보를 생성해야 합니다.

    웹앱을 통해 생성된 프로토타입 작업은 허용되지 않습니다 — 빌드 엔드포인트는 POST /openapi/creative-lab/keycap/v1/prototype에 의해 생성된 프로토타입 작업만을 허용하며, 다른 소스는 404로 거부됩니다.

  • Name
    candidate_id
    Type
    string
    필수
    Description

    성공한 프로토타입 작업의 candidate_ids 배열에서 가져온 빌드할 후보입니다. 해당 작업에 속해야 하며, 다른 값은 400으로 거부됩니다.

  • Name
    name
    Type
    string
    Description

    표시 목적으로 선택적인 작업 이름입니다. 최대 100자.

options

선택적인 지오메트리 조정. 모든 필드는 캘리브레이션된 기본값을 가지고 있으며, 덮어쓰고 싶은 것만 전송하세요.

  • Name
    base_model
    Type
    string
    기본값 cherry-mx-1x1-r1
    Description

    빌드할 키캡 베이스입니다. 현재 사용 가능한 유일한 값은 cherry-mx-1x1-r1이며, 표준 Cherry MX 프로파일 1u 키캡입니다. 3–5개의 추가 주류 표준 크기가 계획되어 있으며, 사용자 정의 크기는 지원되지 않습니다.

  • Name
    head_size_mm
    Type
    number
    기본값 23
    Description

    조각된 헤드의 목표 크기, 밀리미터 단위: 가장 긴 치수가 이 값으로 스케일됩니다. 범위: [10, 40]. 대략 32.9 이상의 값은 베이스의 보호 발자국 제한에 맞도록 줄어들 수 있으며, 따라서 전달된 가장 긴 치수는 요청된 것보다 작을 수 있습니다. 적용된 값은 오늘날 작업 객체에 반영되지 않으며, 실제로 받은 크기를 확인하려면 다운로드한 모델의 keycap-head 메시의 바운딩 박스를 측정하세요.

  • Name
    vertical_offset_mm
    Type
    number
    기본값 0
    Description

    베이스에 배치되기 전에 헤드에 적용되는 수직 오프셋, 밀리미터 단위. 범위: [-5, 5].

반환

응답의 result 속성에는 새로 생성된 키캡 빌드 작업의 작업 id가 포함됩니다. 작업이 SUCCEEDED에 도달할 때까지 작업 가져오기 엔드포인트를 폴링하거나 스트림에 구독한 후 model_urls.glbmodel_urls.obj_zip에서 아티팩트를 다운로드하세요.

실패 모드

  • Name
    400 - Bad Request
    Description

    요청이 허용되지 않았습니다. 일반적인 원인:

    • 누락된 파라미터: input_task_idcandidate_id는 필수입니다.
    • 잘못된 UUID: input_task_id가 유효한 UUID가 아닙니다.
    • 부모가 성공하지 않음: 참조된 프로토타입 작업이 아직 SUCCEEDED에 도달하지 않았습니다.
    • 후보 없음: 프로토타입 작업이 성공했지만 후보를 생성하지 않았습니다.
    • 알 수 없는 후보: candidate_id가 입력 작업의 후보 중 하나가 아닙니다.
    • 범위를 벗어난 옵션: options 필드 중 하나가 허용된 범위 또는 열거형 세트를 벗어났습니다.
  • Name
    401 - Unauthorized
    Description

    인증에 실패했습니다. API 키를 확인하세요.

  • Name
    402 - Payment Required
    Description

    계정이 무료 플랜에 있거나 (작업을 생성하려면 유료 플랜이 필요합니다) 크레딧이 부족합니다.

  • Name
    404 - Not Found
    Description

    참조된 프로토타입 작업이 존재하지 않거나, 다른 사용자에게 속하거나, 웹앱을 통해 생성되었습니다 (API 모드 프로토타입 작업만 빌드로 연결됩니다).

  • Name
    429 - Too Many Requests
    Description

    속도 제한을 초과했습니다.

  • Name
    500 - Internal Server Error
    Description

    예기치 않은 서버 측 오류가 발생했습니다 — 예를 들어 콘텐츠 모더레이션 서비스가 사용 불가능하거나, 입력 이미지 준비에 실패했거나, 작업을 생성할 수 없었습니다. 이 경우 작업이 생성되지 않으므로 다시 시도해도 안전합니다.

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

키캡 작업 검색

유효한 작업 id가 주어졌을 때 프로토타입 또는 빌드 작업을 검색합니다. URL 경로는 작업의 단계와 일치해야 합니다 — /prototype/:id를 통해 가져온 빌드 작업은 404를 반환하며, 그 반대의 경우도 마찬가지입니다.

응답 형식은 키캡 프로토타입 작업 객체키캡 빌드 작업 객체를 참조하세요.

매개변수

  • Name
    id
    Type
    path
    Description

    검색할 키캡 작업의 고유 식별자입니다.

반환값

응답에는 키캡 작업 객체가 포함됩니다. 요청된 단계에 따라 형식이 달라집니다.

Request

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

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

Prototype Response

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

Build Response

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

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

키캡 작업 삭제

키캡 작업을 취소합니다. 작업이 아직 PENDING 상태인 경우, 생성 시 소모된 크레딧이 환불됩니다. 이미 IN_PROGRESS 상태인 작업은 환불 없이 취소됩니다 (작업자가 이미 리소스를 소모하고 있을 수 있습니다). 이미 최종 상태 (SUCCEEDED, FAILED, CANCELED)에 도달한 작업은 취소할 수 없습니다.

URL 경로는 작업의 단계와 일치해야 합니다 — /prototype/:buildId에서 DELETE404를 반환합니다.

경로 매개변수

  • Name
    id
    Type
    path
    Description

    취소할 키캡 작업의 고유 식별자입니다.

반환값

성공 시 빈 본문과 함께 204 No Content를 반환합니다.

실패 모드

  • Name
    400 - Bad Request
    Description

    작업이 이미 최종 상태에 있으며 취소할 수 없습니다.

  • Name
    404 - Not Found
    Description

    작업이 존재하지 않거나, 다른 사용자에게 속해 있거나, 단계가 URL 경로와 일치하지 않습니다.

  • Name
    500 - Internal Server Error
    Description

    취소하는 동안 예기치 않은 서버 측 오류가 발생했습니다. 작업이 취소되었는지 여부는 불확실하므로 다시 읽어 확인한 후 재시도하십시오.

Request

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

Response

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

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

키캡 작업 스트리밍

Server-Sent Events (SSE)를 통해 키캡 작업의 실시간 업데이트를 스트리밍합니다. URL 경로는 작업의 단계와 일치해야 합니다 — /prototype/:buildId/stream에서 스트림을 열면 status_code: 404와 함께 단일 event: error 페이로드가 전송되고 스트림이 닫힙니다.

매개변수

  • Name
    id
    Type
    path
    Description

    스트리밍할 키캡 작업의 고유 식별자입니다.

반환값

키캡 프로토타입 또는 키캡 빌드 작업 객체를 Server-Sent Events로 스트리밍합니다. PENDING 또는 IN_PROGRESS 작업의 경우, 응답 스트림은 필요한 progressstatus 필드만 포함합니다.

Request

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

Response Stream

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

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

키캡 작업 목록

단일 단계에 대한 키캡 작업의 페이지네이션된 목록을 검색합니다. URL 경로는 단계를 선택합니다 — /prototype은 프로토타입 작업을 반환하고, /build는 빌드 작업을 반환합니다. 다른 단계의 작업은 어느 응답에도 포함되지 않습니다.

경로 매개변수

  • Name
    stage
    Type
    path
    필수
    Description

    prototype 또는 build 중 하나입니다. 컬렉션은 URL과 일치하는 단계의 작업만 반환합니다 — /prototype을 가져오면 빌드 작업은 절대 반환되지 않으며 그 반대도 마찬가지입니다.

쿼리 매개변수

  • 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을 나열할 때는 키캡 프로토타입 작업 객체를, /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"
    ]
  }
]

키캡 프로토타입 작업 객체

키캡 프로토타입 작업 객체는 Meshy가 소스 사진으로부터 하나의 완성된 키캡 디자인 이미지를 생성하기 위해 추적하는 작업 단위입니다. 이 단계의 출력물은 input_task_idcandidate_id를 통해 빌드 단계로 연결됩니다.

속성

  • Name
    id
    Type
    string
    Description

    작업의 고유 식별자입니다. 작업 ID에 대해 k-정렬 가능한 UUID를 구현 세부사항으로 사용하지만, 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

    작업이 생성된 시점의 타임스탬프입니다(밀리초 단위).

  • Name
    started_at
    Type
    timestamp
    Description

    작업이 시작된 시점의 타임스탬프입니다(밀리초 단위). 작업이 아직 시작되지 않은 경우 이 속성은 0입니다.

  • Name
    finished_at
    Type
    timestamp
    Description

    작업이 완료된 시점의 타임스탬프입니다(밀리초 단위). 작업이 아직 완료되지 않은 경우 이 속성은 0입니다.

  • Name
    expires_at
    Type
    timestamp
    Description

    작업 결과가 만료되는 시점의 타임스탬프입니다(밀리초 단위).

  • Name
    preceding_tasks
    Type
    integer
    Description

    이전 작업의 수입니다.

  • Name
    task_error
    Type
    object
    Description

    실패한 작업에 대한 오류 세부사항입니다. 전체 task_error 객체 참조는 오류를 참조하세요.

  • Name
    consumed_credits
    Type
    integer
    Description

    이 작업에 의해 소비된 크레딧의 수입니다. 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은 표시용이며, 빌드 엔드포인트는 candidate_ids를 소비하며, 이러한 URL은 소비하지 않습니다. model_urls와 동일한 URL 수명 주기를 가집니다: 서명됨, 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"
  ]
}

키캡 빌드 작업 객체

키캡 빌드 작업 객체는 성공한 프로토타입 작업과 선택된 후보로부터 최종 텍스처가 적용된 3D 키캡을 생성하기 위해 Meshy가 추적하는 작업 단위입니다. 단일 빌드는 전체 파이프라인을 실행합니다 — 화이트 모델 생성, 자동 배치 및 절단, 색상 지정, 조립 및 내보내기.

속성

  • 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 객체 참조는 오류를 참조하세요.

  • Name
    consumed_credits
    Type
    integer
    Description

    이 작업에 소비된 크레딧의 수입니다. SUCCEEDED에 도달한 작업은 해당 단계에 대한 전체 금액이 청구됩니다. 생성되지 않은 작업(요청 시 4xx, 포함하여 moderation 거부)은 전혀 청구되지 않습니다. FAILED에 도달한 작업은 0을 반환합니다 — 청구가 환불되며, 비동기 moderation 차단도 포함됩니다. DELETE를 통해 취소하면 작업이 여전히 PENDING일 때만 환불됩니다; 이미 IN_PROGRESS인 작업은 청구가 유지됩니다, 작업이 이미 진행 중이기 때문입니다.

  • Name
    model_urls
    Type
    object
    Description

    생성된 모델 아티팩트의 다운로드 가능한 URL입니다. GLB와 OBJ 번들은 실제 세계 밀리미터 스케일, Y-up으로 내보내지며, 키캡의 앞면은 +Z를 향합니다. 메시들은 keycap-headkeycap-base로 명명됩니다; 베이스가 패턴 채우기로 대체될 경우, 세 번째 메시 keycap-base-interior도 스템 캐비티에 대해 존재합니다. 정확히 두 개의 메시가 있다고 가정하지 마세요.

    이들은 서명된 URL입니다: Authorization 헤더 없이 가져오세요. 이들은 expires_at까지 유효하며, 이는 finished_at 이후 3일입니다. 그 기간 내에 작업을 다시 읽으면 새로 서명된 것이 아닌 동일한 URL을 반환합니다. 그 전에 파일을 다운로드하고 저장하세요 — 만료된 링크를 새로 고칠 방법은 없습니다.

    • Name
      glb
      Type
      string
      Description

      최종 텍스처가 적용된 model.glb의 다운로드 가능한 URL입니다.

    • Name
      obj_zip
      Type
      string
      Description

      model.obj, model.mtl, 및 MTL이 실제로 참조하는 텍스처 PNG를 포함하는 zip 번들의 다운로드 가능한 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와 1:1로 매핑됩니다.

전체 흐름

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"