문서키 발급부터 첫 클립까지
첫 생성에 필요한 모든 것: 키, 요청 하나, 작업, 그리고 웹훅.
개발자 API는 신청제입니다.
개요
HTTPS 기반 REST이며, JSON으로 주고받습니다. 모든 생성은 비동기로 처리됩니다.
- 기본 URL
https://api.pershot.app/v1- 인증
- Authorization: Bearer 뒤에 키를 붙입니다. 키는 sk_test_ 또는 sk_live_로 시작하며 한 번만 표시되고, 당사는 해시만 저장합니다.
- 키 권한
- 각 키에는 범위가 있으며, 스튜디오에서 설정한 경우 모델과 도구의 허용 목록도 있습니다. 허용 목록이 있는 키는 목록에 있는 것만 사용할 수 있으며, 여기에는 이미지 업스케일, 배경 제거, 화질 향상, 립싱크, 아웃페인팅, 이미지 편집기 같은 도구도 포함됩니다. 그 밖의 요청은 403 forbidden_model로 응답합니다. 화질 향상으로 1080p나 4K를 만들려면 동영상 모델과 화질 향상이 모두 필요합니다.
- 오류 형식
{ "error": { "code", "message", "param", "request_id" } }- ID
- 유형별 접두사가 붙습니다: job_, qt_, key_, up_.
- OpenAPI
- /api/v1/openapi.json
- AI 에이전트용
- AI 에이전트용 텍스트: 입력, 허용 값, 설정별 가격, 요청 예시
seedance-2.0-fastseedance-2.0-miniqwen-image-2512-lightningqwen-image-2512qwen-image-edit-2511-lightningqwen-image-edit-2511
실제 생성은 아직 열리지 않았습니다. 모델 페이지에 이메일을 남겨 주시면 열릴 때 한 번만 연락드리겠습니다.
빠른 시작
네 단계이며, 단계마다 받아야 할 응답을 함께 보여 줍니다.
- 01
키 받기
개발자 API는 신청제입니다. 스튜디오의 API 키 메뉴에서 신청하세요. 이용이 열리면 그곳에서 키를 만들고 바로 복사하세요. 전체 키는 한 번만 표시됩니다.
export API_KEY="sk_test_…" - 02
요청 보내기
Idempotency-Key와 max_credits 상한을 넣어 샷을 POST 요청으로 보내세요. 곧바로 202와 대기 중인 작업을 받으며, 크레딧이 보류됩니다.
curl https://api.pershot.app/v1/videos/generations \ -H "Authorization: Bearer $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "model": "seedance-2.0-fast", "prompt": "Perfume mist in hard side light. Slow push-in, black background, grain.", "duration": 5, "resolution": "720p", "aspect_ratio": "16:9", "generate_audio": true, "max_credits": 34 }'{ "id": "job_01J9ZK4T8W", "object": "job", "kind": "video", "status": "queued", "money_status": "reserved", "queue_position": 2, "requested_model": "seedance-2.0-fast", "credits_quoted": 34, "credits_charged": null } - 03
작업 확인
status가 succeeded가 될 때까지 작업을 GET으로 조회하세요. 출력 URL은 서명된 링크이며 만료되므로, 보관할 파일은 다운로드하세요.
curl https://api.pershot.app/v1/jobs/job_01J9ZK4T8W \ -H "Authorization: Bearer $API_KEY"{ "id": "job_01J9ZK4T8W", "object": "job", "kind": "video", "status": "succeeded", "money_status": "settled", "requested_model": "seedance-2.0-fast", "resolved_model": "seedance-2.0-fast", "credits_quoted": 34, "credits_charged": 34, "outputs": [ { "kind": "video", "url": "https://…/job_01J9ZK4T8W.mp4?sig=…", "width": 1280, "height": 720, "duration_s": 5 } ], "error": null } - 04
웹훅 받기
webhook_url을 전달하면 상태가 바뀔 때마다 타임스탬프로 서명된 POST 요청을 보내 드립니다. 2xx로 응답하세요. 전송에 실패하면 간격을 늘려 가며 재시도합니다.
{ "id": "evt_01J9ZKB1QX", "type": "job.succeeded", "created_at": "2026-09-29T14:02:31Z", "data": { "job": { "id": "job_01J9ZK4T8W", "object": "job", "status": "succeeded", "money_status": "settled", "credits_charged": 34, "outputs": [ { "kind": "video", "url": "https://…/job_01J9ZK4T8W.mp4?sig=…", "width": 1280, "height": 720, "duration_s": 5 } ] } } }
엔드포인트
모든 경로는 기본 URL을 기준으로 합니다.
| 메서드 | 경로 | 기능 |
|---|---|---|
| GET | /v1/models | 내 계정에서 사용할 수 있는 모델, 기능, 상태 |
| GET | /v1/pricing | 공개 가격, 로그인한 경우 내 계정의 가격 |
| POST | /v1/quotes | 계획, 항목별 내역, 최대 청구액, 만료 시각(10분) |
| POST | /v1/videos/generations | 동영상 생성, 202와 작업 반환 |
| POST | /v1/images/generations | 이미지 생성 또는 편집, 202와 작업 반환 |
| GET | /v1/jobs/{id} | 상태, 서명된 링크로 된 출력물, 실제 비용 |
| GET | /v1/jobs | 내 작업, 최신순 |
| POST | /v1/jobs/{id}/cancel | 취소 요청, 모델이 이미 작업을 수락한 경우가 아니면 보류된 크레딧이 환불됨 |
| GET | /v1/balance | 버킷별 사용 가능 크레딧과 보류된 크레딧 |
| GET | /v1/usage | 일별 또는 모델별 사용량, JSON 또는 CSV |
| POST | /v1/uploads | 최대 10 MB의 JPEG, PNG 또는 WebP 업로드 |
견적과 상한
모든 생성 요청에는 quote_id 또는 max_credits 상한 중 하나가 필요하며, 둘을 함께 보낼 수는 없습니다. quote_id를 보내면 작업이 그 견적대로 실행되고, max_credits를 보내면 가격이 상한 이하일 때만 실행됩니다.
model: "auto"에는 항상 max_credits가 필요합니다. 견적은 10분 동안 유효하며, 그 이후에는 quote_expired가 반환됩니다.
멱등성
모든 생성 요청에 Idempotency-Key 헤더(눈에 보이는 ASCII 문자 1~255자)를 보내세요.
24시간 이내에 같은 키로 요청하면 202 대신 HTTP 200과 함께 같은 작업이 반환되므로, 시간 초과 후 재시도해도 두 번째 작업이 생성되거나 청구되지 않습니다.
웹훅
생성 요청(또는 일괄 생성)에 webhook_url을 전달하면 상태 변경을 받을 수 있습니다. 각 이벤트는 id, type, created_at, data가 담긴 JSON 본문의 POST 요청이며, 작업 이벤트는 data.job, batch.completed는 data.batch를 포함합니다.
이벤트
job.queuedjob.processingjob.succeededjob.failedjob.cancelledbatch.completed
- 각 전송에는 이벤트 ID, 타임스탬프, 서명이 있습니다. 본문을 신뢰하기 전에 서명을 검증하세요.
- 엔드포인트가 10초 이내에 2xx로 응답하면 전송된 것으로 간주합니다. 그렇지 않으면 1분, 5분, 30분, 2시간, 6시간 후에 재시도한 뒤 실패로 표시하며, 지원팀이 다시 보낼 수 있습니다. 리디렉션은 따르지 않습니다.
- 웹훅 URL은 https여야 합니다. 사설, 루프백 또는 예약된 주소의 호스트는 제출할 때와 연결할 때 모두 거부됩니다.
헤더
X-Signaturet=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>X-Event-Id- 이벤트 ID이며 본문에도 들어 있습니다. 재시도와 재전송에도 그대로 유지되므로, 저장해 두고 이미 처리한 ID는 건너뛰세요.
- 서명 시크릿
- 계정마다 whsec_… 시크릿이 하나 있으며, 스튜디오의 API 키 메뉴에서 확인할 수 있습니다. HMAC 키는 접두사를 포함한 시크릿 전체입니다.
- 교체
- 교체한 후 24시간 동안은 이전 시크릿도 두 번째 v1 항목으로 계속 서명합니다. v1 중 하나라도 일치하면 전송을 수락하세요.
다시 직렬화한 사본이 아니라 원본 본문으로 HMAC을 계산하고, 상수 시간으로 비교하며, 5분보다 오래된 타임스탬프는 거부하세요.
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody: the request body exactly as received, before any JSON parsing.
export function verifyWebhook(header, rawBody, secret, toleranceSec = 300) {
let t = null;
const signatures = [];
for (const item of (header ?? "").split(",")) {
const [key, value] = item.split("=", 2);
if (key === "t") t = Number(value);
if (key === "v1") signatures.push(Buffer.from(value, "hex"));
}
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
return signatures.some((s) => s.length === expected.length && timingSafeEqual(s, expected));
}
// verifyWebhook(req.headers["x-signature"], rawBody, process.env.WEBHOOK_SECRET)
// Answer 2xx quickly, and skip an X-Event-Id you have already handled.오류
코드와 HTTP 상태는 고정되어 있으며, message는 사람이 읽기 위한 것입니다.
| 코드 | HTTP | 발생 조건 |
|---|---|---|
invalid_request | 400 | 필드가 없거나 범위를 벗어남 |
unauthorized | 401 | 키가 없거나, 폐기된 키이거나, 서명이 잘못됨 |
insufficient_credits | 402 | 잔액이 보류액을 충당하지 못함 |
forbidden_model | 403 | 키의 허용 목록에 이 모델이나 도구가 없음 |
region_not_supported | 403 | 현재 지역에서 제공되지 않는 모델 |
developer_api_closed | 403 | 개발자 API가 닫혀 있을 때의 개발자 키. 이용은 신청제 |
member_connections_paused | 403 | 내 AI 에이전트 연결이 일시 중지된 동안의 회원 로그인(MCP, 연결 코드, 명령줄) |
not_found | 404 | 내 계정에 해당 작업, 견적 또는 업로드가 없음 |
quote_expired | 409 | 견적이 10분보다 오래됨 |
price_changed | 409 | 가격이 상한보다 올라감 |
content_rejected | 422 | 콘텐츠가 거부됨, 청구 없음 |
rate_limited | 429 | 이 키의 요청이 너무 많음 |
concurrency_limited | 429 | 이 계정에서 실행 중인 작업이 너무 많음 |
internal_error | 500 | 당사 쪽에서 문제가 발생함 |
upstream_unavailable | 503 | 모델을 이용할 수 없음, 나중에 재시도 |
모델의 결과가 불확실한 것은 오류가 아닙니다. 작업 상태가 unknown으로 표시되며, 다시 제출하기 전에 확인합니다.
한도
- 요청
- 기본적으로 키당 분당 60회.
- 동시 실행
- 기본적으로 계정당 동시 작업 3개이며, 요청하면 늘릴 수 있습니다.
- 최대치
- 모델의 처리 용량이 절대적인 최대치입니다. 키를 늘려도 동시 실행 수는 늘어나지 않습니다.
이미지
POST /v1/images/generations는 같은 헤더를 사용합니다. 등급과 작업 유형에 따라 모델 ID를 고르세요. 편집 모델은 image_url도 필요하며, 생성 모델은 이를 거부합니다.
| 등급 | 생성 | 편집 |
|---|---|---|
| Image Mini이코노미 · 초안 | qwen-image-2512-lightning | qwen-image-edit-2511-lightning |
| Image Fast추천 | qwen-image-2512 | qwen-image-edit-2511 |
모델별 한도
모든 모델의 API 페이지에 값, 단위, 검사 주체, 한도 초과 시 동작을 담은 전체 표가 있습니다. GET /v1/models도 같은 한도를 JSON으로 반환합니다.
- 강제 적용당사가 검사하며, 견적이나 보류 전에 400으로 응답합니다.
- 공급사공급업체가 검사합니다. 공급업체가 거부한 작업은 실패하며, 비용은 청구되지 않습니다.
- 권장아무도 검사하지 않습니다. 범위 안에 머물면 더 좋은 결과를 얻을 수 있습니다.
| 모델 | 주요 한도 | 전체 표 |
|---|---|---|
seedance-2.0-fastSeedance 2.0 Fast | 프롬프트 2~2,000자 · 4~15초 · 참조 이미지 최대 9장 · 이미지 변당 300~6,000 px | 표 열기 |
seedance-2.0-miniSeedance 2.0 Mini | 프롬프트 2~2,000자 · 4~15초 · 참조 이미지 최대 9장 · 이미지 변당 300~6,000 px | 표 열기 |
qwen-image-2512Qwen-Image-2512 | 프롬프트 2~2,000자 · 1K 또는 2K · 원본 이미지 없음 | 표 열기 |
qwen-image-2512-lightningQwen-Image-2512 · Lightning 4-step | 프롬프트 2~2,000자 · 1K 또는 2K · 원본 이미지 없음 | 표 열기 |
qwen-image-edit-2511Qwen-Image-Edit-2511 | 프롬프트 2~2,000자 · 1K 또는 2K · 원본 이미지 1장, 최대 10 MB의 JPEG, PNG 또는 WebP | 표 열기 |
qwen-image-edit-2511-lightningQwen-Image-Edit-2511 · Lightning | 프롬프트 2~2,000자 · 1K 또는 2K · 원본 이미지 1장, 최대 10 MB의 JPEG, PNG 또는 WebP | 표 열기 |
업로드
POST /v1/uploads는 파일 자체에서 형식을 읽습니다. 업로드 링크는 7일 동안 유효합니다.
| 파일 | 형식 | 최대 파일 크기 | 최대 길이 |
|---|---|---|---|
| 이미지: 첫 프레임, 참조 또는 편집 원본 | JPEG, PNG, WebP | 10 MB | – |
| 동영상: 립싱크 | MP4 | 50 MB | 60초 |
| 오디오: 립싱크 | MP3, WAV, M4A | 10 MB | 60초 |
당사는 다른 호스트의 이미지를 가져오지 않으므로, 그런 링크의 크기는 공급업체가 검사합니다. 공급업체가 거부한 작업에는 비용이 청구되지 않습니다. 같은 한도가 JSON으로도 반환됩니다. GET /v1/models는 모든 모델에 대해 limits 객체를 반환합니다.
fal, Replicate, WaveSpeed에서 옮겨 오는 경우
기본 URL과 키만 바꿔서는 충분하지 않습니다. 모든 요청에는 본문의 모델 ID, Idempotency-Key 헤더, 가격 상한(max_credits 또는 quote_id)도 필요합니다. 마이그레이션 가이드는 Seedance 2.0과 Qwen-Image의 모든 필드를 대응시키고, 그대로 옮겨지지 않는 것을 정리합니다.