솜씨 리셀러PARTNER PROGRAM

도움말 / 솜씨 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":"…"}}입니다.

키 발급과 크레딧

  1. 솜씨 계정을 연결합니다(대시보드 계정 → 솜씨 계정 연결).
  2. 대시보드 계정 → API 화면의 솜씨 API 키(이미지·쇼츠 생성 연동)에서 키를 만듭니다(용도 메모는 선택). 키는 sk_live_로 시작하는 48자이며 만들 때 한 번만 보입니다.
  3. 키는 연결한 솜씨 계정 소유이고, 세트(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), 폐기·만료되었거나(401 invalid_token), 권한이 없거나(403 scope_denied), 소유 솜씨 계정이 정지·탈퇴 상태면(403 account_disabled) 요청이 거절됩니다.
  • User-Agent에 bot, spider, crawl이 들어가면 분당 10회로 제한되어 429를 받을 수 있습니다. 서비스 이름 같은 평범한 값을 쓰세요.
  • API 응답에 세션 쿠키가 붙어 올 수 있지만 인증에는 쓰지 않으므로 무시하면 됩니다.

엔드포인트

메서드경로권한설명
GET/api/v1없음API 안내(인증 없이)
GET/api/v1/mesets키 소유 계정과 남은 크레딧 — 연동 점검용 첫 호출
GET/api/v1/content-typessets세트 상품 유형, 비율, 장수, 크레딧
GET/api/v1/series-typesseries시리즈 종류, 페이지 범위, 페이지당 크레딧
POST/api/v1/setssets세트 만들기 → 202
GET/api/v1/sets?limit=20sets최근 세트 목록
GET/api/v1/sets/{uid}sets세트 상태와 이미지
POST/api/v1/seriesseries시리즈 만들기 → 202
GET/api/v1/series?limit=20series최근 시리즈 목록
GET/api/v1/series/{uid}series시리즈 상태, 페이지, 완성본
GET/api/v1/shorts-optionsshorts쇼츠 주제·길이·목소리·최대 편수·1편 크레딧
POST/api/v1/shortsshorts쇼츠 만들기 → 202
GET/api/v1/shorts?limit=20shorts최근 쇼츠 목록
GET/api/v1/shorts/{uid}shorts쇼츠 상태와 편별 영상
GET/api/v1/mescope sets

키 소유 계정과 현재 크레딧을 돌려줍니다. 만들기 전에 크레딧이 충분한지 확인할 때도 씁니다.

{
  "user": { "id": 1234, "name": "홍길동", "email": "studio@example.com" },
  "credits": 480,
  "token": { "label": "reseller-direct-12", "prefix": "sk_live_01234567", "scopes": ["sets", "series", "shorts"] }
}
GET/api/v1/content-typesscope sets

세트로 만들 수 있는 상품 유형 목록입니다. 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
}
GET/api/v1/series-typesscope series

시리즈 종류입니다. 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
}
POST/api/v1/setsscope sets

세트(같은 소재로 만든 여러 장의 이미지)를 접수합니다. 소재는 이미지 주소(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": []
  }
}
GET/api/v1/sets/{uid}scope sets

세트의 진행 상태와 완성된 이미지입니다. 다른 계정의 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번).
GET/api/v1/sets?limit=20scope sets

키 소유 계정의 최근 세트(최신순, 변형 제외)입니다. 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 } ] }
POST/api/v1/seriesscope series
필드형식설명
series_type문자열필수. /series-types의 code
topic문자열필수. 무엇을 만들지(상품·행사 설명 등)
pages정수페이지 수. 종류의 min~max로 맞춰지고, 생략하면 default
source_url / image문자열 / 파일선택. 참고할 상품 이미지(세트와 같은 규칙)
title, note문자열선택

응답은 202와 {"series":{…}}입니다. 비용 credit_per_page × 페이지 수가 접수 때 차감됩니다.

GET/api/v1/series/{uid}scope series
{
  "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가 환불 뒤 값으로 줄어듦)
GET/api/v1/shorts-optionsscope shorts

만들 수 있는 주제·길이·목소리와 현재 비용입니다. 하루 한 번쯤 다시 읽어 캐시하세요. 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
}
POST/api/v1/shortsscope shorts
필드형식설명
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": []
  }
}
GET/api/v1/shorts/{uid}scope shorts

진행 상태와 편별 영상입니다. 이 조회가 솜씨 쪽 진행 상황을 새로 확인하는 계기가 되지만, 같은 쇼츠는 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 응답에는 없습니다.
GET/api/v1/shorts?limit=20scope shorts

키 소유 계정의 최근 쇼츠(최신순, 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)과 파일 업로드

원본 이미지는 JSON 본문의 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. 크레딧을 구매하면 바로 만들 수 있습니다." } }
HTTPerror.code뜻
202—접수됨(만들기)
401unauthorizedAuthorization 헤더가 없음
401invalid_token없는·폐기된·만료된 키
403scope_denied그 기능의 권한이 없는 키
403account_disabled키 소유 솜씨 계정이 정지·탈퇴 상태
404not_found없는 uid 또는 다른 계정의 uid
422create_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";