superplace 출입 API

매장 출입 제어를 위한 superplace 공개 API입니다.

빠른 시작

# 1) 키를 토큰으로 교환
curl -X POST https://api.superplace.so/core/v1/auth/apikey/token \
  -H 'Content-Type: application/json' -d '{"key":"spk_live_…"}'

# 2) 출입 허가 등록 — 이 순간부터 전화·QR로 입장됩니다
curl -X POST https://api.superplace.so/space/v1/partner/entry-permits \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"externalRef":"member-1001","phone":"01012345678","name":"김회원",
       "startsAt":"2026-09-03T00:00:00Z","endsAt":"2026-09-05T00:00:00Z"}'

두 호출이면 회원이 입장합니다.

기본

인증

POST/core/v1/auth/apikey/token — 키를 15분 토큰으로 교환하고, 모든 요청에 Authorization: Bearer {accessToken}을 전달합니다. 교환은 IP당 분당 30회.

→ {"success":true,"data":{"accessToken":"…","expiresIn":900,"placeId":"…","scopes":["space:partner","device:door"]}}

placeId가 곧 매장 ID입니다 — 활동 기록 조회 등 경로에 매장 ID가 필요한 API에 이 값을 그대로 씁니다. 키가 매장에 묶여 있어 따로 물어볼 필요가 없습니다.

키에는 쓸 수 있는 범위가 담겨 있습니다. 발급 시 요청하신 범위대로 만들어 드리며, 범위 밖 호출은 403으로 거절됩니다.

범위할 수 있는 것
손님과 출입출입 허가 등록·조회·해지 · 출입 기록 · 출입 설정 · 회원권 · 예약
기기 제어문 목록 · 문 열기·잠그기·열어두기 (물리 개방)
기기 제어가 담긴 키는 물리적인 문을 엽니다. 유출됐다면 즉시 알려주세요 — 폐기 후 15분 안에 모든 호출이 거절됩니다.

테스트 매장

spk_test_ 키는 테스트 매장 전용입니다. 모의 응답이 아니라 실매장과 같은 서버·같은 로직으로 동작하며(허가·상태 전이·이력 전부 실기록), 실제 문과 연결되지 않습니다. 키가 매장에 묶여 있어 테스트 호출이 실매장 문을 여는 일은 없습니다.

응답과 오류

성공: {"success":true,"data":…}     목록: {"success":true,"data":[…],"total":n}
실패: {"error":"코드","message":"설명","statusCode":숫자}

401 토큰 만료(재교환) · 403 스코프 없음 · 404 대상 없음 · 409 규칙 위반(message에 이유) · 429 요청 한도 · 502/503 매장 기기 오프라인(재시도)

입장 수단

허가를 등록하면 두 방법이 모두 동작합니다.

수단동작
전화등록된 번호로 매장 출입 전화번호(050)에 전화 → 발신번호 확인 → 개문. 번호는 출입 설정의 entryPhone. 안내물에는 tel:0507… QR로 인쇄하면 찍는 즉시 전화가 걸립니다.
입장 링크 (QR)허가 응답의 url을 앱·문자·인쇄물에 QR로. 손님이 열면 문 버튼이 나타납니다. 링크가 곧 자격이므로 공개 채널에 올리지 마세요 — 해지하면 즉시 무효.

출입 허가

POST/space/v1/partner/entry-permits

{"externalRef":"member-1001","phone":"01012345678","name":"김회원",
 "startsAt":"2026-09-03T00:00:00Z","endsAt":"2026-09-05T00:00:00Z"}

→ {"success":true,"data":{"permitId":"…","entryToken":"…",
    "url":"https://go.superplace.so/entry?t=…"}}

같은 externalRef 재호출은 기간 변경 + 해지 해제됩니다(멱등 — 같은 요청을 몇 번 보내도 결과가 한 번 보낸 것과 같습니다). 새 externalRef에서 doorIds를 생략하거나 null로 보내면 현재 매장의 출입문 범위를 사용합니다. 같은 externalRef를 재발급할 때 생략하거나 null로 보내면 저장된 문 범위를 유지합니다. 비어 있지 않은 배열을 보낼 때만 범위를 바꾸며, 빈 배열은 400으로 거절됩니다. 모든 문으로 넓히려면 현재 문 ID 전체를 명시해야 합니다. 시간창은 한 건당 최대 720시간이며, 장기 자격은 재등록 또는 회원권을 사용합니다.

POST/space/v1/partner/entry-permits/revoke

{"externalRef":"member-1001","reason":"환불"}   또는   {"permitId":"…"}     # reason 선택(≤200자)

GET/space/v1/partner/entry-permits

쿼리: externalRef · limit(≤500) · offset. 파트너가 등록한 허가만 반환합니다.

→ data: [{"permitId":"…","externalRef":"member-1001","name":"김회원","phoneTail":"5678",
   "state":"active",              // active | pending | expired | revoked
   "startsAt":"…","endsAt":"…","useCount":3,"firstUsedAt":"…","url":"…"}]

GET/space/v1/partner/entry-permits/{permitId}

기기 기기 제어 범위

매장 기기는 한 경로로 다룹니다. 목록으로 기기와 연결 상태를 보고, 명령으로 조작합니다. 기기 제어 범위의 키로는 문만 보입니다.

GET/device/v1/devices · GET/device/v1/devices/{id}

행마다 id · name · health.state(online · offline · unknown — unknown은 아직 한 번도 연결된 적 없음) · capabilities(받는 명령 묶음)가 옵니다. 단건은 문의 지금 상태(standing)를 더합니다.

POST/device/v1/devices/{id}/commands

curl -X POST https://api.superplace.so/device/v1/devices/$DOOR/commands \
  -H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: $(uuidgen)" \
  -d '{"capability":"door","command":"hold","args":{"minutes":60}}'   # minutes 0 = 잠글 때까지

문 명령은 door.open(잠깐 열기) · door.hold(열어두기) · door.close(잠그기)이고 args.reason은 기록용입니다. 기기가 실제로 실행했다고 답한 뒤에 응답합니다 — 성공은 200과 outcome: reported, 실패는 details.reason으로 offline(연결 끊김, 보내지 않음, 409) · refused(기기가 거절, 502) · noResponse(기기가 답하지 않음 — 실행됐는지 모름, 504)입니다.

Idempotency-Key 헤더 필수 — 요청마다 고유한 문자열(UUID 권장). 타임아웃 뒤 같은 값으로 다시 보내면 문이 두 번 열리지 않고 처음 결과를 돌려받습니다. 모든 호출이 출입 기록에 남습니다.

영업시간

PATCH/core/v1/places/{placeId} · GET/core/v1/public/places/{placeId}/schedule

PATCH {"hours":{"week":{"mon":[["09:00","22:00"]], …, "sun":[]}}}   # 빈 배열 = 휴무
GET  …/schedule?days=7   # 휴무·공휴일까지 계산된 "그날 실제로 여는 구간" (인증 불필요)

API 키로는 영업시간만 수정할 수 있습니다(다른 매장 정보는 403). 저장하면 영업시간 기준으로 도는 매장 자동화가 즉시 이 값을 따릅니다.

기존 시스템의 명부를 옮겨올 때는 일괄 반입(/space/v1/customers/import · /space/v1/memberships/import)을 쓰세요 — {"source":"어느 시스템", "items":[…]} 형식이고, 행마다 독립 처리라 같은 파일을 다시 올려도 중복이 생기지 않습니다.

오프라인 동작

판정 규칙

전체 명세 (OpenAPI)

변경 이력

날짜내용
2026-09-28기기는 한 경로로: GET /device/v1/devices · GET /device/v1/devices/{id} · POST /device/v1/devices/{id}/commands. 명령은 기기가 실행했다고 답한 뒤에 응답합니다(실패는 details.reason: offline · refused · noResponse). 기존 문·보드 경로(/device/v1/doors·/device/v1/boards)는 그대로 동작하지만 새 기능은 더하지 않고 이 문서에서 뺐습니다. 기존 응답의 실패에는 reason·detail이 더해졌습니다.
2026-09-08문 통합 출입 설정 GET/PUT /space/v1/doors/{deviceId}/access-config, 지목 대상 목록 GET /space/v1/access/people · /groups 공개(기기 제어 범위). 통합 설정이 있는 문에서 기존 시간대 정책 API는 409. people 지목 대상은 허가·회원권 없이 전화만으로 입장.
2026-09-06출입 허가에 doorIds(허용 문 지정) 추가, 문별 허가 최대 길이는 지정한 문 중 가장 짧은 값.
2026-09-04영업시간 PATCH /core/v1/places/{placeId}(hours만) · 공개 일정 GET /core/v1/public/places/{placeId}/schedule.
2026-09-03v2: 허가 목록·단건, 출입 기록, 출입 설정(entryPhone), 문 제어·시간대 정책·끊김 정책(기기 제어 범위 신설), spk_test_/spk_live_ 키 구분, developers.superplace.so 개설. 허가 url 도메인 go.superplace.so 통일(기존 링크 유효).
2026-08-31첫 공개: 허가 등록·해지, 회원권, 예약, 활동 이벤트.

문의는 키를 전달받은 채널로 회신해 주세요.