웹훅
실행이 끝날 때까지 폴링하지 않고 완료 알림을 받습니다.
엔드포인트를 한 번 등록한 다음, 실행을 시작할 때 그 엔드포인트의 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전달이 실행에 대한 자체 기록이 생기기 전에 도착할 수 있습니다. 오류로 처리하지 말고 그렇게 처리하세요 — 또는 그런 실행은 폴링으로 대체하세요.
웹훅은 보장이 아니라 최적화입니다. 자신이 아직 알지 못하는 실행을 폴링하는 느린 점검을 유지하여, 자신 쪽의 잘못된 배포 하나 때문에 하루치 출력이 사라지지 않게 하세요.