도움말 / 솜씨 API v1
솜씨 API v1
연결한 솜씨 계정의 크레딧으로 솜씨 쇼츠(9:16 세로 영상), 솜씨 이미지(세트 10장), 솜씨 시리즈(상세페이지·카드뉴스 등)를 직접 만드는 서버 대 서버 API입니다. 화이트라벨 스토어를 쓰지 않고 내 서비스·주문 시스템에 생성을 붙일 때 사용합니다.
개요
| 기본 주소 | https://somssii.com/api/v1 (언어 경로 /ko/ 없이) |
| 인증 | Authorization: Bearer sk_live_… |
| 형식 | JSON 요청·응답, UTF-8. CSRF·쿠키 불필요 |
| 처리 방식 | 비동기 — 만들기 요청은 202와 uid를 돌려주고, 완성은 조회(폴링)로 확인. 이미지는 몇 분, 쇼츠는 한 시간 이상 |
| 비용 | 키를 발급한 솜씨 계정의 크레딧. 요청을 받는 순간 차감되고, 못 만든 만큼 자동 환불(세트 1개 · 시리즈 페이지당 · 쇼츠 1편 단위) |
| 결과 | 이미지는 https://somssii.com/uploads/…, 쇼츠는 공개 MP4·포스터 주소(video_url·poster_url)로 제공 |
| 시각 | 모든 시각은 한국 시간(KST) 문자열, 시간대 표시 없음 (2026-09-09 20:48:11) |
응답 모양은 리셀러 API와 다릅니다. 성공하면 데이터가 바로 최상위에 오고({"set":{…}}), 실패하면 {"error":{"code":"…","message":"…"}}입니다.
키 발급과 크레딧
- 솜씨 계정을 연결합니다(대시보드 계정 → 솜씨 계정 연결).
- 대시보드 계정 → API 화면의 솜씨 API 키(이미지·쇼츠 생성 연동)에서 키를 만듭니다(용도 메모는 선택). 키는
sk_live_로 시작하는 48자이며 만들 때 한 번만 보입니다. - 키는 연결한 솜씨 계정 소유이고, 세트(
sets) · 시리즈(series) · 쇼츠(shorts) 권한을 함께 가집니다. 동시에 3개까지 쓸 수 있고, 필요 없는 키는 같은 화면에서 폐기합니다. 키의 권한은GET /me의token.scopes로 확인합니다.
- 생성 비용은 연결한 솜씨 계정의 크레딧에서 빠집니다. 크레딧은 솜씨에서 직접 구매하거나, 대시보드 크레딧 판매에서 내가 연결한 솜씨 계정 이메일로 지급해 채웁니다(지갑에서 내 단가로 차감).
- 이 키는 화이트라벨 스토어가 내부적으로 쓰는 토큰과 별개입니다. 이 키를 폐기해도 스토어에는 영향이 없습니다.
- 키는 발급 당시 연결된 솜씨 계정에 묶입니다. 솜씨 계정 연결을 해제하거나 바꾸기 전에 이 키를 먼저 폐기하세요.
- API로 만든 세트·시리즈와 원본 이미지는 그 솜씨 계정의 작업 내역·소스 보관함에도 보이고, 세트가 완성될 때마다 솜씨가 그 계정 이메일로 완료 메일을 보냅니다. 연동 전용 솜씨 계정을 따로 쓰면 관리가 쉽습니다.
인증·요청 형식
Authorization: Bearer sk_live_0123456789abcdef0123456789abcdef01234567
Content-Type: application/json
Accept: application/json Authorization헤더를 쓸 수 없는 환경에서는X-Api-Key: sk_live_…헤더도 받습니다.- POST 본문은 JSON(
Content-Type: application/json)을 권장합니다. 파일 업로드가 필요하면multipart/form-data도 받지만 주의 사항을 먼저 읽으세요. - 토큰이 없거나(401
unauthorized), 폐기·만료되었거나(401invalid_token), 권한이 없거나(403scope_denied), 소유 솜씨 계정이 정지·탈퇴 상태면(403account_disabled) 요청이 거절됩니다. User-Agent에bot,spider,crawl이 들어가면 분당 10회로 제한되어 429를 받을 수 있습니다. 서비스 이름 같은 평범한 값을 쓰세요.- API 응답에 세션 쿠키가 붙어 올 수 있지만 인증에는 쓰지 않으므로 무시하면 됩니다.
엔드포인트
| 메서드 | 경로 | 권한 | 설명 |
|---|---|---|---|
| GET | /api/v1 | 없음 | API 안내(인증 없이) |
| GET | /api/v1/me | sets | 키 소유 계정과 남은 크레딧 — 연동 점검용 첫 호출 |
| GET | /api/v1/content-types | sets | 세트 상품 유형, 비율, 장수, 크레딧 |
| GET | /api/v1/series-types | series | 시리즈 종류, 페이지 범위, 페이지당 크레딧 |
| POST | /api/v1/sets | sets | 세트 만들기 → 202 |
| GET | /api/v1/sets?limit=20 | sets | 최근 세트 목록 |
| GET | /api/v1/sets/{uid} | sets | 세트 상태와 이미지 |
| POST | /api/v1/series | series | 시리즈 만들기 → 202 |
| GET | /api/v1/series?limit=20 | series | 최근 시리즈 목록 |
| GET | /api/v1/series/{uid} | series | 시리즈 상태, 페이지, 완성본 |
| GET | /api/v1/shorts-options | shorts | 쇼츠 주제·길이·목소리·최대 편수·1편 크레딧 |
| POST | /api/v1/shorts | shorts | 쇼츠 만들기 → 202 |
| GET | /api/v1/shorts?limit=20 | shorts | 최근 쇼츠 목록 |
| GET | /api/v1/shorts/{uid} | shorts | 쇼츠 상태와 편별 영상 |
키 소유 계정과 현재 크레딧을 돌려줍니다. 만들기 전에 크레딧이 충분한지 확인할 때도 씁니다.
{
"user": { "id": 1234, "name": "홍길동", "email": "studio@example.com" },
"credits": 480,
"token": { "label": "reseller-direct-12", "prefix": "sk_live_01234567", "scopes": ["sets", "series", "shorts"] }
}
세트로 만들 수 있는 상품 유형 목록입니다. code를 POST /sets의 content_type에 넣고, ratios 가운데 하나를 ratio로 고릅니다. size는 한 세트의 이미지 장수, credits는 세트 하나의 크레딧, reviewed가 true인 유형은 검수를 거친 뒤 이미지가 공개됩니다. 목록과 값은 바뀔 수 있으니 하루 한 번쯤 다시 읽어 캐시하세요.
{
"content_types": [
{ "code": "banner", "label": "광고 배너", "ratios": ["1:1"], "default_ratio": "1:1",
"size": 10, "credits": 10, "reviewed": false },
{ "code": "thumbnail", "label": "썸네일", "ratios": ["16:9"], "default_ratio": "16:9",
"size": 10, "credits": 10, "reviewed": false }
],
"size": 10,
"credits": 10
}
시리즈 종류입니다. min~max가 페이지 수 범위, default가 기본 페이지 수입니다. output이 page.jpg면 세로로 이어 붙인 한 장, document.pdf면 PDF가 만들어지고, null이면 페이지 이미지만 제공합니다. 비용은 credit_per_page × 페이지 수입니다.
{
"series_types": [
{ "code": "detail", "label": "상품 상세페이지", "summary": "…", "ratio": "9:16",
"min": 4, "max": 8, "default": 5, "assemble": "stack", "output": "page.jpg" },
{ "code": "cardnews", "label": "카드뉴스", "summary": "…", "ratio": "3:4",
"min": 3, "max": 10, "default": 6, "assemble": "none", "output": null }
],
"credit_per_page": 1
}
세트(같은 소재로 만든 여러 장의 이미지)를 접수합니다. 소재는 이미지 주소(source_url), 업로드 파일(image), 문장(topic) 가운데 하나입니다.
| 필드 | 형식 | 설명 |
|---|---|---|
source_url | 문자열 | 원본 이미지의 http(s) 주소. 솜씨 서버가 직접 내려받으므로 공개 주소여야 합니다(리다이렉트 3번까지, 25초, 25MB 이하). 권장 방식 |
image | 파일(multipart) | JPG·PNG·WEBP·GIF, 25MB 이하. source_url보다 우선 |
topic | 문자열 ≤190 | 이미지 없이 문장으로 만들 때 필수. 원본 이미지가 있으면 무시 |
content_type | 문자열 | /content-types의 code. 생략하면 banner. 모르는 값은 유형 없이 처리되니 목록의 값만 쓰세요 |
ratio | 문자열 | 유형의 ratios 가운데 하나. 아니면 유형 기본 비율 |
title | 문자열 ≤180 | 제목. 생략하면 파일 이름·주제·날짜로 정해집니다. 내 주문 번호를 넣어 두면 재시도 확인에 쓸 수 있습니다 |
note | 문자열 ≤500 | 추가 요청 사항 |
응답은 202 Accepted입니다. 이 시점에 크레딧이 차감되고, variants는 준비가 시작되기 전까지 비어 있습니다.
HTTP/1.1 202 Accepted
{
"set": {
"uid": "0e48cdc4d5a746033ea4", "title": "ORDER-1042 봄 시즌 배너", "status": "pending",
"content_type": "banner", "ratio": "1:1", "resolution": "2K",
"total": 10, "done_count": 0, "credits_used": 10,
"created_at": "2026-10-02 10:15:03", "finished_at": null, "error": null,
"variants": []
}
}
세트의 진행 상태와 완성된 이미지입니다. 다른 계정의 uid이거나 없는 uid면 404 not_found입니다.
{
"set": {
"uid": "0e48cdc4d5a746033ea4", "title": "ORDER-1042 봄 시즌 배너", "status": "processing",
"content_type": "banner", "ratio": "1:1", "resolution": "2K",
"total": 10, "done_count": 7, "credits_used": 10,
"created_at": "2026-10-02 10:15:03", "finished_at": null, "error": null,
"variants": [
{ "no": 1, "concept": "…", "layout": "…", "palette": "…", "style": "…",
"status": "done", "image": "https://somssii.com/uploads/studio/6f1060465ea5ca51e535-1.jpg" },
{ "no": 8, "concept": "…", "layout": "…", "palette": "…", "style": "…",
"status": "processing", "image": null }
]
}
} 세트 status | 뜻 |
|---|---|
pending | 접수됨, 준비 대기 |
preparing | 소재 분석·변형 구상 중(원본이 부적합하면 여기서 failed + 전액 환불) |
processing | 이미지 생성 중 |
done | 모두 완성 — 최종 |
partial | 일부만 완성, 못 만든 만큼 환불 — 최종 |
failed | 실패, 환불 — 최종 |
- 변형(
variants[])의status는pending·processing·done·failed·reviewing입니다. reviewing은 검수 대상 유형(reviewed: true)에서 생성은 끝났지만 검수 전이라는 뜻이며, 이때image는null입니다.- 세트가
processing인 동안 변형 하나가failed여도 최종이 아닙니다. 자동으로 다시 시도합니다(최대 3번).
키 소유 계정의 최근 세트(최신순, 변형 제외)입니다. limit은 1~100, 기본 20이며 그보다 오래된 세트는 볼 수 없습니다(쪽 넘김 없음). 솜씨 웹에서 직접 만든 세트도 함께 나오므로, 내 시스템에는 uid를 주문과 짝지어 저장하고 GET /sets/{uid}로 조회하세요.
{ "sets": [ { "uid": "0e48cdc4d5a746033ea4", "title": "…", "status": "done", "content_type": "banner",
"ratio": "1:1", "resolution": "2K", "total": 10, "done_count": 10, "credits_used": 10,
"created_at": "…", "finished_at": "…", "error": null } ] }
| 필드 | 형식 | 설명 |
|---|---|---|
series_type | 문자열 | 필수. /series-types의 code |
topic | 문자열 | 필수. 무엇을 만들지(상품·행사 설명 등) |
pages | 정수 | 페이지 수. 종류의 min~max로 맞춰지고, 생략하면 default |
source_url / image | 문자열 / 파일 | 선택. 참고할 상품 이미지(세트와 같은 규칙) |
title, note | 문자열 | 선택 |
응답은 202와 {"series":{…}}입니다. 비용 credit_per_page × 페이지 수가 접수 때 차감됩니다.
{
"series": {
"uid": "785db4baa27d3b98431c", "title": "…", "series_type": "detail", "status": "done",
"ratio": "9:16", "total": 5, "done_count": 5, "credits_used": 5,
"created_at": "…", "finished_at": "…", "error": null,
"output": "https://somssii.com/uploads/series/785db4baa27d3b98431c/page.jpg",
"pages": [
{ "no": 1, "role": "cover", "headline": "…", "subcopy": "…", "status": "done",
"image": "https://somssii.com/uploads/series/785db4baa27d3b98431c/p1.png" }
]
}
} - 시리즈
status:pending→preparing→processing→assembling→done, 또는error(최종). output은 완성본(page.jpg또는document.pdf)이 있을 때만 주소가 들어갑니다. 카드뉴스처럼 완성본이 없는 종류는null이고pages[].image를 씁니다.- 처리 중이거나
error일 때도pages[].image에 문구가 합성되기 전 이미지가 보일 수 있습니다. 최종 결과는done에서 가져가세요. GET /api/v1/series?limit=20은 세트 목록과 같은 규칙입니다.
쇼츠(9:16 영상)
요청 한 줄과 참고 주소로 9:16 세로 영상(쇼츠·릴스)을 만듭니다. 원본 영상을 잘라 붙이는 것이 아니라, 요청과 참고 주소의 내용을 바탕으로 기획(장면·대본) → 장면 제작 → 자막·음악·내레이션 → 검수 순서로 새로 만듭니다. 솜씨 웹의 「솜씨 만들기 → 쇼츠」와 같은 서비스로 처리되어 크레딧·환불 규칙이 같습니다.
| 비용 | credits_per_video × count — 접수(202) 때 차감(현재 1편 25 크레딧, 값은 /shorts-options가 기준) |
| 걸리는 시간 | 기획 20~40분 + 편마다 25~90분(여러 편은 나란히 진행). 보통 1~2시간 |
| 결과 | 편마다 MP4(video_url)·포스터(poster_url)·제목·길이. 1080×1920 |
| 환불 | 끝났을 때 못 만든 편수 × 접수 때의 편당 크레딧을 자동 환불(credits_used가 환불 뒤 값으로 줄어듦) |
만들 수 있는 주제·길이·목소리와 현재 비용입니다. 하루 한 번쯤 다시 읽어 캐시하세요. credits는 키 소유 계정의 현재 잔액입니다.
{
"topics": [
{ "code": "shopping", "label": "쇼핑 쇼츠", "default_duration": 30, "default_tone": "playful" },
{ "code": "promo", "label": "업체 홍보", "default_duration": 30, "default_tone": "balanced" },
{ "code": "insta", "label": "인스타 컨텐츠", "default_duration": 30, "default_tone": "playful" },
{ "code": "youtube", "label": "유튜브 하이라이트", "default_duration": 45, "default_tone": "balanced" },
{ "code": "live", "label": "라이브 쇼츠", "default_duration": 30, "default_tone": "playful" }
],
"durations": [15, 30, 45, 60],
"voices": [ { "name": "Kore", "desc": "여 · 단단함" }, { "name": "Zephyr", "desc": "여 · 밝음" }, "… 30가지" ],
"tones": ["playful", "balanced", "brand"],
"max_count": 10,
"credits_per_video": 25,
"credits": 480
}
| 필드 | 형식 | 설명 |
|---|---|---|
topic | 문자열 | 필수. /shorts-options의 topics[].code — 주제마다 기획 방향이 다릅니다(쇼핑은 상품 이미지를 함께 만들어 화면에 띄웁니다) |
request | 문자열 ≤7000 | 무엇을 어떤 느낌으로 만들지. refs와 둘 중 하나는 필수 |
refs | 배열 또는 줄바꿈 문자열 | 참고 주소(상품 페이지·공식 사이트·유튜브 영상/채널), http(s)만, 최대 20개. 나머지는 무시됩니다 |
count | 정수 | 편수 1~max_count(10). 기본 1 |
duration | 정수 | 15·30·45·60(초). 다른 값이면 주제의 기본 길이 |
voice | 문자열 | 내레이션 목소리 voices[].name. 생략하거나 모르는 값이면 내레이션 없이(자막·음악만) |
tone | 문자열 | playful · balanced · brand. 생략하면 주제 기본값 |
title | 문자열 ≤180 | 선택. 비우면 기획이 끝난 뒤 첫 편 제목으로 채워집니다 |
source | 문자열 | 선택(원본 편집). 유튜브 영상 하나 또는 mp4 주소를 주면 그 영상을 잘라 자막·내레이션·음악을 입힌 1편을 만듭니다(count는 1로 고정). 원본 사용 권리는 요청자에게 있어야 합니다 |
응답은 202 Accepted와 {"shorts":{…}}입니다. 이 시점에 크레딧이 차감되고 상태는 planning(기획 중)입니다.
HTTP/1.1 202 Accepted
{
"shorts": {
"uid": "a8929c97621adc7e24d1", "topic": "promo", "title": "", "status": "planning",
"total": 1, "done_count": 0, "failed_count": 0, "credits_used": 25,
"created_at": "2026-10-05 14:42:29", "finished_at": null, "error": null,
"page": "https://somssii.com/ko/shorts/v/a8929c97621adc7e24d1", "gallery_url": null, "cover": null,
"videos": []
}
}
진행 상태와 편별 영상입니다. 이 조회가 솜씨 쪽 진행 상황을 새로 확인하는 계기가 되지만, 같은 쇼츠는 45초보다 자주 새로 묻지 않으니 1~2분 간격이면 충분합니다. 다른 계정의 uid이거나 없는 uid면 404 not_found입니다.
{
"shorts": {
"uid": "a8929c97621adc7e24d1", "topic": "promo", "title": "파스타 타타 — 그곳에서 보내는 한 시간", "status": "done",
"total": 1, "done_count": 1, "failed_count": 0, "credits_used": 25,
"created_at": "2026-10-05 14:42:29", "finished_at": "2026-10-05 15:46:01", "error": null,
"page": "https://somssii.com/ko/shorts/v/a8929c97621adc7e24d1",
"gallery_url": "https://…/video-farm/31657420f919defd/", "cover": "https://…/posters/01-noodle-score.jpg",
"videos": [
{ "slug": "01-noodle-score", "title": "생면 한 접시가 오기까지", "status": "done", "lang": "ko",
"size": "1080x1920", "duration": 30,
"video_url": "https://…/video-farm/31657420f919defd/01-noodle-score-1791182759.mp4",
"poster_url": "https://…/video-farm/31657420f919defd/posters/01-noodle-score.jpg",
"page_url": null, "error": null }
]
}
} 쇼츠 status | 뜻 |
|---|---|
planning | 기획 중(장면 구성·대본) — 20~40분 |
making | 편마다 제작 중. 완성된 편의 파일 업로드가 끝날 때까지는 끝나도 잠시 making으로 남습니다 |
done | 모든 편 완성 — 최종 |
partial | 일부 편만 완성, 못 만든 편 환불 — 최종 |
failed · canceled | 만들지 못함 또는 취소, 환불 — 최종 |
videos[].status:queued(대기) ·running(만드는 중) ·done·failed.video_url은done인 편에만 있습니다.page는 그 계정으로 로그인해 보는 솜씨 결과 화면(재생·편집기·업로드 도구)입니다. 고객에게는 MP4를 내려받아 전달하거나 내 서비스에서 재생하세요.- 제목·설명·해시태그 같은 업로드 문구는 솜씨 결과 화면의 업로드 도구에서 만들어지며 API 응답에는 없습니다.
키 소유 계정의 최근 쇼츠(최신순, videos 제외)입니다. 세트 목록과 같은 규칙(limit 1~100, 쪽 넘김 없음)이며, 솜씨 웹에서 직접 만든 쇼츠도 함께 나옵니다.
비동기 처리·폴링
- 만들기 요청은 접수만 하고 끝납니다. 실제 생성은 솜씨 서버의 작업 스케줄러가 1분 간격으로 진행하며, 조회 요청은 진행을 앞당기지 않습니다.
- 세트·시리즈는 보통 5분 안팎(시리즈는 10~20분)이 걸리고, 요청이 몰리면 대기 시간이 늘어납니다(한 번에 준비를 시작하는 수가 정해져 있습니다).
GET /sets/{uid}(또는/series/{uid})를 15~30초 간격으로 조회하고, 최종 상태(done·partial·failed, 시리즈는done·error)가 되면 멈추세요.- 45분이 지나도 끝나지 않으면 대기를 멈추고 나중에 다시 확인하거나 문의하세요. 오래 걸린 작업은 서버가 남은 변형을 실패로 정리하고 환불합니다.
- 쇼츠는 보통 1~2시간 걸립니다.
GET /shorts/{uid}를 1~2분 간격으로 조회하고done·partial·failed·canceled에서 멈추세요. 8시간이 지나도 진행 중이면 문의하세요. - 웹훅(완료 알림 호출)은 없습니다.
크레딧·환불
- 크레딧은 접수(202)될 때 키 소유 계정에서 차감됩니다.
422 create_failed로 거절된 요청은 차감되지 않습니다. - 세트 비용 = 그 유형의
credits(/content-types). 시리즈 비용 =credit_per_page × 페이지 수. 쇼츠 비용 =credits_per_video × count(/shorts-options). - 세트 환불: 원본이 부적합해 준비 단계에서 실패하면 전액 환불. 끝났을 때 못 만든 장수가 있으면
round(credits_used × 못 만든 장수 ÷ total)만큼 환불합니다. 세트의credits_used는 차감한 값 그대로 남으므로, 실제 사용량은credits_used − round(credits_used × (total − done_count) ÷ total)입니다. - 시리즈 환불: 못 만든 페이지만큼 환불되고, 시리즈의
credits_used가 환불 뒤 값으로 줄어듭니다. 준비 단계 실패나 완성본 조립이 오래 멈춘 경우는 전액 환불입니다. - 쇼츠 환불: 끝났을 때 못 만든 편수 × 접수 때 낸 편당 크레딧이 환불되고(그 사이 단가가 바뀌어도 접수 때 값),
credits_used가 환불 뒤 값으로 줄어듭니다.failed·canceled는 전액입니다. - 환불과 차감은 솜씨 계정의 크레딧 내역에 그대로 남습니다.
- 잔액 확인은 요청 순간에만 합니다. 같은 계정으로 만들기 요청을 동시에 여러 개 보내면 잔액보다 많이 접수될 수 있으니, 만들기 요청은 키(계정)마다 하나씩 순서대로 보내고, 보내기 전에
GET /me로 크레딧을 확인하세요.
결과 파일 주소
- 결과는
https://somssii.com/uploads/studio/…(세트),https://somssii.com/uploads/series/{uid}/…(시리즈)의 정적 파일입니다. 파일 하나가 보통 2~5MB입니다. - 쇼츠는 영상 저장소의 공개 MP4(
video_url, 30초 기준 10~30MB)와 포스터 JPG(poster_url)입니다. 주소 형식은 바뀔 수 있으니 응답의 값을 그대로 쓰세요. - 주소는 추측할 수 없는 무작위 이름이지만 인증 없이 열립니다. 주소를 아는 사람은 누구나 볼 수 있으니 고객에게 그대로 넘길지 판단하세요.
- 주소에 somssii.com이 보이면 안 되는 서비스라면, 완성 뒤 파일을 내려받아 내 서버에 저장해 제공하세요.
- API에는 삭제·재생성·ZIP 내려받기·쇼츠 편집이 없습니다. 이런 작업은 솜씨 웹에서 그 계정으로 로그인해 합니다(쇼츠 편집기·업로드 도구 포함).
JSON(source_url)과 파일 업로드
source_url로 넘기는 방법을 권장합니다. 이미지를 내 서버(공개 HTTPS 주소)에 올려 두고 그 주소를 보내면 됩니다.- 솜씨 서버 앞단의 웹 방화벽이
multipart/form-data업로드 일부를 이미지 바이트 내용에 따라 차단합니다. 차단되면 JSON이 아닌 HTTP 500(HTML)이 오고, 같은 파일은 다시 보내도 같은 결과입니다. 이때는 세트가 만들어지지 않고 크레딧도 차감되지 않습니다. - multipart의 텍스트 필드에
--로 시작하는 줄이 있으면 항상 차단됩니다. - 그래서 파일 업로드를 쓰더라도 JSON이 아닌 응답(500·403)을 받으면 "차단됨"으로 보고
source_url방식으로 다시 보내도록 만들어 두세요. source_url은 솜씨 서버가 바로 내려받을 수 있는 주소여야 합니다(로그인·쿠키가 필요한 주소, 내부망 주소는 안 됩니다). 받은 원본은 키 소유 계정의 소스 보관함에 저장됩니다.
오류
HTTP/1.1 422 Unprocessable Entity
{ "error": { "code": "create_failed", "message": "크레딧이 부족합니다. 필요 10 · 보유 4. 크레딧을 구매하면 바로 만들 수 있습니다." } } | HTTP | error.code | 뜻 |
|---|---|---|
| 202 | — | 접수됨(만들기) |
| 401 | unauthorized | Authorization 헤더가 없음 |
| 401 | invalid_token | 없는·폐기된·만료된 키 |
| 403 | scope_denied | 그 기능의 권한이 없는 키 |
| 403 | account_disabled | 키 소유 솜씨 계정이 정지·탈퇴 상태 |
| 404 | not_found | 없는 uid 또는 다른 계정의 uid |
| 422 | create_failed | 만들기 실패(크레딧 부족, 주제 누락, 이미지 형식·크기, 주소를 받을 수 없음, 쇼츠의 "주제를 골라 주세요."·"요청문이나 참고 주소 중 하나는 적어 주세요."·"원본 편집에는 유튜브 영상 하나의 주소나 mp4 주소가 필요합니다." 등). message는 한국어 문장이며 세부 코드는 없습니다. 크레딧은 차감되지 않습니다 |
| 429 | (HTML) | User-Agent 제한에 걸림(인증·요청 형식) |
| 404 · 405 · 403 · 500 | (HTML·텍스트) | 없는 경로, 잘못된 메서드, 웹 방화벽 차단, 서버 오류. JSON이 아니므로 "전송 오류"로 처리하세요 |
크레딧 부족을 미리 알려면 만들기 전에 GET /me의 credits와 유형의 credits를 비교하세요.
제한·주의 사항
- 중복 방지 키가 없습니다. 만들기 요청이 시간 초과로 끝나도 서버에서는 접수되었을 수 있으니 그대로 다시 보내지 마세요. 제목에 내 주문 번호를 넣고, 시간 초과가 나면
GET /sets?limit=5에서 같은 제목의 세트가 생겼는지 먼저 확인합니다. 쇼츠는GET /shorts?limit=5에서 같은topic·total이 방금 접수됐는지 확인하세요(쇼츠 접수는 영상 저장소에 작업을 만든 뒤 답하므로 최대 1분쯤 걸릴 수 있습니다 — 제한 시간을 60초 이상으로). - 목록 조회는 최신 100건까지만 볼 수 있습니다.
uid는 반드시 내 시스템에 저장하세요. - 만들기 요청은 계정마다 하나씩 순서대로 보내세요(크레딧·환불).
- 키는 서버에서만 쓰세요. 브라우저·앱에 넣으면 누구나 내 크레딧으로 이미지를 만들 수 있습니다.
- 고객이 입력한 임의의 주소를
source_url로 그대로 넘기지 마세요. 내 서버에 받아 검사한 뒤 내 주소로 넘기는 것이 안전합니다.
예제(curl · PHP)
curl
# 키는 환경 변수에 둔다(예시 값)
export SS_KEY="sk_live_0123456789abcdef0123456789abcdef01234567"
BASE="https://somssii.com/api/v1"
# 1) 연동 점검 · 남은 크레딧
curl -s "$BASE/me" -H "Authorization: Bearer $SS_KEY"
# 2) 상품 유형 확인
curl -s "$BASE/content-types" -H "Authorization: Bearer $SS_KEY"
# 3) 세트 만들기 (JSON + source_url, 권장)
curl -s -X POST "$BASE/sets" \
-H "Authorization: Bearer $SS_KEY" \
-H "Content-Type: application/json" \
-d '{"source_url":"https://cdn.example.com/products/1042.jpg","content_type":"banner","ratio":"1:1","title":"ORDER-1042 봄 시즌 배너","note":"밝은 파스텔 톤"}'
# 4) 문장만으로 세트 만들기
curl -s -X POST "$BASE/sets" \
-H "Authorization: Bearer $SS_KEY" \
-H "Content-Type: application/json" \
-d '{"topic":"수제 딸기잼 신제품 출시","content_type":"banner","title":"ORDER-1043"}'
# 5) 진행 상태 조회 (15~30초 간격으로)
curl -s "$BASE/sets/0e48cdc4d5a746033ea4" -H "Authorization: Bearer $SS_KEY"
# 6) 시리즈(상품 상세페이지 5장) 만들기
curl -s -X POST "$BASE/series" \
-H "Authorization: Bearer $SS_KEY" \
-H "Content-Type: application/json" \
-d '{"series_type":"detail","topic":"무첨가 수제 딸기잼 300g, 국산 딸기 80%","pages":5,"title":"ORDER-1044"}'
# 7) 쇼츠 선택지 확인 → 쇼츠 2편 만들기(쇼핑, 30초, 내레이션 Kore)
curl -s "$BASE/shorts-options" -H "Authorization: Bearer $SS_KEY"
curl -s -X POST "$BASE/shorts" --max-time 90 \
-H "Authorization: Bearer $SS_KEY" \
-H "Content-Type: application/json" \
-d '{"topic":"shopping","request":"겨울 신상 니트 — 울 100%, 5가지 색. 착용 컷 위주로 밝게","refs":["https://shop.example.com/knit-2026"],"count":2,"duration":30,"voice":"Kore","title":"ORDER-1046"}'
# 8) 쇼츠 진행 상태 (1~2분 간격으로)
curl -s "$BASE/shorts/a8929c97621adc7e24d1" -H "Authorization: Bearer $SS_KEY"
# (참고) 파일 업로드 — 웹 방화벽에 막힐 수 있으니 JSON+source_url 을 우선 쓴다
curl -s -X POST "$BASE/sets" -H "Authorization: Bearer $SS_KEY" \
-F "image=@./photo.jpg" -F "content_type=banner" -F "title=ORDER-1045"
PHP (cURL) — 만들고 완성될 때까지 기다리기
<?php
// 키는 코드에 적지 말고 환경 변수에서 읽는다.
const SS_BASE = "https://somssii.com/api/v1";
function ss_call(string $method, string $path, ?array $body = null): array
{
$ch = curl_init(SS_BASE . $path);
$headers = [
"Authorization: Bearer " . getenv("SS_KEY"),
"Accept: application/json",
"User-Agent: my-shop/1.0", // bot·spider·crawl 이 들어가지 않게
];
if ($body !== null) {
$headers[] = "Content-Type: application/json";
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body, JSON_UNESCAPED_UNICODE));
}
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 60,
]);
$raw = curl_exec($ch);
$status = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$err = curl_error($ch);
curl_close($ch);
if ($raw === false) {
// 시간 초과 등: POST 였다면 다시 보내기 전에 GET /sets?limit=5 로 접수 여부를 확인한다.
throw new RuntimeException("전송 오류: " . $err);
}
$json = json_decode($raw, true);
if (!is_array($json)) {
throw new RuntimeException("JSON 이 아닌 응답(HTTP {$status}) — 방화벽 차단·서버 오류로 본다");
}
if ($status >= 400) {
throw new RuntimeException(($json["error"]["code"] ?? "error") . ": " . ($json["error"]["message"] ?? ""));
}
return $json;
}
// 1) 크레딧 확인
$me = ss_call("GET", "/me");
if ($me["credits"] < 10) {
exit("솜씨 계정 크레딧이 부족합니다.\n");
}
// 2) 접수 — uid 를 내 주문과 함께 저장한다
$set = ss_call("POST", "/sets", [
"source_url" => "https://cdn.example.com/products/1042.jpg",
"content_type" => "banner",
"ratio" => "1:1",
"title" => "ORDER-1042 봄 시즌 배너",
])["set"];
$uid = $set["uid"];
// 3) 폴링 — 20초 간격, 최대 45분
$deadline = time() + 45 * 60;
do {
sleep(20);
$set = ss_call("GET", "/sets/" . rawurlencode($uid))["set"];
} while (!in_array($set["status"], ["done", "partial", "failed"], true) && time() < $deadline);
// 4) 결과 — 필요하면 내려받아 내 서버에 보관한다
foreach ($set["variants"] ?? [] as $v) {
if ($v["status"] === "done" && $v["image"] !== null) {
echo $v["no"], " ", $v["image"], "\n";
}
}
PHP — 쇼츠 만들고 완성 영상 받기
<?php
// ss_call() 은 위 예제와 같다. 쇼츠 접수는 최대 1분쯤 걸릴 수 있어 CURLOPT_TIMEOUT 을 90초로 둔다.
$opt = ss_call("GET", "/shorts-options");
$need = $opt["credits_per_video"] * 2;
if ($opt["credits"] < $need) {
exit("솜씨 계정 크레딧이 부족합니다(필요 {$need}).\n");
}
$shorts = ss_call("POST", "/shorts", [
"topic" => "promo",
"request" => "성수동 브런치 카페 — 창가 좌석과 시그니처 메뉴를 따뜻한 느낌으로",
"refs" => ["https://cafe.example.com", "https://www.instagram.com/cafe.example/"],
"count" => 2,
"duration" => 30,
"voice" => "Zephyr",
"title" => "ORDER-1047",
])["shorts"];
$uid = $shorts["uid"]; // 주문과 함께 저장
// 2분 간격, 최대 8시간
$deadline = time() + 8 * 3600;
do {
sleep(120);
$shorts = ss_call("GET", "/shorts/" . rawurlencode($uid))["shorts"];
} while (!in_array($shorts["status"], ["done", "partial", "failed", "canceled"], true) && time() < $deadline);
foreach ($shorts["videos"] ?? [] as $v) {
if ($v["status"] === "done" && $v["video_url"] !== null) {
// 고객에게 줄 파일은 내 저장소로 옮겨 두면 주소가 바뀌어도 안전하다
file_put_contents(__DIR__ . "/" . $v["slug"] . ".mp4", fopen($v["video_url"], "rb"));
echo $v["title"], " (", $v["duration"], "초)\n";
}
}
echo "사용 크레딧(환불 뒤): ", $shorts["credits_used"], "\n";