MDM Gate APIV1 OpenAPI JSON 콘솔 · API 토큰
Integration · Gate API v1

출입 게이트 연동 API

보안구역 출입 게이트(스캐너)가 직원 휴대폰의 출입 QR을 읽어 입실·퇴실을 서버에 알리면, 서버가 해당 기기에 카메라 차단/해제 명령을 보냅니다. Wi-Fi 보안구역과 별개로 동작하며, 게이트 입실 상태에서는 Wi-Fi와 관계없이 카메라가 차단됩니다.

개요

Base URLhttps://mdm.pino-like.com
형식요청·응답 모두 JSON (Content-Type: application/json), UTF-8
인증API 토큰 (Authorization: Bearer mdmg_…), scope gate
오류 형식{"detail": "…"} — 필드 검증 오류(422)는 {"detail": [{type, loc, msg, input}, …]}
스펙OpenAPI 3.0 (openapi.json)

인증

  1. 관리 콘솔 → 연동 → API 토큰에서 admin 계정으로 새 토큰을 만듭니다. 이름(예: 판교 4층 게이트), 선택적으로 허용 게이트 ID와 만료 기간을 지정합니다.
  2. 생성 직후 한 번만 표시되는 토큰(mdmg_ + 40자)을 복사해 게이트 장비의 비밀 저장소에 보관합니다. 서버는 해시만 저장하므로 다시 볼 수 없습니다.
  3. 모든 요청에 헤더를 붙입니다.
Authorization: Bearer mdmg_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# 또는
X-API-Key: mdmg_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

교체 · 폐기

  • 교체: 새 토큰을 먼저 발급해 게이트에 배포하고, 모든 게이트가 새 토큰으로 호출하는 것을 API 로그에서 확인한 뒤 이전 토큰을 폐기합니다. 토큰은 여러 개를 동시에 쓸 수 있습니다.
  • 폐기: 콘솔에서 폐기하면 즉시 401 {"detail": "api token revoked"}가 됩니다. 되돌릴 수 없습니다.
  • 만료: 만료일이 지나면 401 {"detail": "api token expired"}. 만료를 지정하지 않으면 폐기할 때까지 유효합니다.

게이트 ID 제한 (gate_ids)

토큰에 허용 게이트 ID 목록을 지정하면 그 토큰으로는 목록에 있는 gate_id로만 입실·퇴실을 보낼 수 있습니다(그 외 403 {"detail": "gate_id not allowed for this token"}). 비워 두면 모든 게이트에 쓸 수 있습니다. 게이트(또는 게이트 컨트롤러)마다 토큰을 따로 발급하는 것을 권장합니다.

출입 QR (패스 코드)

직원 앱의 출입 코드 화면에 QR과 6자리 코드가 표시됩니다. QR 원문은 다음 형식입니다.

MDMPASS:{device_id}:{code}
# 예
MDMPASS:dev_1a2b3c4d5e6f:305109
  • code는 기기 비밀키로 계산한 6자리 숫자이며 5분마다 바뀝니다(유닉스 시간 300초 단위). 서버는 현재 구간과 직전 구간 코드를 인정하므로, 스캔 시점부터 최소 5분·최대 10분 동안 유효합니다.
  • 게이트는 매번 휴대폰 화면을 실시간으로 스캔해야 합니다. 코드를 저장해 두었다가 나중에 보내거나 재사용할 수 없습니다(만료 시 403).
  • QR 원문을 그대로 pass로 보내면 됩니다. 사람이 코드를 입력하는 키패드형 게이트는 device_id + code로 보낼 수 있으며, 코드 사이의 공백·•·-는 무시됩니다.
  • 서버와 게이트의 시계가 크게 어긋나도 서버 시각 기준으로 검증하므로 게이트 쪽 시각은 영향을 주지 않습니다.
!
호출 로그에는 패스 코드가 MDMPASS:dev_…:******처럼 가려져 저장됩니다. 게이트 장비 로그에도 코드를 남기지 마세요.

연동 흐름

1 · 입실 스캔직원이 입구 게이트에 휴대폰 QR을 댑니다.
2 · POST entry게이트가 /api/gate/v1/entry 호출. 200이면 문을 엽니다.
3 · 카메라 차단서버가 gate_entry 명령을 큐에 넣고 푸시로 기기를 깨웁니다. 앱에 “{게이트 이름} 입실” 표시.
4 · 퇴실출구에서 스캔 → /api/gate/v1/exit → 카메라 해제(gate_exit).
  • 응답의 camera는 명령을 보냈다는 뜻이지 기기가 이미 적용했다는 뜻은 아닙니다. 적용 여부가 필요하면 몇 초 뒤 GET devices의 camera_disabled를 확인합니다.
  • 403(코드 불일치·만료)이면 문을 열지 말고 “앱의 출입 코드를 다시 보여 주세요”를 안내합니다. 404는 등록되지 않은 기기입니다.
  • 네트워크 오류·5xx·429 이면 같은 event_id로 재시도하세요(멱등성). 재시도는 코드가 유효한 동안(최소 5분)만 의미가 있습니다.

POST/api/gate/v1/entry입실

패스를 검증하고, 기기에 gate_entry 명령({gate_id, gate_name, event_id})을 보내고, 기기를 게이트 입실 상태로 표시합니다. 통제 이력에 GATE ENTRY 행이 서버 측에서 기록됩니다.

요청

필드타입설명
passstring스캔한 QR 원문 MDMPASS:{device_id}:{code}. 또는 아래 두 필드
device_id + codestringpass 대신 사용
gate_id 필수string ≤64게이트 식별자 (토큰 gate_ids 제한 대상)
gate_namestring ≤100표시 이름 — 앱·콘솔·통제 이력에 표시. 없으면 gate_id
event_idstring ≤64멱등 키. 게이트가 스캔마다 고유하게 생성 (권장)
tsnumber게이트 시각(unix 초). 기록용이며 서버 시각이 기준입니다
{
  "pass": "MDMPASS:dev_1a2b3c4d5e6f:305109",
  "gate_id": "pangyo-4f-g2",
  "gate_name": "판교 R&D 4층 게이트 2",
  "event_id": "g2-20260929-000123",
  "ts": 1790000000
}

응답 200

{
  "result": "accepted",
  "device_id": "dev_1a2b3c4d5e6f",
  "device_name": "홍길동 Galaxy S24",
  "command_id": 812,
  "camera": "block_pending",      // 이미 차단돼 있었으면 "already_blocked"
  "gate_inside": true,
  "was_inside": false,
  "gate_id": "pangyo-4f-g2",
  "gate_name": "판교 R&D 4층 게이트 2",
  "event_id": "g2-20260929-000123",
  "server_time": 1790000000.412
}

오류: 401 토큰 · 403 invalid or expired pass / 허용되지 않은 gate_id · 404 unknown device · 409 event_id 충돌 · 422 필드 오류 · 429 속도 제한

POST/api/gate/v1/exit퇴실

요청 형식은 entry와 같습니다. 기기에 gate_exit 명령을 보내고 게이트 입실 상태를 해제하며, 통제 이력에 GATE EXIT 행을 남깁니다. 입실 기록이 없어도 200으로 처리하며(멱등) 이때 was_inside: false입니다.

{
  "result": "accepted",
  "device_id": "dev_1a2b3c4d5e6f",
  "device_name": "홍길동 Galaxy S24",
  "command_id": 815,
  "camera": "release_pending",    // 또는 "stays_blocked"
  "gate_inside": false,
  "was_inside": true,
  "gate_id": "pangyo-4f-g2",
  "gate_name": "판교 R&D 4층 게이트 2",
  "event_id": "g2-20260929-000187",
  "server_time": 1790003600.087
}

camera는 서버가 아는 범위의 추정입니다. 기기가 Wi-Fi 보안구역 안에 있다고 보고했거나, 그룹 정책이 카메라를 끄거나, 관리자가 마지막으로 “카메라 끄기”를 보낸 경우 stays_blocked, 그 밖에는 release_pending입니다. 최종 상태는 기기가 판단합니다(게이트 해제 후에도 다른 차단 사유가 있으면 차단 유지).

POST/api/gate/v1/verify확인만

코드만 확인하고 명령·상태 변경·통제 이력 기록은 하지 않습니다(호출 로그에는 남음). 검증만 하는 게이트나 경비 단말에 사용합니다.

// 요청
{ "pass": "MDMPASS:dev_1a2b3c4d5e6f:305109" }
// 응답 200 — 코드가 틀리면 "valid": false (역시 200)
{ "valid": true, "device_id": "dev_1a2b3c4d5e6f", "device_name": "홍길동 Galaxy S24" }

오류: 401 · 404 unknown device · 422 · 429

GET/api/gate/v1/devices/{device_id}

{
  "device_id": "dev_1a2b3c4d5e6f",
  "device_name": "홍길동 Galaxy S24",
  "online": true,                 // 최근 30초 안에 체크인
  "last_checkin": 1790000003.2,
  "camera_disabled": true,        // 기기가 마지막으로 보고한 실제 상태
  "gate_inside": true,
  "gate_id": "pangyo-4f-g2",
  "gate_name": "판교 R&D 4층 게이트 2",
  "zone": "out",                  // Wi-Fi 보안구역: off | in | out | unknown | null
  "compliant": true,              // 콘솔 준수 상태와 같은 규칙
  "agent_version": "1.4.0"
}

오류: 401 · 404 unknown device · 429

GET/api/gate/v1/health

연결과 토큰을 확인합니다(토큰 필요). 게이트 기동 시·주기적 헬스체크에 사용하세요.

{ "ok": true, "server_time": 1790000000.412, "api_version": "v1", "token": "판교 4층 게이트" }

오류 코드

상태detail의미 · 게이트 동작
401api token required · invalid api token · api token revoked · api token expired토큰 문제. 재시도하지 말고 관리자에게 알림
403invalid or expired pass코드 불일치·만료 — 문 열지 않음, 다시 스캔 안내
403gate_id not allowed for this token · api token lacks scope 'gate'토큰 설정 문제
404unknown device등록되지 않았거나 삭제된 기기
405Method Not AllowedHTTP 메서드 오류
409event_id already used for …같은 event_id를 다른 기기/동작에 재사용
413request body too large (max 64 KB)본문 크기 초과
422검증 오류 목록필수 필드 누락(gate_id, pass 또는 device_id+code), 길이 초과, 잘못된 QR 형식, 잘못된 JSON
429rate limit exceededRetry-After(초) 후 같은 event_id로 재시도
5xx—서버 오류. 잠시 후 같은 event_id로 재시도
// 422 예시
{ "detail": [ { "type": "missing", "loc": ["body", "gate_id"], "msg": "Field required", "input": { "pass": "MDMPASS:dev_1a2b3c4d5e6f:******" } } ] }

멱등성 (event_id)

  • entry/exit에 event_id를 넣으면, 같은 토큰으로 같은 event_id를 다시 보냈을 때 명령을 다시 보내지 않고 최초 응답에 "duplicate": true를 붙여 돌려줍니다(패스 코드가 그사이 만료됐어도 동일).
  • 같은 event_id를 다른 기기나 다른 동작(entry↔exit)에 쓰면 409입니다. 스캔마다 새 값을 만드세요(예: {gate_id}-{날짜}-{일련번호} 또는 UUID).
  • event_id는 토큰별로 관리되며, 호출 로그 보존 기간(기본 180일) 동안 기억됩니다.
  • event_id 없이 보내면 매 호출이 새 이벤트로 처리됩니다.

속도 제한

  • 토큰마다 초당 20회, 순간 40회까지(토큰 버킷). 초과 시 429 + Retry-After 헤더.
  • 인증에 실패한 호출은 클라이언트 IP마다 초당 5회(순간 20회)로 제한됩니다.
  • 요청 본문은 최대 64 KB.

반영 지연

  • API 응답은 보통 수십 ms 안에 옵니다. 명령은 응답 전에 저장되므로 200을 받으면 기기에 반드시 전달됩니다.
  • 기기 반영: 푸시(FCM)가 설정돼 있으면 수 초 이내, 푸시가 없거나 실패하면 에이전트 폴링 주기인 최대 약 5초 안에 카메라가 차단/해제됩니다. 기기가 오프라인이면 다시 연결될 때 적용됩니다.
  • 입실 직후 촬영을 확실히 막아야 하는 구역은 게이트 통과 후 짧은 전실(버퍼 공간)을 두거나, GET devices로 camera_disabled: true를 확인한 뒤 내부 문을 여는 방식을 권장합니다.

호출 로그

/api/gate/ 아래의 모든 호출(실패 포함)이 콘솔 연동 → API 로그에 기록됩니다: 시각, 토큰, 메서드·경로, 상태, 처리 시간, 기기, 게이트, 결과, 클라이언트 IP, 요청·응답 본문(각 2000자, 패스 코드 마스킹). 보존 기간은 기본 180일입니다.

curl 예시

# 토큰 확인
export MDM_GATE_TOKEN=mdmg_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
curl -s https://mdm.pino-like.com/api/gate/v1/health -H "Authorization: Bearer $MDM_GATE_TOKEN"

# 입실
curl -s -X POST https://mdm.pino-like.com/api/gate/v1/entry \
  -H "Authorization: Bearer $MDM_GATE_TOKEN" -H "Content-Type: application/json" \
  -d '{"pass":"MDMPASS:dev_1a2b3c4d5e6f:305109","gate_id":"pangyo-4f-g2","gate_name":"판교 R&D 4층 게이트 2","event_id":"g2-20260929-000123"}'

# 퇴실
curl -s -X POST https://mdm.pino-like.com/api/gate/v1/exit \
  -H "Authorization: Bearer $MDM_GATE_TOKEN" -H "Content-Type: application/json" \
  -d '{"pass":"MDMPASS:dev_1a2b3c4d5e6f:512877","gate_id":"pangyo-4f-g2","event_id":"g2-20260929-000187"}'

# 코드만 확인
curl -s -X POST https://mdm.pino-like.com/api/gate/v1/verify \
  -H "X-API-Key: $MDM_GATE_TOKEN" -H "Content-Type: application/json" \
  -d '{"device_id":"dev_1a2b3c4d5e6f","code":"305 109"}'

# 기기 상태
curl -s https://mdm.pino-like.com/api/gate/v1/devices/dev_1a2b3c4d5e6f -H "Authorization: Bearer $MDM_GATE_TOKEN"

변경 이력

버전날짜내용
v12026-09-29최초 공개: entry / exit / verify / devices / health, API 토큰(scope gate, gate_ids 제한, 만료·폐기), event_id 멱등성, 토큰별 속도 제한, 호출 로그.

MDM Gate API v1 · 이 문서는 서버가 직접 제공합니다 (https://mdm.pino-like.com/api/gate/docs)