출입 게이트 연동 API
보안구역 출입 게이트(스캐너)가 직원 휴대폰의 출입 QR을 읽어 입실·퇴실을 서버에 알리면, 서버가 해당 기기에 카메라 차단/해제 명령을 보냅니다. Wi-Fi 보안구역과 별개로 동작하며, 게이트 입실 상태에서는 Wi-Fi와 관계없이 카메라가 차단됩니다.
개요
| Base URL | https://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) |
인증
- 관리 콘솔 → 연동 → API 토큰에서 admin 계정으로 새 토큰을 만듭니다. 이름(예: 판교 4층 게이트), 선택적으로 허용 게이트 ID와 만료 기간을 지정합니다.
- 생성 직후 한 번만 표시되는 토큰(
mdmg_+ 40자)을 복사해 게이트 장비의 비밀 저장소에 보관합니다. 서버는 해시만 저장하므로 다시 볼 수 없습니다. - 모든 요청에 헤더를 붙입니다.
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_…:******처럼 가려져 저장됩니다. 게이트 장비 로그에도 코드를 남기지 마세요.연동 흐름
/api/gate/v1/entry 호출. 200이면 문을 엽니다.gate_entry 명령을 큐에 넣고 푸시로 기기를 깨웁니다. 앱에 “{게이트 이름} 입실” 표시./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 행이 서버 측에서 기록됩니다.
요청
| 필드 | 타입 | 설명 |
|---|---|---|
pass | string | 스캔한 QR 원문 MDMPASS:{device_id}:{code}. 또는 아래 두 필드 |
device_id + code | string | pass 대신 사용 |
gate_id 필수 | string ≤64 | 게이트 식별자 (토큰 gate_ids 제한 대상) |
gate_name | string ≤100 | 표시 이름 — 앱·콘솔·통제 이력에 표시. 없으면 gate_id |
event_id | string ≤64 | 멱등 키. 게이트가 스캔마다 고유하게 생성 (권장) |
ts | number | 게이트 시각(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 | 의미 · 게이트 동작 |
|---|---|---|
| 401 | api token required · invalid api token · api token revoked · api token expired | 토큰 문제. 재시도하지 말고 관리자에게 알림 |
| 403 | invalid or expired pass | 코드 불일치·만료 — 문 열지 않음, 다시 스캔 안내 |
| 403 | gate_id not allowed for this token · api token lacks scope 'gate' | 토큰 설정 문제 |
| 404 | unknown device | 등록되지 않았거나 삭제된 기기 |
| 405 | Method Not Allowed | HTTP 메서드 오류 |
| 409 | event_id already used for … | 같은 event_id를 다른 기기/동작에 재사용 |
| 413 | request body too large (max 64 KB) | 본문 크기 초과 |
| 422 | 검증 오류 목록 | 필수 필드 누락(gate_id, pass 또는 device_id+code), 길이 초과, 잘못된 QR 형식, 잘못된 JSON |
| 429 | rate limit exceeded | Retry-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"
변경 이력
| 버전 | 날짜 | 내용 |
|---|---|---|
| v1 | 2026-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)