소스 사진을 두 단계에 걸쳐 풀 컬러 맞춤형 기계식 키보드 키캡으로 변환합니다. 프로토타입은 입력 사진에서 "완성된 키캡" 디자인 렌더를 생성합니다. 해당 렌더를 확인한 후, 빌드는 단일 실행에서 텍스처가 적용된 3D 키캡 모델로 변환합니다 — 화이트 모델 생성, 자동 배치 및 보정된 기본 자세에서의 절단, 전체 모델 색상화, 최종 조립이 모두 하나의 빌드 작업 내에서 이루어집니다. 두 단계는 input_task_id와 candidate_id를 통해 연결됩니다.
POST /openapi/creative-lab/keycap/v1/prototype
POST /openapi/creative-lab/keycap/v1/build
두 POST endpoint는 유료 구독 플랜이 필요합니다. 무료 플랜 계정의 요청은 402 Payment Required로 거부됩니다.
소스 사진에서 완성된 키캡 디자인 렌더를 생성합니다. 작업 결과는 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 rendercurlhttps://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype \-XPOST \-H"Authorization: Bearer ${YOUR_API_KEY}" \-H'Content-Type: application/json' \-d'{ "image_url": "<your publicly accessible image url or base64-encoded data URI>" }'
성공한 프로토타입 작업과 그 후보 중 하나로부터 최종 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.glb 및 model_urls.obj_zip에서 아티팩트를 다운로드하세요.
GLB 및 OBJ 번들은 실제 세계 밀리미터 스케일로 내보내지며, Y-up 좌표계와 키캡의 앞면이 +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 키를 확인하세요.
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 keycapcurlhttps://api.meshy.ai/openapi/creative-lab/keycap/v1/build \-XPOST \-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 } }'
키캡 작업을 취소합니다. 작업이 아직 PENDING 상태인 경우, 생성 시 소모된 크레딧이 환불됩니다. 이미 IN_PROGRESS 상태인 작업은 환불 없이 취소됩니다 (작업자가 이미 리소스를 소모하고 있을 수 있습니다). 이미 최종 상태 (SUCCEEDED, FAILED, CANCELED)에 도달한 작업은 취소할 수 없습니다.
키캡 프로토타입 작업 객체는 Meshy가 소스 사진으로부터 하나의 완성된 키캡 디자인 이미지를 생성하기 위해 추적하는 작업 단위입니다. 이 단계의 출력물은 input_task_id와 candidate_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
작업이 생성된 시점의 타임스탬프입니다(밀리초 단위).
타임스탬프는 1970년 1월 1일 UTC 이후 경과된 밀리초 수를 나타내며, RFC 3339 표준을 따릅니다. 예를 들어, 2023년 9월 1일 금요일 오후 12:00:00 GMT는 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 객체 참조는 오류를 참조하세요.
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의 형식에 대해 어떤 가정도 하지 않아야 합니다.
키캡 빌드 작업 객체는 성공한 프로토타입 작업과 선택된 후보로부터 최종 텍스처가 적용된 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-head와 keycap-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 — 페인트된 키캡 베이스 캔버스 (사용 가능한 경우 존재).
키 세트를 개방형으로 취급하세요; 새로운 종류가 추가되어도 호환성 문제가 발생하지 않습니다.
전체 흐름: 사진에서 프로토타입을 생성하고, 이를 SUCCEEDED로 폴링하고,
candidate_ids에서 후보를 선택하고, 그 후보로 빌드를 생성하고,
빌드를 SUCCEEDED로 폴링한 다음, model_urls에서 GLB와 OBJ 번들을 다운로드합니다.
이 예제는 첫 번째 후보를 프로그래밍 방식으로 선택합니다. 실제 통합에서는 image_urls 항목을 최종 사용자에게 표시하고 그들이 선택하도록 해야 합니다. 선택된 인덱스는 candidate_ids와 1:1로 매핑됩니다.
전체 흐름
POST
/openapi/creative-lab/keycap/v1
#!/usr/bin/env bashset-euopipefail# 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:-}" ]]; thenecho"export IMAGE_PATH (local file) or IMAGE_URL (public url) first">&2exit1fiBASE="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 bodyshift2 out=$(curl--silent--show-error--max-time60--write-out$'\n%{http_code}' \-X"$method""$url"-H"$AUTH""$@") ||return1 http_code=${out##*$'\n'} body=${out%$'\n'*}if ((http_code >=400)); thenecho"HTTP $http_code for $url: $body">&2return1fiprintf'%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:; doif (($(date +%s) >= deadline)); thenecho"gave up waiting for $kind $id">&2return1fi task_status=$(apiGET"$BASE/$kind/$id"|jq-r'.status')echo"$kind: $task_status"case"$task_status"inSUCCEEDED)return0 ;;FAILED|CANCELED)return1 ;;esacsleep"$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"'EXITif [[ -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')"inpng) 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"elseprintf'{"image_url":"%s"}'"$IMAGE_URL">"$BODY"fi# 1. Create the prototype taskPROTO_ID=$(apiPOST"$BASE/prototype" \-H'Content-Type: application/json'--data-binary@"$BODY"|jq-r'.result')# 2. Wait for the design renderpollprototype"$PROTO_ID"# 3. Pick a candidate (first one here; show image_urls to a user in production)CANDIDATE_ID=$(apiGET"$BASE/prototype/$PROTO_ID"|jq-r'.candidate_ids[0]')# 4. Create the build taskjq-n--argp"$PROTO_ID"--argc"$CANDIDATE_ID" \'{input_task_id: $p, candidate_id: $c}'>"$BODY"BUILD_ID=$(apiPOST"$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)pollbuild"$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=$(apiGET"$BASE/build/$BUILD_ID")curl--silent--show-error--fail--max-time900 \-okeycap.glb"$(jq-r '.model_urls.glb' <<<"$TASK")"curl--silent--show-error--fail--max-time900 \-okeycap-obj.zip"$(jq-r '.model_urls.obj_zip' <<<"$TASK")"echo"Done: keycap.glb + keycap-obj.zip"