웹훅

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

엔드포인트를 한 번 등록한 다음, 그 엔드포인트의 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 자격 증명이 포함되지 않아야 하며, 조직은 최대 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 객체는 동일한 형태입니다 워크플로우 실행 읽기 를 반환하므로, 자산 이 포함되므로 — 성공한 전달은 후속 호출이 필요 없습니다. 이는 이벤트가 발생했을 당시의 실행 상태이며, 전달 재시도 기간 동안에는 자산 링크가 약 하루 동안 유효합니다.

모든 전달 검증하기

다음의 HMAC-SHA256을 계산하세요 {timestamp}.{raw body} 를 서명 비밀키로 계산한 뒤 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;

  // 재전송된 전달은 거부합니다.
  return Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
}

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

재시도 및 순서

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

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

이 페이지의 내용