Skip to content

공개 API · 웹훅 ​

사내 대시보드·BI·티켓 시스템에서 ISMS Doctor 의 준비 현황을 가져오거나(API), 이벤트를 받아 자동화(웹훅)할 수 있습니다.

API 키 ​

설정 › 조직 › 공개 API 키 에서 조직 관리자가 발급합니다.

  • 키 원문(isdk_…)은 발급 직후 한 번만 표시됩니다. 서버에는 해시만 저장하므로 다시 볼 수 없습니다.
  • 유효 기간(30·90·180·365일)이 반드시 있고, 조직당 활성 키는 10개까지입니다.
  • 권한 범위는 읽기 전용입니다 — 키로는 어떤 데이터도 바꿀 수 없습니다.
범위허용하는 엔드포인트
summary:readGET /api/v1/summary
controls:readGET /api/v1/controls
action-items:readGET /api/v1/action-items

GET /api/v1/org 는 유효한 키면 범위와 관계없이 호출할 수 있습니다.

호출 방법 ​

bash
curl -sS https://<도메인>/api/v1/summary \
  -H "Authorization: Bearer $ISMS_DOCTOR_API_KEY"

응답은 앱과 같은 형식 { "data": …, "error": null, "message": "OK" } 입니다.

엔드포인트설명쿼리
GET /api/v1/org조직 이름·인증 유형·카탈로그·최근/다음 스캔 시각—
GET /api/v1/summary통제 상태별 개수(대시보드와 같은 집계)—
GET /api/v1/controls통제별 상태·증적 수·세부점검 상태status(READY · EVIDENCE_NEEDED · REMEDIATING · FAIL · UNKNOWN · NOT_APPLICABLE), area(예: 2 또는 2.5)
GET /api/v1/action-items할 일 목록 (최신순)status(OPEN · IN_PROGRESS · DONE), controlCode, limit(1~200, 기본 50), cursor

할 일 목록은 커서 방식입니다. 응답의 nextCursor 를 다음 요청의 cursor 로 넘기고, null 이면 마지막 페이지입니다. 알 수 없는 커서(오타 · 다른 조직의 값 · 인증 유형 전환 전에 받은 값)는 빈 페이지 대신 400 INVALID_CURSOR 를 돌려주니, 첫 페이지부터 다시 조회하세요.

한도와 오류 ​

  • 키마다 시간당 600회, IP 마다 분당 120회. 넘으면 429.
  • 401 — 키 형식이 틀렸거나, 회수·만료된 키이거나, 키를 발급한 관리자가 조직을 떠났거나 관리자 권한을 잃었습니다 (사유는 구분하지 않습니다). 마지막 경우 설정 화면에 "발급자 권한 없음" 으로 표시되며, 현재 관리자가 새로 발급해야 합니다.
  • 키 호출은 조직 감사 로그에 api-key.access 로 남습니다 (성공은 키·경로당 1분에 1건, 실패는 매번).
  • 403 INSUFFICIENT_SCOPE — 키에 해당 범위가 없습니다.
  • 409 DEMO_MODE — 조직이 데모 데이터 모드입니다. 가상 데이터가 외부로 나가지 않도록 실데이터로 전환한 뒤 호출할 수 있습니다.

웹훅 (이벤트 수신) ​

설정 › 알림 › 알림 채널 에서 "범용 웹훅(Generic Webhook)" 채널을 추가하면, 알림으로 설정한 이벤트(스캔 완료 · 새 부적합 · 증적 만료 임박 · 할 일 기한 · 인증 마일스톤 등)가 JSON 으로 전송됩니다.

json
{
  "event": "new_fail",
  "orgId": "…",
  "title": "…",
  "text": "…",
  "url": "https://<도메인>/controls/2.5.1",
  "occurredAt": "2026-09-27T00:00:00.000Z"
}

헤더 X-ISMSDoctor-Event 에 이벤트 이름이, X-ISMSDoctor-Signature 에 t=<발송 시각 unix 초>,v1=<서명 hex> 가 담깁니다. v1 은 HMAC-SHA256(서명 시크릿, "<t>.<원문 본문>") — 발송 시각 t 와 본문을 . 으로 이어 붙인 문자열의 HMAC 입니다. 서명 시크릿은 채널을 만들 때(또는 재발급할 때) 한 번만 표시됩니다.

수신 측은 다음을 모두 확인하세요.

  1. 헤더에서 t 와 v1 을 꺼냅니다.
  2. t 가 수신 시각과 5분 넘게 차이 나면 거절합니다 — 가로챈 요청을 나중에 다시 보내는 재전송(replay) 을 막습니다.
  3. JSON 을 파싱·재직렬화하지 말고 원문 본문 그대로 "<t>.<원문 본문>" 의 HMAC 을 계산해 v1 과 상수 시간 비교합니다. t 가 서명에 포함되므로 t 만 바꿔 재전송하면 검증에 실패합니다.
js
import crypto from 'node:crypto';

const TOLERANCE_SECONDS = 5 * 60;

function verify(rawBody, signatureHeader, secret, now = Date.now()) {
  const parts = Object.fromEntries(
    (signatureHeader ?? '').split(',').map((kv) => {
      const i = kv.indexOf('=');
      return [kv.slice(0, i).trim(), kv.slice(i + 1).trim()];
    }),
  );
  const t = Number(parts.t);
  if (!Number.isInteger(t) || Math.abs(now / 1000 - t) > TOLERANCE_SECONDS) return false; // 재전송·시계 오류
  const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest();
  const received = Buffer.from(parts.v1 ?? '', 'hex');
  return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}

수신 서버의 시계가 크게 틀리면 정상 요청도 거절되니 NTP 로 맞춰 두세요.

웹훅 대상 주소는 공인 IP 여야 합니다 (사설·루프백·예약·문서용 등 공인이 아닌 대역은 발송 시점에 차단됩니다).