{"openapi":"3.0.0","paths":{"/v1/images":{"post":{"operationId":"PublicApiController_generateImage","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateImageDto"}}}},"responses":{"201":{"description":""}},"summary":"텍스트 → 이미지 생성.\n- JSON: `{ prompt, model?, aspectRatio?, referenceImages?: [url] }` (URL 레퍼런스).\n- multipart/form-data: `prompt`/`model`/`aspectRatio` 폼 필드 + `referenceFiles`\n  로컬 이미지 파일(≤4, 각 ≤20MB). multer 가 JSON 본문 10MB 한도와 별개로\n  스트리밍 처리하고, non-multipart 요청은 건너뛰므로 기존 JSON 클라이언트 무영향.","tags":["Public API v1"]}},"/v1/models/from-text":{"post":{"operationId":"PublicApiController_generateModelFromText","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateModelFromTextDto"}}}},"responses":{"201":{"description":""}},"summary":"텍스트 → 3D 모델 생성.","tags":["Public API v1"]}},"/v1/models/from-image":{"post":{"operationId":"PublicApiController_generateModelFromImage","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateModelFromImageDto"}}}},"responses":{"201":{"description":""}},"summary":"이미지 → 3D 모델 생성.\n- JSON: `{ imageUrl, engine?, polycount?, texture? }` (URL 입력).\n- multipart/form-data: 폼 필드 + `image` 로컬 이미지 파일(≤20MB) — 호스팅 불필요.","tags":["Public API v1"]}},"/v1/assets":{"get":{"operationId":"PublicApiController_listAssets","parameters":[{"name":"page","required":false,"in":"query","description":"페이지 (1부터). 기본 1.","schema":{"minimum":1,"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"페이지 크기 (최대 100). 기본 20.","schema":{"minimum":1,"maximum":100,"example":20,"type":"number"}},{"name":"category","required":false,"in":"query","description":"카테고리 필터. all(기본) | 3d | image | remesh | texture | animation | palette.","schema":{"example":"3d","type":"string","enum":["all","3d","image","remesh","texture","animation","palette"]}},{"name":"keyword","required":false,"in":"query","description":"이름 부분 일치 검색.","schema":{"maxLength":255,"example":"dragon","type":"string"}}],"responses":{"200":{"description":""}},"summary":"내 자산 목록 (최신순, owner-scoped). 단건 폴링은 GET /v1/assets/:id.\n`?page=&limit=&category=3d|image|...&keyword=` — 라이브러리 브라우징/싱크용.\n정적 경로이므로 `assets/:id` 보다 먼저 선언(Nest 가 'assets' 를 id 로 오인 X).","tags":["Public API v1"]}},"/v1/assets/{id}":{"get":{"operationId":"PublicApiController_getAsset","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"생성 자산 상태/결과 조회. taskStatus: 0=대기 1=진행중 2=완료 3=실패.\n완료 시 files.{model,image,thumbnail,textures} 에 서명된 결과 URL.","tags":["Public API v1"]}},"/v1/assets/{id}/download":{"post":{"operationId":"PublicApiController_download","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DownloadAssetV1Dto"}}}},"responses":{"201":{"description":""}},"summary":"완료된 자산을 glb/fbx/obj 로 내보내 서명 다운로드 URL 반환.","tags":["Public API v1"]}},"/v1/assets/{id}/remesh":{"post":{"operationId":"PublicApiController_remeshAsset","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemeshAssetDto"}}}},"responses":{"201":{"description":""}},"summary":"리메시 — 기존 3D 자산(:id)을 리토폴로지해 새 자산 생성.","tags":["Public API v1"]}},"/v1/assets/{id}/texture":{"post":{"operationId":"PublicApiController_textureAsset","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TextureAssetDto"}}}},"responses":{"201":{"description":""}},"summary":"텍스처 — 기존 3D 자산(:id)에 PBR 텍스처 재생성해 새 자산 생성.","tags":["Public API v1"]}},"/v1/assets/{id}/animate":{"post":{"operationId":"PublicApiController_animateAsset","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnimateAssetDto"}}}},"responses":{"201":{"description":""}},"summary":"애니메이션 — 기존 3D 자산(:id)을 자동 리깅(+리타겟)해 새 자산 생성.","tags":["Public API v1"]}},"/v1/models":{"get":{"operationId":"PublicApiController_listModels","parameters":[{"name":"category","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"사용 가능한 모델/엔진 목록. category=3d(기본) | image | remesh | texture | animate.","tags":["Public API v1"]}},"/v1/animations":{"get":{"operationId":"PublicApiController_listAnimations","parameters":[{"name":"engine","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"애니메이션 프리셋 목록 — animate 의 `preset` 으로 쓸 id.\n`?engine=tripo`(기본) | `meshy`. 엔진별 프리셋은 서로 호환 안 됨.","tags":["Public API v1"]}},"/v1/credits":{"get":{"operationId":"PublicApiController_getCredits","parameters":[],"responses":{"200":{"description":""}},"summary":"현재 크레딧 잔액 + 플랜.","tags":["Public API v1"]}},"/v1/collections":{"post":{"operationId":"PublicApiController_createCollection","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCollectionV1Dto"}}}},"responses":{"201":{"description":""}},"tags":["Public API v1"]},"get":{"operationId":"PublicApiController_listCollections","parameters":[],"responses":{"200":{"description":""}},"summary":"내 컬렉션 목록.","tags":["Public API v1"]}},"/v1/collections/{id}/assets":{"get":{"operationId":"PublicApiController_listCollectionAssets","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","description":"페이지 (1부터). 기본 1.","schema":{"minimum":1,"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"페이지 크기 (최대 100). 기본 20.","schema":{"minimum":1,"maximum":100,"example":20,"type":"number"}}],"responses":{"200":{"description":""}},"summary":"컬렉션 안 자산 목록 (페이지네이션).","tags":["Public API v1"]},"post":{"operationId":"PublicApiController_addCollectionAssets","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionAssetsV1Dto"}}}},"responses":{"201":{"description":""}},"summary":"컬렉션에 자산 추가.","tags":["Public API v1"]}},"/v1/collections/{id}/assets/remove":{"post":{"operationId":"PublicApiController_removeCollectionAssets","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionAssetsV1Dto"}}}},"responses":{"201":{"description":""}},"summary":"컬렉션에서 자산 제거.","tags":["Public API v1"]}},"/v1/collections/{id}":{"patch":{"operationId":"PublicApiController_updateCollection","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCollectionV1Dto"}}}},"responses":{"200":{"description":""}},"summary":"컬렉션 이름 변경.","tags":["Public API v1"]},"delete":{"operationId":"PublicApiController_deleteCollection","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"컬렉션 삭제.","tags":["Public API v1"]}}},"info":{"title":"PicoBerry API","description":"PicoBerry Generation API — public v1 surface","version":"1.0.0","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"access-token":{"scheme":"bearer","bearerFormat":"JWT","type":"http","name":"JWT","in":"header"}},"schemas":{"GenerateImageDto":{"type":"object","properties":{"callbackUrl":{"type":"string","maxLength":2048,"format":"uri","description":"완료/실패 통지를 받을 콜백 URL(http/https, 공인 호스트만 — 사설/내부 IP 는 거부). 지정 시 폴링 없이 PicoBerry 가 POST. payload: { event, deliveryId, createdAt, data(=GET /v1/assets 동일) }.","example":"https://example.com/webhooks/picoberry"},"webhookSecret":{"type":"string","maxLength":255,"description":"HMAC 서명 시크릿(선택, 권장). 지정 시 webhook 본문이 `X-PB-Signature: t=<unix>,v1=<hex>` 헤더로 서명됨(HMAC-SHA256 of `<t>.<body>`) — 수신측이 동일 secret 으로 진위·replay 검증."},"prompt":{"type":"string","maxLength":5000,"description":"이미지 생성 프롬프트 (최대 5000자)","example":"a low-poly medieval wooden barrel, game asset"},"model":{"type":"string","description":"모델 name. 생략 시 기본 모델. 사용 가능 목록은 GET /v1/models?category=image (예: 'nano-banana', 'gpt-image-2')."},"aspectRatio":{"type":"string","description":"종횡비 (예: '1:1', '16:9', '9:16'). 모델별 지원 범위는 GET /v1/models 의 supportedAspectRatios 참고.","example":"1:1"},"referenceImages":{"maxItems":4,"description":"레퍼런스 이미지 URL (최대 4개, http/https). 프롬프트와 함께 시각 가이드로 전달 — 각 URL 은 다운로드→GCS 업로드 후 모델에 넘긴다. nano-banana 권장.","type":"array","items":{"type":"string","format":"uri"}},"license":{"enum":["cc0","cc-by-4.0","cc-by-nc-4.0","all-rights-reserved"],"type":"string","description":"생성물 라이선스 (기본 all-rights-reserved=Private, 오버라이드 가능)"}},"required":["prompt"]},"GenerateModelFromTextDto":{"type":"object","properties":{"callbackUrl":{"type":"string","maxLength":2048,"format":"uri","description":"완료/실패 통지를 받을 콜백 URL(http/https, 공인 호스트만 — 사설/내부 IP 는 거부). 지정 시 폴링 없이 PicoBerry 가 POST. payload: { event, deliveryId, createdAt, data(=GET /v1/assets 동일) }.","example":"https://example.com/webhooks/picoberry"},"webhookSecret":{"type":"string","maxLength":255,"description":"HMAC 서명 시크릿(선택, 권장). 지정 시 webhook 본문이 `X-PB-Signature: t=<unix>,v1=<hex>` 헤더로 서명됨(HMAC-SHA256 of `<t>.<body>`) — 수신측이 동일 secret 으로 진위·replay 검증."},"prompt":{"type":"string","maxLength":1024,"description":"텍스트→3D 생성 프롬프트 (최대 1024자 — Tripo 엔진 제한)","example":"a stylized treasure chest, game ready"},"engine":{"type":"string","description":"엔진/모델 name. 생략 시 기본 엔진. 사용 가능 목록은 GET /v1/models?category=3d (예: 'tripo', 'tripo-v3.1', 'hunyuan-3.1')."},"polycount":{"type":"number","minimum":100,"maximum":2000000,"description":"목표 폴리곤 수. 모델별 지원 범위는 GET /v1/models 의 polygonConfig 참고 — 범위를 벗어난 값은 해당 모델의 범위로 자동 보정(clamp)된다 (예: tripo 는 500~20,000)."},"texture":{"type":"boolean","description":"텍스처(PBR) 생성 여부. 기본 true."},"license":{"enum":["cc0","cc-by-4.0","cc-by-nc-4.0","all-rights-reserved"],"type":"string","description":"생성물 라이선스 (기본 all-rights-reserved=Private, 오버라이드 가능)"}},"required":["prompt"]},"GenerateModelFromImageDto":{"type":"object","properties":{"callbackUrl":{"type":"string","maxLength":2048,"format":"uri","description":"완료/실패 통지를 받을 콜백 URL(http/https, 공인 호스트만 — 사설/내부 IP 는 거부). 지정 시 폴링 없이 PicoBerry 가 POST. payload: { event, deliveryId, createdAt, data(=GET /v1/assets 동일) }.","example":"https://example.com/webhooks/picoberry"},"webhookSecret":{"type":"string","maxLength":255,"description":"HMAC 서명 시크릿(선택, 권장). 지정 시 webhook 본문이 `X-PB-Signature: t=<unix>,v1=<hex>` 헤더로 서명됨(HMAC-SHA256 of `<t>.<body>`) — 수신측이 동일 secret 으로 진위·replay 검증."},"imageUrl":{"type":"string","format":"uri","description":"입력 이미지 URL (http/https). 로컬 파일은 multipart/form-data 의 `image` 파트로 업로드. PB 생성 이미지의 files.image 서명 URL 도 사용 가능."},"engine":{"type":"string","description":"엔진 name. 생략 시 기본. 목록은 GET /v1/models?category=3d (예: 'tripo', 'hunyuan-3.1')."},"polycount":{"type":"number","minimum":100,"maximum":2000000,"description":"목표 폴리곤 수. 모델별 지원 범위는 GET /v1/models 의 polygonConfig 참고 — 범위를 벗어난 값은 해당 모델의 범위로 자동 보정(clamp)된다 (예: tripo 는 500~20,000)."},"texture":{"type":"boolean","description":"텍스처(PBR) 생성 여부. 기본 true."},"license":{"enum":["cc0","cc-by-4.0","cc-by-nc-4.0","all-rights-reserved"],"type":"string","description":"생성물 라이선스 (기본 all-rights-reserved=Private, 오버라이드 가능)"}}},"DownloadAssetV1Dto":{"type":"object","properties":{"format":{"type":"string","enum":["glb","fbx","obj"],"description":"다운로드 포맷"},"texturePreset":{"type":"object","enum":["standard","unity"],"description":"텍스처 패킹 (fbx/obj). 'unity' = Unity URP/Built-in 용 채널 분리(.meta 동봉). 기본 standard."},"name":{"type":"string","maxLength":100,"description":"내보낼 파일 기본 이름. 생략 시 \"model\"."}},"required":["format"]},"RemeshAssetDto":{"type":"object","properties":{"callbackUrl":{"type":"string","maxLength":2048,"format":"uri","description":"완료/실패 통지를 받을 콜백 URL(http/https, 공인 호스트만 — 사설/내부 IP 는 거부). 지정 시 폴링 없이 PicoBerry 가 POST. payload: { event, deliveryId, createdAt, data(=GET /v1/assets 동일) }.","example":"https://example.com/webhooks/picoberry"},"webhookSecret":{"type":"string","maxLength":255,"description":"HMAC 서명 시크릿(선택, 권장). 지정 시 webhook 본문이 `X-PB-Signature: t=<unix>,v1=<hex>` 헤더로 서명됨(HMAC-SHA256 of `<t>.<body>`) — 수신측이 동일 secret 으로 진위·replay 검증."},"engine":{"type":"string","description":"엔진(task name). 생략 시 기본. 목록: GET /v1/models?category=remesh (예: 'pb-remesh', 'tripo-remesh', 'tripo-remesh-quad', 'meshy-remesh', 'hunyuan-remesh')."},"polycount":{"type":"number","minimum":100,"maximum":2000000,"description":"목표 폴리곤 수. pb-remesh 는 500~500,000."},"license":{"enum":["cc0","cc-by-4.0","cc-by-nc-4.0","all-rights-reserved"],"type":"string","description":"생성물 라이선스 (기본 all-rights-reserved=Private, 오버라이드 가능)"}}},"TextureAssetDto":{"type":"object","properties":{"callbackUrl":{"type":"string","maxLength":2048,"format":"uri","description":"완료/실패 통지를 받을 콜백 URL(http/https, 공인 호스트만 — 사설/내부 IP 는 거부). 지정 시 폴링 없이 PicoBerry 가 POST. payload: { event, deliveryId, createdAt, data(=GET /v1/assets 동일) }.","example":"https://example.com/webhooks/picoberry"},"webhookSecret":{"type":"string","maxLength":255,"description":"HMAC 서명 시크릿(선택, 권장). 지정 시 webhook 본문이 `X-PB-Signature: t=<unix>,v1=<hex>` 헤더로 서명됨(HMAC-SHA256 of `<t>.<body>`) — 수신측이 동일 secret 으로 진위·replay 검증."},"prompt":{"type":"string","maxLength":1000,"description":"텍스처 프롬프트(텍스트). 생략 시 엔진이 모델 기준으로 재텍스처.","example":"weathered bronze with green patina"},"engine":{"type":"string","description":"엔진(task name). 생략 시 기본. 목록: GET /v1/models?category=texture (예: 'tripo-texture', 'meshy-texture', 'hunyuan-texture')."},"license":{"enum":["cc0","cc-by-4.0","cc-by-nc-4.0","all-rights-reserved"],"type":"string","description":"생성물 라이선스 (기본 all-rights-reserved=Private, 오버라이드 가능)"}}},"AnimateAssetDto":{"type":"object","properties":{"callbackUrl":{"type":"string","maxLength":2048,"format":"uri","description":"완료/실패 통지를 받을 콜백 URL(http/https, 공인 호스트만 — 사설/내부 IP 는 거부). 지정 시 폴링 없이 PicoBerry 가 POST. payload: { event, deliveryId, createdAt, data(=GET /v1/assets 동일) }.","example":"https://example.com/webhooks/picoberry"},"webhookSecret":{"type":"string","maxLength":255,"description":"HMAC 서명 시크릿(선택, 권장). 지정 시 webhook 본문이 `X-PB-Signature: t=<unix>,v1=<hex>` 헤더로 서명됨(HMAC-SHA256 of `<t>.<body>`) — 수신측이 동일 secret 으로 진위·replay 검증."},"engine":{"type":"string","description":"엔진(task name). 생략 시 기본. 목록: GET /v1/models?category=animate. '-rig-animate' 는 preset 으로 클립 적용, '-rig' 는 리깅만 (예: 'tripo-rig-animate', 'tripo-rig', 'meshy-rig-animate', 'meshy-rig')."},"preset":{"type":"string","maxLength":64,"description":"애니메이션 프리셋 id ('-rig-animate' 엔진). 목록: GET /v1/animations?engine=tripo|meshy. 엔진별 접두(preset:/meshy:) 자동 처리. 생략 시 리깅만.","example":"walk"},"license":{"enum":["cc0","cc-by-4.0","cc-by-nc-4.0","all-rights-reserved"],"type":"string","description":"생성물 라이선스 (기본 all-rights-reserved=Private, 오버라이드 가능)"}}},"CreateCollectionV1Dto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"description":"컬렉션 이름","example":"Dungeon Pack"},"parentId":{"type":"string","description":"상위 컬렉션 id (중첩 시 생략 가능)."}},"required":["name"]},"CollectionAssetsV1Dto":{"type":"object","properties":{"assetIds":{"minItems":1,"maxItems":200,"description":"자산 id 목록 (최대 200).","type":"array","items":{"type":"string"}}},"required":["assetIds"]},"UpdateCollectionV1Dto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255,"description":"새 컬렉션 이름."}}}}},"security":[{"access-token":[]}]}