PayStars Unified API · v3.0
텔레그램 스타 API · Fragment API.
StarKerak과 같은 잔액.
웹사이트, 텔레그램 WebApp, 외부 API가 모두 같은 StarKerak 잔액과 처리 엔진을 사용합니다. API 결제는 USD 잔액으로 하며 가격은 Fragment 가격 + 5%입니다. 응답은 JSON입니다.
인증
대시보드에서 API 키를 만드세요. 전체 키는 한 번만 표시됩니다. 서버 환경 변수에 보관하고 프론트엔드 JavaScript나 Git 저장소에 절대 넣지 마세요.
X-API-Key: ps_your_secret_api_key Content-Type: application/json Idempotency-Key: order_20260719_0001
한도, 확인, 멱등성
- API 키당 초당 3회 요청.
- API 수신자 확인 한도: 계정당 분당 120회, 웹사이트/WebApp은 12회.
- 구매 전에 반드시
/check-username을 호출해 180초 유효한verification_token을 받아야 합니다. - verification token은 하나의 논리적 주문에만 연결되며, 같은 멱등 키로 안전하게 재시도할 수 있습니다.
- 스타와 프리미엄 구매 시 8–128자의 고유한
Idempotency-Key를 보내세요. - 같은
Idempotency-Key와 같은 payload를 다시 보내면 추가 차감 없이 기존 주문이 반환됩니다. - 같은 멱등 키를 다른 payload로 쓰면
409 Conflict가 반환됩니다.
API 상태
/statuscurl https://paystars.uz/api/v1/status
USD 잔액과 가격
계정과 달러 잔액은 StarKerak에서 가져옵니다. 가격은 USD이며 모든 주문은 Fragment 가격 + 5%입니다.
/accountcurl https://paystars.uz/api/v1/account \
-H "X-API-Key: $PAYSTARS_API_KEY"{
"ok": true,
"user": { "telegram_id": 123456789 },
"balances": { "USD": "12.50" },
"currency_pref": "USD"
}/pricesUSD 가격은 아래의 POST /usd/quote를 사용하세요: 가격 = Fragment + 5%.
유저네임 확인
이 엔드포인트는 Fragment로 이름, 사진, 프리미엄 상태를 조회합니다. verification_token은 구매 가능한 수신자에게만 반환됩니다.
/check-usernamecurl -X POST https://paystars.uz/api/v1/check-username \ -H "X-API-Key: $PAYSTARS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"username":"telegram","kind":"premium"}'
{
"valid": true,
"username": "telegram",
"nickname": "Telegram User",
"photo_url": "https://cdn4.telesco.pe/...",
"premium_active": false,
"verification_token": "...",
"verification_expires_in": 180
}kind는 stars 또는 premium입니다. 이미 프리미엄이 활성화되어 있으면 premium_active: true, valid: false, 토큰은 null입니다.
스타 주문
/stars/buycurl -X POST https://paystars.uz/api/v1/stars/buy \ -H "X-API-Key: $PAYSTARS_API_KEY" \ -H "Idempotency-Key: order_20260719_0001" \ -H "Content-Type: application/json" \ -d '{"username":"telegram","quantity":100,"verification_token":"TOKEN_FROM_CHECK","currency":"USD","max_usd":1.58}'
{
"ok": true,
"order_id": 1842,
"status": "processing",
"quantity": 100,
"cost": 1.58,
"balance": 10.92,
"currency": "USD"
}달러(USD) 잔액과 USDT
API 결제는 달러 잔액으로 이루어집니다. TON 또는 BEP20 네트워크의 USDT로 충전합니다(최소 1 USDT). TRC20(TRON)은 지원하지 않습니다. USD 가격 = Fragment 가격 + 5% (센트 단위 올림).
/usd/wallet달러 잔액, TON 주소와 개인 메모, BEP20 주소 (QR 이미지 포함).
{
"ok": true,
"usd": { "balance": "12.50", "micros": 12500000 },
"min_deposit": "1.00",
"ton": { "address": "UQ...", "memo": "...", "enabled": true, "ttl_min": 30 },
"bsc": { "address": "0x...", "contract": "0x55d398326f99059fF775485246999027B3197955", "enabled": true, "ttl_min": 30 }
}usd.balance는 달러 잔액(문자열), usd.micros: 1 USD = 1,000,000 micros.
/usd/invoice{"amount": 10, "chain": "ton"} 또는 "chain": "bsc" → 30분간 유효한 정확한 금액 (예: 10.0437). 선택한 네트워크의 주소로 그 금액의 USDT를 정확히 보내세요 (TON은 메모 불필요). /usd/bsc-invoice는 이전 이름으로 계속 작동합니다 (기본값: bsc).
/usd/invoice/{id}/cancel대기 중인 인보이스를 취소합니다 (예: 금액 변경). 취소된 정확한 금액은 24시간 동안 다른 사람에게 배정되지 않으며, 그 사이 도착한 결제도 잔액에 반영됩니다.
/usd/invoice/{id}상태: pending, paid, expired, cancelled.
/usd/quote{"kind":"stars","username":"durov","quantity":100} 또는 {"kind":"premium","username":"durov","months":3} → {"usd": 1.58}.
달러 잔액으로 결제하려면 /stars/buy 또는 /premium/buy payload에 "currency": "USD"와 /usd/quote에서 받은 "max_usd": 1.58을 추가하세요. Fragment 가격이 max_usd를 넘으면 차감 없이 409 price_changed가 반환되니 새 견적을 받으세요. currency를 생략하면 계정에 저장된 통화 설정(/usd/wallet의 pref)이 쓰이므로 항상 "currency": "USD"를 보내세요. 응답의 cost와 balance는 currency 필드의 통화 기준입니다.
curl -X POST https://paystars.uz/api/v1/stars/buy \
-H "X-API-Key: $PAYSTARS_API_KEY" -H "Idempotency-Key: stars_8f2c1a9b" \
-H "Content-Type: application/json" \
-d '{"username":"durov","quantity":100,"verification_token":"...","currency":"USD","max_usd":1.58}'주문
/orders웹사이트, WebApp, API로 들어온 최근 50개 주문을 반환합니다.
/order/{order_id}curl https://paystars.uz/api/v1/order/1842 \
-H "X-API-Key: $PAYSTARS_API_KEY"오류
| Status | 의미 | 조치 |
|---|---|---|
| 400 | payload 또는 멱등 키 오류 | 요청 형식을 확인하세요 |
| 401 | 유효하지 않은 API 키 | 새 키를 만드세요 |
| 402 | USD 잔액 부족 | USDT로 충전하세요 |
| 409 | 확인 만료/사용됨 또는 멱등 충돌 | 수신자를 다시 확인하세요 |
| 422 | 유저네임 또는 서비스 사용 불가 | 수신자를 확인하세요 |
| 402 | insufficient_balance (USD) | 달러 잔액을 USDT로 충전하세요 |
| 409 | price_changed — USD 가격이 max_usd 초과 | 새 /usd/quote를 받으세요 |
| 429 | 요청 한도 초과 | Retry-After 이후 재시도 |
| 503 | 일시적으로 서비스 불가 | 지수 백오프를 사용하세요 |
{
"detail": {
"code": "insufficient_balance",
"message": "StarKerak balance is insufficient"
}
}실행 가능한 예제
여러 프로그래밍 언어 예제
각 예제는 수신자를 확인하고 단기 토큰을 받은 뒤, 같은 주문을 안전하게 재시도할 수 있도록 멱등 키를 사용합니다. 모든 예제는 USD 잔액으로 결제합니다.
API="https://paystars.uz/api/v1"
ORDER_KEY="stars_$(uuidgen)"
VERIFY=$(curl --fail-with-body -sS -X POST "$API/check-username" \
-H "X-API-Key: $PAYSTARS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"username":"telegram","kind":"stars"}')
TOKEN=$(printf '%s' "$VERIFY" | jq -r '.verification_token')
curl --fail-with-body -sS -X POST "$API/stars/buy" \
-H "X-API-Key: $PAYSTARS_API_KEY" \
-H "Idempotency-Key: $ORDER_KEY" \
-H "Content-Type: application/json" \
-d "{\"username\":\"telegram\",\"quantity\":100,\"verification_token\":\"$TOKEN\",\"currency\":\"USD\"}"import { randomUUID } from 'node:crypto';
const base = 'https://paystars.uz/api/v1';
const headers = { 'X-API-Key': process.env.PAYSTARS_API_KEY, 'Content-Type': 'application/json' };
const verify = await fetch(`${base}/check-username`, {
method: 'POST', headers, body: JSON.stringify({ username: 'telegram', kind: 'stars' })
}).then(async r => { if (!r.ok) throw new Error(await r.text()); return r.json(); });
const order = await fetch(`${base}/stars/buy`, {
method: 'POST', headers: { ...headers, 'Idempotency-Key': `stars_${randomUUID()}` },
body: JSON.stringify({ username: verify.username, quantity: 100, verification_token: verify.verification_token, currency: 'USD' })
}).then(async r => { if (!r.ok) throw new Error(await r.text()); return r.json(); });
console.log(order.order_id, order.status);import os, uuid, requests
base = "https://paystars.uz/api/v1"
headers = {"X-API-Key": os.environ["PAYSTARS_API_KEY"]}
verify = requests.post(f"{base}/check-username", headers=headers,
json={"username": "telegram", "kind": "premium"}, timeout=15)
verify.raise_for_status()
recipient = verify.json()
order = requests.post(f"{base}/premium/buy", headers={
**headers, "Idempotency-Key": f"premium_{uuid.uuid4()}"
}, json={"username": recipient["username"], "months": 3,
"verification_token": recipient["verification_token"], "currency": "USD"}, timeout=20)
order.raise_for_status()
print(order.json())<?php
$base = 'https://paystars.uz/api/v1';
$key = getenv('PAYSTARS_API_KEY');
function postJson($url, $headers, $body) {
$ch = curl_init($url);
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true,
CURLOPT_HTTPHEADER => $headers, CURLOPT_POSTFIELDS => json_encode($body), CURLOPT_TIMEOUT => 20]);
$raw = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch);
if ($status < 200 || $status >= 300) throw new RuntimeException($raw);
return json_decode($raw, true, flags: JSON_THROW_ON_ERROR);
}
$common = ["X-API-Key: $key", 'Content-Type: application/json'];
$user = postJson("$base/check-username", $common, ['username' => 'telegram', 'kind' => 'stars']);
$order = postJson("$base/stars/buy", [...$common, 'Idempotency-Key: stars_'.bin2hex(random_bytes(16))],
['username' => $user['username'], 'quantity' => 100, 'verification_token' => $user['verification_token'], 'currency' => 'USD']);
print_r($order);package main
import ("bytes"; "encoding/json"; "fmt"; "io"; "net/http"; "os"; "github.com/google/uuid")
func post(path string, body any, idempotency string, out any) error {
data, _ := json.Marshal(body)
req, _ := http.NewRequest("POST", "https://paystars.uz/api/v1"+path, bytes.NewReader(data))
req.Header.Set("X-API-Key", os.Getenv("PAYSTARS_API_KEY")); req.Header.Set("Content-Type", "application/json")
if idempotency != "" { req.Header.Set("Idempotency-Key", idempotency) }
res, err := http.DefaultClient.Do(req); if err != nil { return err }; defer res.Body.Close()
if res.StatusCode >= 300 { raw, _ := io.ReadAll(res.Body); return fmt.Errorf("API %d: %s", res.StatusCode, raw) }
return json.NewDecoder(res.Body).Decode(out)
}
func main() {
var user struct { Username string `json:"username"`; VerificationToken string `json:"verification_token"` }
if err := post("/check-username", map[string]any{"username":"telegram", "kind":"stars"}, "", &user); err != nil { panic(err) }
var order map[string]any
if err := post("/stars/buy", map[string]any{"username":user.Username, "quantity":100,
"verification_token":user.VerificationToken, "currency":"USD"}, "stars_"+uuid.NewString(), &order); err != nil { panic(err) }
fmt.Println(order)
}프롬프트 하나로 연동
AI 프롬프트
아래 프롬프트를 Codex, ChatGPT 등 코딩 에이전트에 보내세요. 대괄호 안의 값은 프로젝트에 맞게 바꾸세요.
너는 시니어 백엔드 및 애플리케이션 보안 엔지니어야. PayStars API와의 완전하고 운영 환경에 바로 쓸 수 있는 연동을 만들어 줘.
프로젝트 유형: [텔레그램 봇 / 웹 백엔드 / 모바일 앱 백엔드]
언어와 프레임워크: [예: Python 3.12 + aiogram 3 + FastAPI]
프로젝트 이름: [이름]
PayStars base URL: https://paystars.uz/api/v1
API 키는 PAYSTARS_API_KEY 환경 변수에서만 읽어. 프론트엔드, 로그, Git, 오류 메시지에 절대 노출하지 마. 모든 요청은 HTTPS로, 서버 측에서 보내. 타임아웃, 구조화된 로깅(비밀값 제외), 입력 검증, 테스트를 추가해.
다음 흐름을 완전히 구현해:
1. GET /usd/wallet으로 USD 잔액을 가져와. 가격을 하드코딩하지 말고, 매 구매 전에 POST /usd/quote로 USD 가격(Fragment 가격 + 5%)을 받아.
2. 스타나 프리미엄 구매 전에 POST /check-username에 {"username":"...","kind":"stars|premium"}을 보내.
3. 응답의 valid, nickname, photo_url, premium_active, verification_token을 확인해. 사용자에게 사진, 이름, @username, 프리미엄 상태를 보여 주고 명시적 확인을 받아. 확인 없이 주문을 만들지 마.
4. verification_token은 180초 동안 유효해. 만료되거나 409가 오면 유저네임을 다시 확인해.
5. 스타는 POST /stars/buy에 username, quantity, verification_token을, 프리미엄은 POST /premium/buy에 username, months(3, 6, 12), verification_token을 보내. 모든 구매에 "currency": "USD"와 견적 가격을 "max_usd"로 보내고, 409 price_changed면 새 견적을 받고, 402 insufficient_balance면 사용자에게 USDT(TON 또는 BEP20)로 USD 잔액 충전을 안내해.
6. 논리적 주문마다 암호학적 UUID 기반 8–128자 Idempotency-Key를 만들어. 네트워크 재시도에는 정확히 같은 키와 payload를 재사용하고, 다른 주문에는 절대 재사용하지 마.
7. GET /order/{order_id}로 상태를 폴링하고 GET /orders로 내역을 보여 줘. processing/pending/completed/failed 상태를 올바르게 처리해.
8. API 한도는 키당 초당 3회야. 429에서는 Retry-After를 따르고, 503과 일시적 네트워크 오류에는 지터를 넣은 제한된 지수 백오프를 써. 400, 401, 402, 409, 422, 429, 503에 대해 안전하고 이해하기 쉬운 메시지를 보여 줘.
9. API 응답을 맹신하지 마: 스키마로 검증하고, 유저네임을 정규화하고, quantity/months 한도를 서버에서 검사해. photo_url은 허용된 HTTPS 이미지로만 표시해. verification token, API 키, 전체 요청 헤더는 절대 로깅하지 마.
10. 같은 사용자의 동시 클릭, 리플레이, 중복 주문, 위조 콜백, 경쟁 상태, 타임아웃, 프로세스 재시작을 처리해. 상태는 트랜잭션으로 DB에 저장하고 사용자 확인을 주문에 연결해.
프로젝트가 텔레그램 봇이면: /start, "스타 구매", "프리미엄 구매", "잔액", "주문" 메뉴를 만들고, 유저네임과 수량을 단계별로 받고, 확인 후 인라인 "확인/취소" 버튼을 보여 주고, 콜백 소유자와 TTL을 검사하고, 웹훅 시크릿이나 롱폴링 보안을 설정해.
의사 코드가 아니라 실행 가능한 실제 코드를 줘: 정확한 폴더 구조, 의존성 파일, .env.example(실제 비밀값 없이), DB 마이그레이션, Dockerfile, 헬스체크, README, 로컬 실행 및 배포 안내, 단위/통합 테스트. API 클라이언트는 별도 모듈로 분리해. 모든 가격, 잔액, 주문의 유일한 기준은 PayStars API로 하고, StarKerak 데이터베이스에 직접 연결하지 마. 부족한 비즈니스 값은 먼저 짧은 목록으로 물어보고, 나머지 기술적 결정은 안전한 기본값으로 직접 마무리해.