Vercel Cron Jobs: 중복 없이 매일 Sume API 호출하기
Vercel cron job이 라우트에 GET을 보내면 라우트가 날짜 기반 Idempotency-Key로 Sume API를 호출하므로, 중복 호출이 두 번 과금될 수 없습니다.

Vercel cron job에서 API를 호출하려면 vercel.json에 crons 항목을 추가하세요. 그러면 Vercel이 프로덕션 배포의 해당 경로로 HTTP GET을 보내고, 여러분의 라우트가 API를 호출합니다. 매일 만드는 Sume 영상이라면 라우트가 날짜로 만든 Idempotency-Key와 함께 Format 실행 하나를 POST하므로, Vercel이 같은 예약 회차를 두 번 전달해도 두 번째 POST는 두 번째 실행을 시작하거나 과금할 수 없습니다.
Vercel 관련 내용은 Vercel의 Cron Jobs, Cron Jobs 관리, 사용량과 요금 페이지에서, Sume 관련 내용은 Format 호출하기 (영문)와 Scheduled에서 가져왔습니다. 모두 2026-09-27에 확인했습니다. Sume에는 Vercel 전용 커넥터가 없으며, cron 라우트는 HTTPS로 직접 호출합니다. 시계 말고는 작업을 일으키는 것이 없다면 Sume 자체의 Scheduled 기능이 여러분의 코드 없이 저장된 자동화를 정해진 주기로 실행합니다. AI 영상 에이전트 스케줄 실행을 참고하세요.
Vercel cron job은 내 라우트를 어떻게 호출하나요?
cron 항목마다 path와 schedule을 지정합니다. 예를 들어 매일 05:00 UTC라면 { "crons": [{ "path": "/api/cron/daily-video", "schedule": "0 5 * * *" }] }처럼 씁니다. 각 요청의 user agent는 vercel-cron/1.0이며, 호출을 트리거한 표현식은 x-vercel-cron-schedule 헤더에 담깁니다.
| 속성 | Vercel 동작 |
|---|---|
| 요청 | 프로덕션 배포 URL의 path로 보내는 HTTP GET |
| 시간대 | 항상 UTC |
| Hobby | 하루 최대 한 번, 더 잦으면 배포 실패. 예약한 시각이 속한 한 시간 안 어느 때든 실행 |
| Pro와 Enterprise | 최대 분당 한 번까지. 예약한 분 안에 실행 |
| 실행 시간 | Vercel Functions와 같은 한도 |
| 실패한 호출 | 재시도하지 않음 |
| 전달 | best effort 방식. 회차가 누락되거나 두 번 이상 호출될 수 있음 |
| 리다이렉트 | 따라가지 않음 |
다른 사람이 cron 라우트를 호출하지 못하게 하려면 어떻게 하나요?
프로젝트에 CRON_SECRET 환경 변수를 추가하세요. Vercel은 16자 이상의 무작위 문자열을 권장합니다. Vercel은 작업을 호출할 때 이 값을 Bearer 접두사와 함께 Authorization 헤더에 담아 보내므로, 라우트는 둘을 비교해 일치하지 않으면 401로 응답합니다. SUME_API_KEY도 프로젝트 환경 변수에 두고 서버에서만 쓰세요. 클라이언트 JavaScript나 NEXT_PUBLIC_* 변수에는 절대 넣지 마세요.
라우트는 Sume API에 무엇을 보내나요?
POST /v1/formats/{handle}/{slug}/runs 요청 하나입니다. 본문에는 instruction, input, previous_run_id, attachments 중 적어도 하나가 있어야 합니다. 키와 본문을 모두 날짜만으로 만들어, 같은 날 다시 호출되더라도 똑같은 요청을 보내게 하세요.
// app/api/cron/daily-video/route.ts
export async function GET(request: Request) {
const cronSecret = process.env.CRON_SECRET;
if (!cronSecret || request.headers.get("authorization") !== `Bearer ${cronSecret}`) {
return new Response("Unauthorized", { status: 401 });
}
const day = new Date().toISOString().slice(0, 10); // UTC, like the schedule
const res = await fetch("https://api.sume.com/v1/formats/acme/product-promo/runs", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SUME_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": `daily-promo-${day}`, // one run per UTC day
},
body: JSON.stringify({
instruction: `Make the daily promo video for ${day}.`, // date only
generation_spend_cap_usd: 3,
communication: { webhook_url: "https://example.com/api/sume-webhook" },
}),
});
const { data, error } = await res.json(); // 202 new run, 200 replay
if (!res.ok) return Response.json(error, { status: res.status });
await saveDailyRun(day, data.id); // your database
return Response.json({ runId: data.id, replay: data.idempotency_hit });
}Vercel이 같은 회차를 두 번 호출하면 어떻게 되나요?
Vercel은 cron 전달이 가끔 같은 예약 회차를 두 번 이상 호출할 수 있다고 밝히며, 작업을 멱등하게 만들라고 요청합니다. 날짜 키가 Sume 생성 요청을 멱등하게 만듭니다. 키 전반은 AI 영상 API 멱등성 키에서 다룹니다. 라우트는 실행되는 시점의 날짜를 읽으므로 스케줄을 UTC 자정 근처에 두지 마세요. Hobby에서는 호출이 예약한 시각이 속한 한 시간 안 어느 때든 일어날 수 있습니다.
| 상황 | Sume의 응답 |
|---|---|
| Vercel이 그날의 회차를 한 번 더 호출함 | 같은 키, 같은 본문: 원래 실행과 idempotency_hit: true가 담긴 200. 두 번째 실행도, 두 번째 청구도 없음 |
| 두 호출이 같은 순간에 Sume에 도착함 | 하나가 이기고, 다른 하나는 재시도할 수 있는 409 idempotency_key_in_use를 받음. 1초쯤 기다렸다가 다시 보내면 원래 실행을 받음 |
| 본문에 타임스탬프나 무작위 값이 들어 있음 | 같은 키, 다른 본문: 409 idempotency_conflict. 아무것도 실행되지 않음 |
첫 생성 요청이 실패함(402, 503, …) | 키가 해제되었으므로 그 키로 보내는 다음 호출이 그날의 실행을 시작할 수 있음 |
Vercel이 하루를 놓치면 어떻게 하나요?
Vercel은 실패한 cron 호출을 재시도하지 않으며, 일시적인 네트워크 오류 때문에 예약된 요청이 함수에 아예 도달하지 못할 수도 있습니다. Vercel이 권하는 방법은 조정(reconciliation)입니다. 각 회차가 마지막으로 성공한 회차 이후 밀린 작업을 처리하게 하는 것입니다.
- 위 라우트처럼 날짜별로 그날의 실행 ID(
data.id)를 저장하세요. - 호출될 때마다 저장된 실행이 없는 날을 찾고, 아직 영상이 필요한 날은 그날 고유의 키와 본문으로 제출하세요.
- 어떤 날이 이미 실행됐는지는 키가 아니라 저장된 ID로 판단하세요. 실행이 실패한 날에는 날짜에 직접 올리는 버전을 붙인 키 같은 새 키가 필요합니다. 이전 키는 이미 받은 영수증에 묶여 있기 때문입니다.
cron 함수에서 기다리지 않고 영상을 받으려면 어떻게 하나요?
Cron job은 Vercel Functions와 같은 실행 시간 한도(기본 300초)를 따르고, 영상을 만드는 실행은 초가 아니라 분 단위로 걸리므로, 라우트는 Sume가 실행을 수락하자마자 반환합니다. 본문의 communication.webhook_url은 실행이 완료되거나 실패할 때 서명된 format.run.terminal POST를 한 번 보내 달라는 요청입니다. 이를 받는 라우트는 Vercel 함수 타임아웃과 영상 생성에서 보여 주며, 실행의 result_url 읽기가 백업입니다.
출처
관련 글
연동 카테고리의 다른 글
- Windsurf MCP 서버: Devin Desktop에 Sume 추가
Windsurf는 이제 Devin Desktop입니다. API 키 헤더로 Sume 호스팅 MCP 서버를 Devin Local 에이전트나 레거시 Cascade 에이전트에 추가하세요.
- Zapier AI 영상 자동화: Zap 두 개와 Sume 웹훅 하나
Zap 하나는 Custom Request로 Sume 영상 실행을 시작하고, 두 번째 Zap은 Catch Raw Hook으로 Sume의 서명된 웹훅을 받아 Code 단계에서 검증합니다.
- Claude 커스텀 커넥터로 Sume 추가하기 (원격 MCP)
Customize > Connectors에서 Sume 호스팅 MCP 서버를 Claude에 추가하고, Sume OAuth 동의가 무엇을 부여하는지 확인한 뒤, 유료 도구를 허용할지 정하세요.
- Airtable 자동화 영상 생성 API: 레코드마다 영상 하나
Airtable Run a script 액션으로 callback_url과 함께 POST /v1/videos를 호출하고, 두 번째 자동화에서 Sume 웹훅을 받아 URL을 저장하세요.
작성자 Sume