웹훅

실행이 끝날 때까지 폴링하지 않고 완료 알림을 받습니다.

엔드포인트를 한 번 등록한 다음, 실행을 시작할 때 그 엔드포인트의 webhook_id를 전달하면, 해당 실행이 구독한 상태로 바뀌는 순간 저희가 호출합니다 — 보통 1분 이내입니다.

엔드포인트 등록

POST {base_url}/webhooks

{
  "url": "https://hooks.example.com/morphic",
  "events": ["workflow_run.succeeded", "workflow_run.failed"],
  "description": "story pipeline"
}

runs:write 권한이 필요합니다. URL은 자격 증명이 포함되지 않은 공개 https URL이어야 하며, 조직은 최대 10개의 엔드포인트를 보유할 수 있습니다.

201 응답에는 엔드포인트의 id(실행 시 webhook_id로 전달)와 한 번만 표시되는 서명 비밀키(whsec_…)가 담겨 있습니다. API 키처럼 보관하세요.

GET {base_url}/webhooks
DELETE {base_url}/webhooks/{webhook_id}

GET (runs:read)는 엔드포인트를 나열할 뿐, 비밀값은 절대 표시하지 않습니다. DELETE (runs:write)는 하나를 제거합니다. 해당 항목에 대해 아직 보류 중인 전달은 삭제됩니다. 비밀을 교체하려면 새 엔드포인트를 등록하고 실행을 그쪽으로 옮기세요.

이벤트

이벤트다음 경우에 발생
workflow_run.succeeded실행이 완료되었으며, 자산을 사용할 수 있습니다
workflow_run.failed실행이 중단되었습니다. error가 그 이유를 설명합니다
workflow_run.needs_input실행이 Morphic Studio의 사람을 기다리고 있습니다
workflow_run.expired실행이 수명 내에 끝나지 않았습니다

전달 내용

POST https://hooks.example.com/morphic
Morphic-Event-Id: 0192f4a0-3c71-7b92-8e14-5d6f2a9b3c07
Morphic-Delivery-Id: 0192f4a0-4d82-7c03-9f25-6e7a3b0c4d18
Morphic-Event-Type: workflow_run.succeeded
Morphic-Signature: t=1790056632,v1=3f9c1a…

{
  "id": "0192f4a0-3c71-7b92-8e14-5d6f2a9b3c07",
  "type": "workflow_run.succeeded",
  "created_at": "2026-09-22T04:17:12Z",
  "api_version": "v1",
  "data": {
    "run": { "id": "0192f3d0-…", "status": "succeeded", "assets": [], "credits_used": 1792 }
  }
}

run 객체는 워크플로우 실행 읽기가 반환하는 것과 같은 형태이며 assets도 포함됩니다 — 성공한 전달은 후속 호출이 필요 없습니다. 이는 이벤트가 발생했을 당시의 실행 상태이며, 전달 재시도 기간 동안에는 자산 링크가 약 하루 동안 유효합니다.

모든 전달 검증하기

서명 비밀키로 {timestamp}.{raw body}의 HMAC-SHA256을 계산한 뒤 v1과 상수 시간으로 비교하세요. JSON 파싱 전의 원시 본문을 사용하세요.

import crypto from 'node:crypto';

function verify({ rawBody, header, secret }) {
  const parts = Object.fromEntries(
    header.split(',').map((pair) => pair.split('=')),
  );

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest('hex');

  const signed = Buffer.from(expected);
  const given = Buffer.from(parts.v1);

  if (signed.length !== given.length) return false;
  if (!crypto.timingSafeEqual(signed, given)) return false;

  // Refuse a replayed delivery.
  return Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
}

검증되지 않은 웹훅 엔드포인트는 열린 문과 같습니다: URL만 알아도 실행이 성공했다고 알려줄 수 있습니다. 서명을 검증하고 5분이 지난 타임스탬프는 거부하세요.

재시도 및 순서

  • 10초 이내에 2xx로 응답하세요. 먼저 수신 확인을 하고, 그다음 작업을 수행하세요 — 느린 처리기는 실패로 간주됩니다.
  • 비-2xx 또는 타임아웃은 약 하루 동안 지수적 백오프로 재시도된 뒤 삭제됩니다. 리디렉션은 따르지 않으며, 실패로 간주됩니다.
  • 엔드포인트가 구독한 이벤트만 전송되며, 다른 상태에 도달한 실행은 이에 대해 아무 것도 보고하지 않습니다.
  • 전달은 순서가 뒤바뀌거나 여러 번 도착할 수 있습니다. Morphic-Event-Id를 키로 사용하고, 이미 처리한 것은 무시하세요.
  • succeeded 전달이 실행에 대한 자체 기록이 생기기 전에 도착할 수 있습니다. 오류로 처리하지 말고 그렇게 처리하세요 — 또는 그런 실행은 폴링으로 대체하세요.

웹훅은 보장이 아니라 최적화입니다. 자신이 아직 알지 못하는 실행을 폴링하는 느린 점검을 유지하여, 자신 쪽의 잘못된 배포 하나 때문에 하루치 출력이 사라지지 않게 하세요.

이 페이지의 내용