웹훅 받기
외부 서비스가 보내는 웹훅을 접수창구로 받아, 검증을 거쳐 앱까지 안전하게 전달해요.
결제 완료나 GitHub push처럼 외부 서비스가 보내 주는 소식(웹훅)을 앱이 받을 수 있어요.
외부에는 AxHub의 접수창구 주소만 공개되고, 검증을 통과한 요청만 앱에 전달돼요.
어떻게 동작하나
외부 서비스 → 접수창구 (hooks.{회사}… /r/{창구 id}) → 발신자 검증 → 앱의 수신 경로- 접수창구 주소는 앱 주소와 분리돼 있어요. 앱을 다시 배포하거나 내부 경로를 바꿔도 외부에 알려 준 주소는 그대로예요.
- 검증을 통과한 요청만 앱에 도달하고, 원본 요청의 메서드 · 바디 · 쿼리는 그대로 보존돼요.
준비물
- 연결된 앱 — 웹훅은 앱 단위로 받아요. 아직 없다면 앱 만들고 배포하기부터 하세요.
- CLI 로그인 — 창구 관리는
axhub relay명령으로 해요.
접수창구 만들기
axhub relay create --app <앱> --name <창구-이름> --verify-mode key출력에 받는 주소와 열쇠(키), 수신 계약이 나와요. 이 출력이 기준이에요.
키는 이때 한 번만 보여요. 잃어버리면 axhub relay rotate-key로 새로 발급하세요.
발신자 검증(--verify-mode)은 외부 서비스에 맞춰 세 가지 중 골라요.
| verify-mode | 발신자가 보내는 것 |
|---|---|
key (기본) | X-AxHub-Key 헤더에 공유 키 |
hmac | 원문 바디의 HMAC-SHA256을 X-Signature-256: sha256=<hex> 헤더로 |
none | 검증 없음. 신뢰할 수 있는 발신자에게만 쓰세요 |
앱에서 받기
받는 쪽은 SDK가 아니라 프레임워크의 평범한 라우트 핸들러예요. Next.js라면 이렇게 생겼어요.
import { createHmac, timingSafeEqual } from 'crypto';
export async function POST(req: Request): Promise<Response> {
const secret = process.env.AXHUB_RELAY_SIGNING_SECRET ?? '';
const rawBody = await req.text();
const provided = req.headers.get('x-axhub-signature') ?? '';
const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex');
const ok = secret !== '' && provided.length === expected.length &&
timingSafeEqual(Buffer.from(provided), Buffer.from(expected));
if (!ok) {
return new Response('unauthorized', { status: 401 });
}
const deliveryId = req.headers.get('x-axhub-delivery') ?? '';
// 재시도로 같은 전달이 다시 올 수 있어요 — deliveryId 기준으로 한 번만 처리하세요.
console.log('inbound webhook', deliveryId, rawBody.length);
// 처리가 끝나면 2xx를 돌려주세요. 2xx가 아니면 다시 전달돼요.
return new Response('ok', { status: 200 });
}- 전달마다
X-AxHub-Signature: sha256=<hex>서명이 붙어요. 배포 때 자동 주입되는AXHUB_RELAY_SIGNING_SECRET환경변수로 원문 바디의 HMAC-SHA256을 재계산해 비교하면, 접수창구를 거쳐 온 요청만 받게 돼요. 따로 설정할 건 없어요. - 전달마다
X-AxHub-Delivery헤더(전달 고유 id)도 붙어요. 재시도로 같은 전달이 두 번 올 수 있으니, 이 값으로 한 번만 처리하게 만드세요. - 열쇠(키)는 발신자와 접수창구 사이에서만 쓰여요. 접수창구가 검사를 마치면
X-AxHub-Key같은 자격증명 헤더는 지우고 전달하니, 앱에서 키를 다시 검사하지 마세요.
전달과 재시도
| 전달 모드 | 동작 |
|---|---|
durable (기본) | 앱이 2xx를 줄 때까지 간격을 늘려 가며 다시 보내요 (1분 → 5분 → 30분 → 2시간 → 6시간, 그 뒤 실패 처리) |
sync | 앱의 응답을 발신자에게 그대로 돌려줘요 |
요청 본문은 기본 1MiB까지예요(넘으면 413). 접수는 분당 기본 300건까지고, 넘으면 429가 나요.
운영하기
| 하고 싶은 일 | 명령 |
|---|---|
| 창구 목록 보기 | axhub relay list --app <앱> |
| 전달 이력 보기 (상태 · 시도 · 응답 코드) | axhub relay deliveries <창구 id> --app <앱> |
| 실패한 전달 다시 보내기 | axhub relay replay <창구 id> <전달 id> --app <앱> --execute |
| 키 교체하기 | axhub relay rotate-key <창구 id> --app <앱> --execute |
| 창구 폐쇄하기 (되돌릴 수 없음) | axhub relay delete <창구 id> --app <앱> --execute |
이렇게 보이면 성공
외부 서비스의 웹훅 설정에 접수창구 주소와 키를 넣고 시험 이벤트를 보내 보세요.
axhub relay deliveries에 전달이 기록되고 응답 코드가 2xx면 성공이에요.