문서
SublimeKeys를 앱에 연동하는 데 필요한 모든 것. 읽는 데 계정은 필요 없습니다.
$SUBLIMEKEYS_API_KEY
아래의 모든 요청은 이것을 실제 키의 자리 표시자로 사용합니다. 로그인 (무료, 카드 불필요)하여 본인의 키를 받고 이 예제들이 본인의 제품으로 채워진 모습을 확인하세요.
빠른 시작 — 3번의 호출
1. 제품 등록 (제품에서 한 번만 수행)
curl -X POST https://api.sublimearts.io/v1/products \
-H "Authorization: Bearer $SUBLIMEKEYS_API_KEY" \
-d '{"slug":"my-app","key_prefix":"MYAPP"}'2. 판매마다 키 발급
curl -X POST https://api.sublimearts.io/v1/licenses \
-H "Authorization: Bearer $SUBLIMEKEYS_API_KEY" \
-d '{"product":"my-app","email":"buyer@mail.com","max_activations":3}'
→ {"key":"MYAPP-K3F7Q-9WZ2M-P8RT4-XN5CB", ...}| product | 필수 — 1단계의 제품 slug |
| 선택 — 대시보드의 라이선스 목록에 표시됩니다 | |
| max_activations | 선택, 기본값 1 — 이 하나의 키가 동시에 몇 개의 서로 다른 machine_id에서 활성화될 수 있는지. 본인의 가격 정책에 맞게 설정하세요(예: "개인 사용, 3대" 플랜이라면 3으로 설정). 최종 고객의 플랜이 아니라 본인의 SublimeKeys 플랜에 따라 상한이 정해집니다 — Free는 5, Pro는 25, Business는 100(요금제 참고). |
| expires_at | 선택 — ISO 날짜; 영구 키의 경우 생략 |
| notes | 선택 — 자유 텍스트, 본인 참고용 |
또는 이 호출 자체를 완전히 건너뛸 수도 있습니다 — 아래 AUTOMATE 참고.
3. 앱 내에서 검증
# pip install sublimekeys
from sublimekeys import SublimeKeysClient
client = SublimeKeysClient(product_id="my-app")
result = client.activate(license_key=key) # first run
result = client.verify(license_key=key) # every launch after — offline-first,
# verifies a signed lease locally,
# zero network calls for up to 7 days
if result.valid:
unlock_full_version()// npm install sublimekeys
import { SublimeKeysClient } from "sublimekeys";
const client = new SublimeKeysClient("my-app");
const activated = await client.activate(key); // first run
const result = await client.verify(key); // every launch after — offline-first,
// verifies a signed lease locally,
// zero network calls for up to 7 days
if (result.valid) unlockFullVersion();Python이나 Node.js를 사용하지 않거나, 직접 raw API를 호출하고 싶으신가요? PyPI의 Python SDK · npm의 Node.js SDK 또는 아래 엔드포인트를 직접 사용하세요.
import requests
r = requests.post("https://api.sublimearts.io/activate", json={
"license_key": key,
"machine_id": machine_id,
"product_id": "my-app",
})
if r.json()["valid"]:
unlock_full_version()const r = await fetch("https://api.sublimearts.io/activate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ license_key, machine_id, product_id: "my-app" }),
});
const { valid } = await r.json();
if (valid) unlockFullVersion();curl -X POST https://api.sublimearts.io/activate \
-d '{"license_key":"...","machine_id":"...","product_id":"my-app"}'▸ 처음이신가요? 이 호출들이 실제로 앱 어디에 들어가는지
위 예제는 /activate 만 단독으로 보여줍니다 — 실제 앱에서는 서로 다른 시점에 서로 다른 엔드포인트를 호출합니다:
앱 시작
├─ 아직 저장된 라이선스 키가 없음(최초 실행)
│ → "라이선스 키 입력" 화면 표시
│ → 사용자가 제출 → /activate를 한 번 호출 → 결과를 로컬에 저장
│
├─ 이미 라이선스 키가 저장되어 있음(이후 매 실행)
│ → 대신 /verify를 호출(다시 /activate가 아님) — 이 기기에서
│ 여전히 유효한지 확인
│
├─ API에 접근할 수 없음(사용자가 오프라인 상태)
│ → /activate와 /verify 모두 서명된 "리스"를 반환(7일간 유효)
│ → 마지막 결과를 무조건 신뢰하는 대신 서명을 로컬에서
│ 검증 — Python과 Node.js SDK는 이를 자동으로 수행하며, 다른
│ 언어에서는 Ed25519 서명을 직접 검증할 수 있음(공개 키는
│ GET /public-key에서 확인)
│
└─ 사용자가 제거/로그아웃(선택)
→ /deactivate를 호출하여 다른 기기를 위해 자리를 비움Python이나 Node.js/Electron에서는 공식 SDK(PyPI·npm)가 오프라인 리스에 대한 실제 암호학적 검증을 포함해 이미 이를 자동으로 처리합니다. 아래의 raw 버전은 이 단계를 건너뜁니다(오프라인 상태에서는 단순히 마지막으로 저장된 결과를 신뢰합니다) — 더 단순하지만 암호학적으로 검증되지는 않습니다. Python/Node.js를 사용하지 않거나 완전한 제어가 필요할 때 사용하세요.
import requests, json, os
STATE_FILE = "license_state.json"
def check_license(machine_id):
saved = json.load(open(STATE_FILE)) if os.path.exists(STATE_FILE) else None
try:
if saved is None:
# first run — ask the user for their key once
key = prompt_for_license_key()
r = requests.post("https://api.sublimearts.io/activate", json={
"license_key": key, "machine_id": machine_id, "product_id": "my-app",
}, timeout=5)
else:
# every later launch — re-check the saved key, don't ask again
r = requests.post("https://api.sublimearts.io/verify", json={
"license_key": saved["license_key"], "machine_id": machine_id, "product_id": "my-app",
}, timeout=5)
result = r.json()
json.dump(result, open(STATE_FILE, "w"))
return result["valid"]
except requests.RequestException:
# offline — trust the last known result instead of locking the user out
return saved["valid"] if saved else False이미 개념이 익숙하신가요? 이 부분은 건너뛰세요 — 위의 호출만으로 충분합니다.
공식 SDK
🐍 Python — sublimekeys
전체 API를 감싸고 오프라인 검증을 대신 처리합니다 — 로컬에서 검증되는 서명된 리스로 activate/verify/deactivate를 수행하므로 대부분의 실행에서 네트워크 호출이 전혀 발생하지 않으며, 오프라인 기간을 견디는 체험판 확인 기능도 있습니다. 터미널에서 통합을 테스트할 수 있는 sublimekeys CLI도 함께 설치됩니다.
pip install sublimekeys
⚡ Node.js / Electron — sublimekeys
동일하게 오프라인을 지원하는 설계이며 런타임 의존성이 전혀 없습니다 — Ed25519 검증은 Node 내장 crypto를 사용하므로 Electron의 asar 패키징이 걸림돌이 될 요소가 없습니다.
npm install sublimekeys
더 많은 언어가 로드맵에 있습니다. 그동안 아래의 모든 엔드포인트는 일반적인 REST 호출입니다 — HTTPS 요청을 보낼 수 있는 어떤 것에서든 호출할 수 있습니다.
엔드포인트 레퍼런스 — 퍼블릭(앱에서 호출)
POST /activate
body: { "license_key", "machine_id", "product_id" }
▸ 세부 정보
최초 실행 — 라이선스 키를 machine_id에 연결합니다. 동일한 기기에서 다시 호출해도 안전합니다 — 추가 활성화 슬롯을 소비하지 않습니다. 불가능한 경우(예: 다른 기기에서 활성화 한도에 도달한 경우) 메시지와 함께 valid:false를 반환합니다. 성공 시 응답의 lease 필드에 서명된 리스(7일 오프라인 신뢰 기간)도 함께 반환됩니다 — Python SDK는 이후 실행 시 매번 API를 호출하는 대신 이를 로컬에서 검증합니다.
POST /verify
body: { "license_key", "machine_id", "product_id" }
▸ 세부 정보
이후의 모든 실행마다 — 키가 이 기기에서 여전히 유효한지 확인합니다. 활성화 횟수에 영향을 주지 않으므로 원하는 만큼 자주 호출해도 됩니다. 성공적으로 호출될 때마다 서명된 리스(/activate 참고)도 갱신됩니다.
POST /deactivate
body: { "license_key", "machine_id", "product_id" }
▸ 세부 정보
사용자가 로그아웃/제거 — 다른 기기를 위해 자리를 비웁니다.
POST /trial/start
body: { "machine_id", "product_id" }
▸ 세부 정보
기기에 대해 7일 체험판을 가져오거나 생성합니다. 멱등성을 가집니다 — 재설치해도 절대 시간이 초기화되지 않습니다.
POST /trial/status
body: { "machine_id", "product_id" }
▸ 세부 정보
읽기 전용 체험판 확인입니다 — 체험판을 시작하지는 않습니다.
여기에는 Authorization 헤더가 없습니다 — license_key 자체가 자격 증명입니다. 계정 범위의 전체 API(생성/목록/취소)는 /v1/* 아래에 있으며, 대시보드를 참고하세요.
⚡ AUTOMATE — 백엔드 없는 키 전달
위의 2단계를 완전히 건너뛸 수 있습니다. 결제 제공업체의 웹훅을 제품의 URL로 연결하면 판매가 발생할 때마다 자동으로 키가 발급되어 구매자에게 이메일로 전송됩니다.
- Stripe 대시보드 → Developers → Webhooks → Add endpoint
- 제품의 URL을 붙여넣으세요 (로그인 후 제품을 생성하면 URL을 받을 수 있습니다)
- 이벤트 선택: checkout.session.completed
- 저장하세요. 이게 전부입니다 — 서버도, 코드도 필요 없습니다.
- 선택 사항이지만 권장: Stripe가 바로 다음에 Signing secret을 보여줍니다 — 이를 제품 페이지의 "Signature verification"에 붙여넣으면, 이 URL을 알고 있는 아무나가 아니라 실제로 Stripe에서 온 요청만 받아들이게 됩니다.
🔔 판매가 있을 때마다 본인도 이메일을 받고 싶으신가요? 제품 페이지에서 이 블록 옆의 "Notify me"를 켜세요.
GUMROAD, KEYGEN 또는 자체 서버에서 마이그레이션
기존 고객을 email 열 하나가 있는 CSV로 내보낸 다음, 제품마다 이를 한 번 실행하세요. 각 행마다 본인의 브랜드 접두사가 붙은 새 SublimeKeys 라이선스를 일괄 발급합니다.
import csv, os, requests
API_KEY = os.environ["SUBLIMEKEYS_API_KEY"]
PRODUCT = "my-app"
with open("customers.csv") as f:
for row in csv.DictReader(f):
r = requests.post("https://api.sublimearts.io/v1/licenses",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"product": PRODUCT, "email": row["email"]})
print(row["email"], "->", r.json()["key"])이 방식은 완전히 새로운 키를 발급합니다 — 기존 키 문자열은 유지되지 않습니다(설계상 커스텀 키 값은 허용하지 않습니다). 고객에게 새 키를 이메일로 보내거나, 기존 시스템을 폐지하기 전 전환 기간 동안 앱에서 두 검증을 나란히 실행하세요.
플랜 한도
FREE
제품 1개 · 키 100개 · 키당 기기 5대
PRO
제품 5개 · 키 1,000개 · 키당 기기 25대
BUSINESS
제품·키 무제한 · 키당 기기 100대
한도에 도달해도 기존 키는 절대 손상되지 않습니다 — 영원히 계속 검증됩니다. 업그레이드하기 전까지 새 키를 발급할 수 없을 뿐입니다. 다운그레이드나 해지 역시 무엇도 삭제하지 않습니다.