개발자

Sume 영상 실행용 서명된 웹훅: 이벤트, 재시도, 검증

Format·Action·Agent Completion 실행이 완료되거나 실패하면 Sume가 HMAC-SHA256 서명 POST를 한 번 보냅니다. 원본 본문을 검증하고 request_id로 중복을 제거하세요.

읽는 시간 6분Sume
전체 글

Sume 실행 웹훅은 Action, Format, Agent Completion 실행이 완료되거나 실패했을 때 Sume가 communication.webhook_url로 보내는 서명된 POST 한 번이며, 폴링 엔드포인트가 반환하는 것과 같은 영수증을 담습니다. <timestamp>.<raw_body>에 대한 HMAC-SHA256으로 서명되므로, 수신기는 원본 본문을 검증하고 request_id로 중복을 제거한 뒤 2xx를 빠르게 반환합니다.

아래 규칙은 Sume의 Run 웹훅 (영문), 생성 Job용 웹훅 (영문), SDK 웹훅 검증 페이지를 바탕으로 합니다. 웹훅 전달은 프로덕션인 api.sume.com에서 동작하고 있으며, 폴링도 백업으로 계속 지원됩니다.

웹훅은 어떻게 요청하나요?

실행을 시작할 때 communication.webhook_url을 보내세요. 세 가지 실행 표면 모두 같은 방식으로 동작합니다.

  • URL은 공개 HTTPS여야 하며 최대 2048자입니다. localhost, 사설 네트워크, HTTPS가 아닌 URL은 400 invalid_request로 거부됩니다.
  • communication.callback_url도 별칭으로 받습니다. communication.mode는 async(기본값) 또는 webhook이지만 설명용일 뿐이며, 실제로 전달을 켜는 것은 URL입니다.
  • Sume는 전달 시점에 URL을 다시 검증합니다. 리다이렉트는 따라가지 않으므로 3xx는 전달로 치지 않습니다.
  • /v1/avatar-1.0/generate 같은 모델 엔드포인트의 생성 Job은 mode: "webhook"과 webhook_url을 받고, 대신 job.* 이벤트를 보냅니다.

엔드포인트는 어떤 이벤트를 받나요?

종료 이벤트만 받습니다. 실행은 에이전트 턴 한 번이므로, 그 턴이 클립이나 이미지를 몇 개 만들든 이벤트는 정확히 한 번 발생합니다. 실행을 이어 가면 자체 웹훅을 가진 새 실행이 시작됩니다. 결과는 이벤트 이름이 아니라 status와 payload.status에 담깁니다. 영수증 자체는 Format 실행 수명주기에서 다룹니다.

Run 웹훅 (영문)과 웹훅 (영문) 기준 이벤트 이름, 2026-09-25 확인.
호출한 대상이벤트중복 제거 기준
Format 실행format.run.terminalrun_id와 같은 request_id
Action 실행action.run.terminalrun_id와 같은 request_id
Agent Completion 실행agent.run.terminalrun_id와 같은 request_id
모델 엔드포인트 Jobjob.completed, job.failed, job.canceledjob_id

실행 웹훅 페이로드에는 무엇이 들어 있나요?

봉투가 실행 영수증을 감싸고 있습니다.

  • status는 실행이 완료됐으면 OK, 실패했으면 ERROR입니다. outcome은 ok, degraded, error 중 하나이며, 쓸 수 있는 결과물을 받았는지가 궁금하다면 이 값으로 분기하세요.
  • degraded는 실행이 완료되어 artifacts[]에 실제 미디어를 만들었지만 이를 output_schema에 투영하지 못해 output이 null이라는 뜻입니다.
  • request_id는 재시도해도 바뀌지 않으므로 중복 제거 키로 씁니다. 전달 순서는 created_at으로 정하세요.
  • payload는 GET /v1/{family}-runs/{run_id}의 data 객체와 바이트 단위로 같으므로, 핸들러 하나로 웹훅과 폴링을 모두 처리할 수 있습니다.
  • 1 MiB를 넘는 영수증은 payload: null과 오류 코드 payload_too_large로 도착합니다. result_url에서 가져오세요.
  • 취소되거나 건너뛴 실행은 실행 웹훅을 보내지 않습니다. 대신 취소 응답이나 생성 응답을 신뢰하세요.

웹훅 서명은 어떻게 검증하나요?

전달마다 x-sume-webhook-timestamp와 x-sume-webhook-signature: sume-v1=<hex_signature>가 실립니다. TypeScript에서는 아래 핸들러처럼 @sume-com/sdk의 verifyWebhook이 검증을 처리합니다. 중요한 점은 다음과 같습니다.

  • 원본 본문을 넘기세요. 키 순서와 공백도 서명 대상의 일부이므로, 파싱했다가 다시 직렬화한 객체는 검증되지 않습니다.
  • verifyWebhook은 async이고, 예외를 던지는 대신 false를 반환하며, 상수 시간으로 비교하고, 기본값이 300인 재전송 허용 시간 toleranceSeconds를 적용합니다.
  • 서명 시크릿은 대시보드의 웹훅 탭에서 보거나, account:read가 있는 키로 GET /v1/webhooks/signing-secret을 호출해 읽으세요. 이 시크릿은 워크스페이스별로 파생됩니다. SUME_COM_WEBHOOK_SIGNING_SECRET으로 저장하세요.
  • 서명이 검증되지 않으면 x-sume-webhook-secret-fingerprint 헤더를 대시보드에 표시된 지문과 비교하세요.
  • 실행 웹훅과 Job 웹훅은 시크릿 하나와 서명 방식 하나를 공유하므로, 검증기 하나로 둘 다 처리할 수 있습니다. event로 라우팅하고, 모르는 이벤트에는 204로 응답하세요.
import { verifyWebhook } from "@sume-com/sdk";

export async function POST(request: Request) {
  const body = await request.text(); // raw, before any JSON.parse
  const ok = await verifyWebhook({
    body,
    headers: request.headers,
    secret: process.env.SUME_COM_WEBHOOK_SIGNING_SECRET!,
  });
  if (!ok) return new Response("bad signature", { status: 401 });

  const event = JSON.parse(body);
  await recordTerminalRun(event.request_id, event); // dedupe on request_id
  return new Response(null, { status: 204 }); // fast 2xx, then work
}

엔드포인트가 다운되면 어떻게 되나요?

이벤트를 내구성 있게 기록한 뒤 어떤 2xx든 빠르게 반환하고, 처리는 그다음에 하세요. 전달 결과는 실행 자체를 절대 바꾸지 않습니다. 모든 시도가 거부되면 result_url에서 실행을 읽으세요.

  • 재전송(Redeliver)은 실제 종료 이벤트를 새 타임스탬프와 서명으로 다시 POST합니다. 자동 시도를 모두 소진한 뒤에도 동작하며, 자동 시도 10회 중 하나를 쓰지 않습니다.
  • 테스트 전송(POST /v1/webhooks/test-deliveries, account:write)은 더미 webhook.test 페이로드를 보냅니다. 실제 실행을 재생하는 것이 아닙니다.
Run 웹훅 (영문)과 웹훅 (영문) 기준 전달 규칙, 2026-09-25 확인.
속성실행 웹훅Job 웹훅
시도 횟수총 최대 10회, 이후 exhausted총 최대 10회
간격min(max(30s × 2^(attempt−1) with jitter, Retry-After), 1h)지수 백오프가 아닌 고정 지연, 기본 30초
타임아웃시도당 10초시도당 10초
재전송Format 실행: POST /v1/format-runs/{run_id}/webhook/redeliver(formats:write 필요)POST /v1/jobs/{job_id}/webhook/redeliver(jobs:write 필요)

웹훅 서명 시크릿은 어떻게 교체하나요?

웹훅 → 시크릿 교체를 사용하거나, account:write가 있는 키로 POST /v1/webhooks/signing-secret/rotate를 호출하세요. 교체는 즉시 전환이 아닙니다. 교체 후 24시간 동안 Sume는 모든 전달을 두 시크릿으로 각각 서명하고, 최신 서명부터 쉼표로 구분해 x-sume-webhook-signature에 담아 보냅니다. sume-v1= 항목 중 하나라도 일치하면 전달을 수락하세요.

@sume-com/sdk 0.2.0의 verifyWebhook은 이미 다중 서명 헤더를 처리합니다. 헤더를 문자열 일치로 비교하는 자체 구현 검증기는 이 기간 동안 모든 전달에서 실패하므로, 교체하기 전에 수신기를 먼저 업그레이드하세요.

출처

관련 글

작성자 Sume