API 문서
API 키 발급 → 캡처 요청 → 결과 조회. 모든 요청은 HTTPS와 Bearer 키 인증을 사용합니다. 로컬 개발 주소만 HTTP를 사용합니다.
1. 인증과 캡처 요청
작업 공간의 API 키에서 키를 발급하세요. 키 원문은 한 번만 표시되며 querystring에는 넣을 수 없습니다.
export BASE=https://url2shot.rexjeong.com
export KEY=YOUR_API_KEY
export REQUEST_ID=$(uuidgen)
curl -X POST "$BASE/v1/screenshots" \
-H "Authorization: Bearer $KEY" \
-H "Idempotency-Key: $REQUEST_ID" \
-H 'Content-Type: application/json' \
-d '{"url":"https://example.com","format":"png"}'
# 응답의 id로 상태 조회
curl "$BASE/v1/screenshots/JOB_ID" \
-H "Authorization: Bearer $KEY"
# status=succeeded 이후 다운로드 링크 발급
curl -X POST "$BASE/v1/screenshots/JOB_ID/download-url" \
-H "Authorization: Bearer $KEY"202는 작업 수락을 뜻합니다. 상태 조회가 HTTP 200이어도 status가 succeeded인지 확인하세요. 결과 URL은 별도 POST로 발급하며 최대 5분, 이미지 자체는 캡처 후 24시간 보관됩니다.
2. 상태 조회와 다운로드
const base = process.env.URL2SHOT_BASE ?? 'https://url2shot.rexjeong.com';
const headers = {
Authorization: 'Bearer ' + process.env.URL2SHOT_KEY,
'Content-Type': 'application/json'
};
// 네트워크 재전송에는 이 idempotency key를 그대로 사용합니다.
const idempotencyKey = crypto.randomUUID();
const created = await fetch(base + '/v1/screenshots', {
method: 'POST',
headers: { ...headers, 'Idempotency-Key': idempotencyKey },
body: JSON.stringify({ url: 'https://example.com' })
});
if (!created.ok) throw new Error(await created.text());
const { id } = await created.json();
let downloadUrl;
for (let attempt = 0; attempt < 90; attempt++) {
const response = await fetch(base + '/v1/screenshots/' + id, { headers });
if (!response.ok) throw new Error(await response.text());
const job = await response.json();
if (job.status === 'succeeded') {
const link = await fetch(base + '/v1/screenshots/' + id + '/download-url', {
method: 'POST', headers
});
if (!link.ok) throw new Error(await link.text());
downloadUrl = (await link.json()).url;
break;
}
if (['failed', 'expired'].includes(job.status)) throw new Error(job.error.code);
await new Promise(resolve => setTimeout(resolve, 3500));
}
if (!downloadUrl) throw new Error('Query this job again later: ' + id);
console.log(downloadUrl);조회 간격은 2초 이상을 권장합니다. 클라이언트 타임아웃 이후에도 작업은 계속되므로 job ID로 다시 조회하세요. 새 멱등 키를 만들면 별도 요청으로 계산됩니다.
SDK와 MCP로 연결
Node.js 24+ JavaScript/TypeScript SDK와 Python 3.11+ SDK에서 캡처, 완료 대기, 파일 저장과 사용량 조회를 지원합니다. 현재는 저장소의 로컬 패키지로 설치하며, npm·PyPI 공개 게시 전입니다.
# 저장소 루트에서 빌드 후 실행
npm run sdk:build
export URL2SHOT_BASE=https://url2shot.rexjeong.com
export URL2SHOT_KEY=YOUR_API_KEY
node examples/capture.mjs
# TypeScript: node examples/capture.ts예제는 기본 로컬 데모 URL을 캡처합니다. 원격 서비스에서는 URL2SHOT_TARGET=https://example.com을 지정하세요. MCP는 로컬 stdio 연결로 capture, get_screenshot, get_usage 도구를 제공합니다. 원격 HTTP MCP와 OAuth 연결은 제공하지 않습니다.
SDK는 캡처 POST를 자동 재시도하지 않습니다. 같은 요청을 재전송할 때는 저장한 멱등 키와 옵션을 유지하세요. 설치와 오류 처리, MCP 호스트 설정은 저장소의 packages/sdk/README.md, packages/python/README.md, packages/mcp/README.md에 있습니다.
애플리케이션에서 호출
설치 후 사용할 코드입니다. API 키와 서비스 주소는 환경변수로 설정하세요.
import { randomUUID } from 'node:crypto';
import { Url2Shot } from '@url2shot/sdk';
const apiKey = process.env.URL2SHOT_KEY;
const baseUrl = process.env.URL2SHOT_BASE;
if (!apiKey || !baseUrl) throw new Error('URL2SHOT_KEY와 URL2SHOT_BASE를 설정하세요.');
const client = new Url2Shot({ apiKey, baseUrl });
const key = randomUUID(); // 요청 전에 저장하고 재전송에 같은 키 사용
const job = await client.captureAndWait(
{ url: 'https://example.com', format: 'png' },
{ idempotencyKey: key },
);
await client.save(job.id, 'capture-' + job.id + '.png');
const usage = await client.getUsage();MCP 설정의 경로는 실제 저장소 절대 경로로 바꾸세요. stdio 프로세스를 실행하는 클라이언트가 필요하며, 설정 형식은 호스트에 따라 다릅니다. capture에 input과 idempotency_key를 전달하고 반환된 job.id로 get_screenshot을 조회합니다. get_usage는 같은 계정의 사용량을 반환합니다.
3. 캡처 옵션
표를 좌우로 밀어 전체 내용을 확인하세요.
| 필드 | 기본값 | 범위 |
|---|---|---|
| url | 필수 | 공개 HTTP(S) 도메인 · 2,048bytes 이하 |
| viewport | 1280 × 720 | 너비 320–1920 · 높이 240–1080 |
| full_page | false | 상단 최대 6,000px, 가로는 viewport 폭 |
| format | png | png 또는 jpeg |
| quality | 80 (JPEG) | JPEG만 40–90 · PNG에 주면 422 |
| wait_ms | 500 | 0–2,000ms 추가 대기 |
| cache_ttl_seconds | 300 | 0–300초 · 0이면 캐시 우회 |
사용량과 멱등성
성공한 새 작업당 1회를 사용합니다. 캐시 hit도 1회이며 동일한 Idempotency-Key 재전송은 추가 차감하지 않습니다. 처리 중에는 1회를 예약하고 최종 실패 시 환원합니다. 멱등 기록은 7일간 보관합니다. 같은 키에 다른 입력을 보내면 409입니다.
기간 한도를 넘으면 429 QUOTA_EXCEEDED를 반환하며 자동 초과 결제는 없습니다. 상태 조회와 다운로드 링크 발급은 캡처 횟수를 차감하지 않습니다. 보관 만료나 삭제는 이미 사용한 크레딧을 돌려주지 않습니다.
지원 범위
공개 HTML 페이지, 일반적인 JavaScript 렌더링, PNG·JPEG를 지원합니다. DPR 1, 영어 locale, UTC, light scheme으로 고정합니다. 최대 이미지 10MiB, 캡처 시도 30초, 작업 전체 마감 5분입니다.
6,000px보다 긴 페이지는 상단을 캡처하고 PAGE_TRUNCATED 경고를 반환합니다. 실패가 아닌 정상 캡처 1회로 계산됩니다. 폰트·이미지·lazy load의 일부가 완료되지 않으면 warnings를 확인하세요.
로그인·고객 쿠키·CAPTCHA 우회·사용자 스크립트·국가별 프록시·사이트별 수정은 지원하지 않습니다. 네트워크 정책상 GET/HEAD만 사용하며 POST·WebSocket·Service Worker가 필수인 사이트는 일부 내용이 누락될 수 있습니다. HTTP 200 오류 화면이나 동의 배너를 모두 감지하는 서비스는 아닙니다.
무료 체험은 평생 25회, 하루 렌더 시도 10회·평생 50회입니다. 유료 플랜은 동시 2개·분당 생성 30회·키당 20회·기간당 시도 3,000회입니다. 실패도 실행 안전 한도에는 포함됩니다.
오류 처리
표를 좌우로 밀어 전체 내용을 확인하세요.
| 코드 | 대응 |
|---|---|
INVALID_API_KEY | 키를 확인하거나 새 키를 발급하세요. |
URL_NOT_ALLOWED | 공개 도메인과 표준 포트만 사용하세요. |
TARGET_BLOCKED | 봇 차단·CAPTCHA 페이지입니다. 자동 재시도하지 마세요. |
TARGET_HTTP_ERROR | 원본 사이트가 오류 HTTP 상태를 반환했습니다. |
RENDER_TIMEOUT / RESOURCE_LIMIT | 페이지가 실행 시간·자원 상한을 초과했습니다. |
RATE_LIMITED | Retry-After에 따라 기다리세요. |
QUOTA_EXCEEDED | 잔여 크레딧 또는 결제 기간을 확인하세요. |
SERVICE_PAUSED | 운영 예산 또는 공급자 상태로 수락을 중단했습니다. |
RESULT_EXPIRED | 새 멱등 키로 새로운 캡처가 필요합니다. |
전체 계약
다운로드한 계약의 servers.url을 사용할 서비스 주소로 설정하세요. 현재 주소는 https://url2shot.rexjeong.com입니다.
OpenAPI 3.1 계약 다운로드 · 오류를 기록할 때는 API 키나 URL querystring 대신 응답의 request_id를 보관하세요.