웹훅

AgentSend 계정에서 이벤트가 발생할 때 실시간으로 알림을 받으세요. 새 이메일 수신, 전송 확인, 반송 감지 등.

개요

새 메시지를 확인하기 위해 API를 폴링하는 대신, 웹훅을 사용하면 AgentSend가 이벤트 발생 즉시 서버로 이벤트 데이터를 푸시할 수 있습니다. HTTPS 엔드포인트를 등록하면 AgentSend는 구독 이벤트가 발생할 때마다 JSON 페이로드와 함께 POST 요청을 보냅니다.

웹훅은 반응형 에이전트를 구축하는 권장 방법입니다. 답장이 에이전트의 수신함에 도착하면 애플리케이션은 몇 초 내에 전체 메시지 페이로드를 받아 즉시 조치할 수 있습니다.

웹훅 엔드포인트는 HTTPS를 통해 공개적으로 접근 가능해야 합니다. localhost URL은 허용되지 않습니다. 로컬에서 개발할 때는 ngrok이나 터널 서비스를 사용하세요.

웹훅 만들기

/webhooksPOST 요청을 보내 새 웹훅을 등록합니다. url 필드는 필수이며, 다른 모든 필드는 선택 사항입니다.

POST /webhooks
파라미터 타입 설명
url 필수 string AgentSend가 이벤트를 POST할 HTTPS URL.
description string 대시보드에서 웹훅을 식별하는 사람이 읽을 수 있는 레이블.
events string[] 구독할 이벤트 타입 목록. 생략하면 모든 이벤트를 받습니다.
javascript
const res = await fetch("https://api.agentsend.io/webhooks", {
  method: "POST",
  headers: {
    "x-api-key": process.env.AGENTSEND_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://myapp.example.com/hooks/agentsend",
    description: "Production inbox events",
    events: ["message.received", "message.bounced"],
  }),
});

const webhook = await res.json();
console.log(webhook.id);     // wh_01j9...
console.log(webhook.secret); // whsec_... store this securely!

secret은 생성 응답에서 단 한 번만 반환됩니다. 안전한 환경 변수에 즉시 저장하세요. 다시 가져올 수는 없지만 PUT /webhooks/{id}로 순환시킬 수 있습니다.

이벤트 타입

events 배열에 식별자를 전달하여 특정 이벤트를 구독합니다. 배열을 생략하면 AgentSend가 모든 이벤트 타입을 엔드포인트에 전달합니다.

이벤트 설명
domain.verified 커스텀 도메인이 DNS 검증을 통과하여 사용 준비가 되었습니다.
message.received 수신 이메일이 에이전트의 수신함 중 하나에 도착했습니다.
message.sent 발신 메시지가 수락되어 전송 대기 중입니다.
message.delivered 수신자의 메일 서버가 성공적인 전송을 확인했습니다.
message.bounced 메시지를 전송할 수 없습니다 (하드 또는 소프트 바운스).
message.complained 수신자가 메일 클라이언트에서 메시지를 스팸으로 표시했습니다.

웹훅 페이로드

모든 웹훅 전송은 Content-Type: application/json 본문을 포함하는 POST 요청입니다. 페이로드는 이벤트 타입과 관계없이 일관된 형식을 갖습니다.

json — message.received example
{
  "id": "evt_01j9xkq7z8abc",
  "type": "message.received",
  "createdAt": "2026-04-16T10:23:45.000Z",
  "webhookId": "wh_01j9abc123",
  "data": {
    "id": "msg_01j9xkp4n5def",
    "inboxId": "inbox_01j8mq3r2t",
    "threadId": "thr_01j9xkp4m1ghi",
    "fromAddress": "alice@example.com",
    "fromName": "Alice Chen",
    "toAddresses": ["a1b2c3@agentsend.io"],
    "subject": "Re: Your proposal",
    "bodyText": "Looks great, let's move forward.",
    "bodyHtml": "<p>Looks great, let's move forward.</p>",
    "hasAttachments": false,
    "receivedAt": "2026-04-16T10:23:44.812Z"
  }
}

서명 검증

모든 웹훅 요청에는 X-AgentSend-Signature 헤더가 포함됩니다. 이는 웹훅의 secret으로 서명된 원시 요청 본문의 HMAC-SHA256 해시입니다. 위조된 요청으로부터 보호하기 위해 전송을 처리하기 전에 항상 이 서명을 검증하세요.

javascript — Express / Node.js
import crypto from "node:crypto";

app.post("/hooks/agentsend", express.raw({ type: "application/json" }), (req, res) => {
  const sig       = req.headers["x-agentsend-signature"];
  const secret    = process.env.AGENTSEND_WEBHOOK_SECRET;
  const expected  = crypto
    .createHmac("sha256", secret)
    .update(req.body) // raw Buffer — do NOT parse JSON first
    .digest("hex");

  if (!crypto.timingSafeEqual(
    Buffer.from(sig),
    Buffer.from(expected)
  )) {
    return res.status(401).send("Invalid signature");
  }

  const event = JSON.parse(req.body);
  // handle event.type …
  res.sendStatus(200);
});
python — Flask
import hmac, hashlib, os
from flask import Flask, request, abort

app = Flask(__name__)

@app.route("/hooks/agentsend", methods=["POST"])
def webhook():
    sig      = request.headers.get("X-AgentSend-Signature", "")
    secret   = os.environ["AGENTSEND_WEBHOOK_SECRET"].encode()
    expected = hmac.new(secret, request.data, hashlib.sha256).hexdigest()

    if not hmac.compare_digest(sig, expected):
        abort(401)

    event = request.get_json()
    # handle event["type"] …
    return "", 200
💡

타이밍 공격을 방지하려면 서명을 확인할 때 항상 상수 시간 비교(예: crypto.timingSafeEqual 또는 hmac.compare_digest)를 사용하세요.

재시도 정책

엔드포인트가 10초 이내에 2xx HTTP 상태 코드로 응답하면 AgentSend는 전송이 성공한 것으로 간주합니다. 요청이 타임아웃되거나 2xx가 아닌 응답이 반환되면 지수 백오프로 전송이 재시도됩니다:

시도 이전 시도 이후 지연
1차 재시도 5초
2차 재시도 30초
3차 재시도 5분
4차 재시도 30분
5차 재시도 2시간

5회 재시도 실패(총 6회 시도) 후 전송은 실패로 표시되며 더 이상 시도하지 않습니다. 실패한 전송은 전송 로그에서 확인하고 대시보드에서 수동으로 재생할 수 있습니다.

가능한 한 빨리 200 OK로 응답하세요. 처리 로직에 시간이 걸리면 페이로드를 즉시 수락하고 큐나 백그라운드 작업으로 비동기 처리하세요.

웹훅 관리

웹훅 API를 사용하면 등록된 엔드포인트를 나열, 업데이트, 삭제할 수 있습니다.

웹훅 목록

계정에 등록된 모든 웹훅을 반환합니다.

bash
# GET /webhooks
curl https://api.agentsend.io/webhooks \
  -H "x-api-key: $AGENTSEND_API_KEY"

웹훅 업데이트

URL, 설명 또는 구독 이벤트 타입을 변경합니다. "rotateSecret": true를 전달해 서명 시크릿을 순환할 수도 있습니다. 응답에 새 secret이 포함됩니다.

bash
# PUT /webhooks/{id}
curl -X PUT https://api.agentsend.io/webhooks/wh_01j9abc123 \
  -H "x-api-key: $AGENTSEND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"events": ["message.received", "message.delivered", "message.bounced"]}'

웹훅 삭제

웹훅을 영구적으로 제거합니다. 삭제가 적용되기 전에도 진행 중인 전송은 시도됩니다.

bash
# DELETE /webhooks/{id}
curl -X DELETE https://api.agentsend.io/webhooks/wh_01j9abc123 \
  -H "x-api-key: $AGENTSEND_API_KEY"

활동 모니터링

특정 웹훅의 최근 이벤트 볼륨 및 오류율 요약을 가져옵니다.

bash
# GET /webhooks/activity
curl "https://api.agentsend.io/webhooks/activity?webhookId=wh_01j9abc123" \
  -H "x-api-key: $AGENTSEND_API_KEY"

전송 로그

모든 전송 시도가 기록됩니다. logs 엔드포인트를 쿼리해 HTTP 응답 코드, 응답 본문, 타이밍을 포함한 웹훅의 전체 기록을 확인하세요.

GET /webhooks/logs
쿼리 파라미터 타입 설명
webhookId string 특정 웹훅으로 로그를 필터링합니다.
status string success, failed, 또는 pending.
limit number 반환할 레코드 수 (기본값 50, 최대 200).
before string 페이지네이션 커서; 마지막으로 본 레코드의 id를 전달합니다.
bash
# Fetch failed deliveries for a webhook
curl "https://api.agentsend.io/webhooks/logs?webhookId=wh_01j9abc123&status=failed" \
  -H "x-api-key: $AGENTSEND_API_KEY"

각 로그 항목에는 다음이 포함됩니다: