"매 reverse-API: 매 server 가 client 의 HTTP endpoint 로 event 를 push 하는 매 async integration pattern". 2007 GitHub 가 popularize, 2026 Stripe/Shopify/Slack 의 표준. 매 polling 대비 latency ↓ 99%, 매 challenge: delivery guarantee + signature verification + replay protection.
매 핵심
매 Webhook anatomy
POST https://your-app/hooks/stripe with JSON body + headers (Stripe-Signature, Webhook-Id, Webhook-Timestamp).
매 receiver 의 2xx 응답 < 매 5s — 매 그렇지 않으면 sender 가 retry.
매 Delivery guarantees
At-least-once: 매 표준. 매 idempotency key 필수.
매 retry: exponential backoff (1m, 5m, 30m, 2h, ...) up to 매 24-72h.
import{Hono}from'hono';import{createHmac,timingSafeEqual}from'crypto';constapp=newHono();app.post('/hooks/stripe',async(c)=>{constsig=c.req.header('stripe-signature')!;constbody=awaitc.req.text();const[t,v1]=sig.split(',').map(p=>p.split('=')[1]);if(Math.abs(Date.now()/1000-+t)>300)returnc.text('stale',400);constexpected=createHmac('sha256',process.env.STRIPE_SECRET!).update(`${t}.${body}`).digest('hex');if(!timingSafeEqual(Buffer.from(expected),Buffer.from(v1)))returnc.text('bad sig',401);constevent=JSON.parse(body);awaitenqueue(event);// 매 fast 200, async process
returnc.text('ok',200);});
app.post('/hooks/:provider',asyncc=>{constbody=awaitc.req.text();awaitsqs.send(newSendMessageCommand({QueueUrl: process.env.HOOKS_QUEUE,MessageBody: JSON.stringify({provider: c.req.param('provider'),body,hdr: c.req.header()}),}));returnc.text('ok',200);// 매 fast ack
});