# 자동 생성 — 문구는 scripts/partner-openapi-copy.yaml, 표면은 서비스 openapi.yaml의 x-public. scripts/partner-openapi.py로 재생성. openapi: 3.0.3 info: title: superplace 파트너 API version: v1 description: '발급받은 spk_ 키를 액세스 토큰으로 바꿔 호출합니다. 모든 응답은 `{"success": true, "data": …}` 형태이고, 오류는 `{"success": false, "error": "코드", "message": "설명"}`입니다. 시작 방법과 동작 규칙은 [가이드](https://developers.superplace.so)에 있습니다.' servers: - url: https://api.superplace.so tags: - name: 인증 description: API 키를 액세스 토큰으로 바꾸고, 매장에서 일어난 일을 조회합니다. - name: 손님과 출입 description: 손님 등록, 회원권, 출입 허가, 예약, 출입 기록. 출입 자격은 회원권·출입 허가·예약 중 하나만 있으면 됩니다. - name: 기기 description: 매장에 설치된 기기를 다룹니다. 지금은 출입문(doors)과 제어 보드(boards)가 있고, 종류는 계속 늘어납니다. paths: /core/v1/auth/apikey/token: post: tags: - 인증 summary: API 키를 액세스 토큰으로 교환 description: '발급받은 spk_ 키를 보내면 15분간 유효한 액세스 토큰을 돌려줍니다. 이후 모든 호출에 `Authorization: Bearer <액세스 토큰>` 헤더를 붙이세요. 만료되면 같은 방법으로 다시 교환하면 됩니다. 키가 잘못되면 401, 한 IP에서 지나치게 자주 부르면 429가 옵니다.' responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: key: spk_test_... security: [] /core/v1/places/{id}/events: get: tags: - 인증 summary: 매장 활동 기록 조회 description: 개문, 허가 발급·회수처럼 매장에서 일어난 일을 시간순으로 조회합니다. filter·page 파라미터로 좁힐 수 있습니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' parameters: - name: id in: path required: true schema: type: string description: 매장 ID — 토큰 교환 응답의 placeId를 그대로 넣습니다 (문 ID가 아닙니다) security: - bearerAuth: [] /device/v1/boards: get: tags: - 기기 summary: 제어 보드 목록 description: 문을 실제로 여닫는 제어 보드의 연결 상태(온라인 여부)와 펌웨어 버전을 돌려줍니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' security: - bearerAuth: [] /device/v1/boards/{boardId}: get: tags: - 기기 summary: 제어 보드 단건 조회 responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' parameters: - name: boardId in: path required: true schema: type: string security: - bearerAuth: [] /device/v1/boards/{boardId}/netloss: get: tags: - 기기 summary: 인터넷 끊김 정책 조회 description: 설정한 값(desired)과 보드가 실제로 갖고 있는 값(reported)을 함께 돌려주므로 반영 여부를 바로 확인할 수 있습니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' parameters: - name: boardId in: path required: true schema: type: string security: - bearerAuth: [] put: tags: - 기기 summary: 인터넷 끊김 정책 설정 description: 인터넷이 graceSec(10~3600초)보다 오래 끊기면 보드가 스스로 채널별 정책을 적용합니다 — open(열어두기)·close(잠그기)·hold(현 상태 유지)·off(아무것도 안 함). channels는 보내는 값으로 전체 교체됩니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: graceSec: 60 channels: door1: open parameters: - name: boardId in: path required: true schema: type: string security: - bearerAuth: [] /device/v1/doors: get: tags: - 기기 summary: 문 목록 description: 문마다 현재 상태(잠김·열림·열어두기)와 온라인 여부를 돌려줍니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' security: - bearerAuth: [] /device/v1/doors/{id}/close: post: tags: - 기기 summary: 문 잠그기 description: 열어두기 중이었다면 해제하고 잠급니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' parameters: - name: id in: path required: true schema: type: string - name: Idempotency-Key in: header required: true schema: type: string example: order-1024-open-1 description: 요청마다 고유한 문자열. 네트워크 재시도로 같은 값이 다시 오면 명령을 중복 실행하지 않고 원래 결과를 돌려줍니다. security: - bearerAuth: [] /device/v1/doors/{id}/hold: post: tags: - 기기 summary: 문 열어두기 description: minutes 동안 문을 열린 상태로 유지합니다. 0이면 다시 잠글 때까지 계속 열려 있습니다. 최대 720분(12시간). 열어두기 중에도 출입 기록은 남습니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: minutes: 30 parameters: - name: id in: path required: true schema: type: string - name: Idempotency-Key in: header required: true schema: type: string example: order-1024-open-1 description: 요청마다 고유한 문자열. 네트워크 재시도로 같은 값이 다시 오면 명령을 중복 실행하지 않고 원래 결과를 돌려줍니다. security: - bearerAuth: [] /device/v1/doors/{id}/open: post: tags: - 기기 summary: 문 열기 description: 문이 잠깐 열립니다(도어락 1회 개방). reason은 기록용이며 생략해도 됩니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: reason: 방문 손님 parameters: - name: id in: path required: true schema: type: string - name: Idempotency-Key in: header required: true schema: type: string example: order-1024-open-1 description: 요청마다 고유한 문자열. 네트워크 재시도로 같은 값이 다시 오면 명령을 중복 실행하지 않고 원래 결과를 돌려줍니다. security: - bearerAuth: [] /device/v1/doors/{id}/policies: get: tags: - 기기 summary: 문 시간대 정책 조회 description: 시간대별로 문이 어떻게 동작할지 정한 목록입니다. mode는 free(자유 개방)·auth(인증해야 열림)·closed(폐쇄) 세 가지입니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' parameters: - name: id in: path required: true schema: type: string security: - bearerAuth: [] post: tags: - 기기 summary: 문 시간대 정책 추가 description: window는 always(항상)·business_hours(영업시간)·after_hours(영업 외)·custom 중 하나입니다. 시간대가 겹치면 더 엄격한 쪽(closed > auth > free)이 적용됩니다. 저장하면 즉시 기기에 반영됩니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: window: ref: always mode: auth parameters: - name: id in: path required: true schema: type: string security: - bearerAuth: [] /device/v1/doors/{id}/policies/{policyId}: delete: tags: - 기기 summary: 문 시간대 정책 삭제 responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' parameters: - name: id in: path required: true schema: type: string - name: policyId in: path required: true schema: type: string security: - bearerAuth: [] /space/v1/customers: get: tags: - 손님과 출입 summary: 손님 검색 description: q에 이름이나 전화번호 일부를 넣어 검색합니다. q가 없으면 최근 등록순입니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' security: - bearerAuth: [] post: tags: - 손님과 출입 summary: 손님 등록 description: 전화번호가 이미 있으면 새로 만들지 않고 그 손님의 정보를 갱신합니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: phone: 01012345678 name: 홍길동 security: - bearerAuth: [] /space/v1/customers/import: post: tags: - 손님과 출입 summary: 손님 일괄 등록 description: 여러 명을 한 번에 등록합니다. source에 어느 시스템에서 온 명부인지 적고, items에 행을 담습니다. 행마다 독립으로 처리되므로 일부가 실패해도 나머지는 등록되고, 응답에 행별 결과가 담깁니다. 같은 파일을 다시 올려도 중복이 생기지 않습니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: source: 우리시스템 items: - phone: 01012345678 name: 홍길동 - phone: 01098765432 name: 김영희 security: - bearerAuth: [] /space/v1/entry-permits: get: tags: - 손님과 출입 summary: 출입 허가 목록 (전체) description: 콘솔에서 발급한 것까지 포함해 최근 200건을 돌려줍니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' security: - bearerAuth: [] /space/v1/memberships: get: tags: - 손님과 출입 summary: 회원권 목록 responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' security: - bearerAuth: [] post: tags: - 손님과 출입 summary: 회원권 발급 description: 기간 안에는 등록된 전화번호로 전화·QR 입장이 됩니다. 손님이 미리 등록돼 있지 않아도 자동으로 등록됩니다. 날짜는 RFC3339 형식입니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: phone: 01012345678 name: 홍길동 startsAt: '2026-09-04T00:00:00+09:00' endsAt: '2026-10-04T00:00:00+09:00' price: 99000 security: - bearerAuth: [] /space/v1/memberships/import: post: tags: - 손님과 출입 summary: 회원권 일괄 반입 description: 기존 시스템에서 회원권을 옮겨올 때 씁니다. 손님과 기간이 같은 회원권이 이미 있으면 건너뛰므로(응답에 skipped로 표시) 여러 번 올려도 안전합니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: source: 우리시스템 items: - phone: 01012345678 name: 홍길동 startsAt: '2026-09-01' endsAt: '2026-09-30' security: - bearerAuth: [] /space/v1/memberships/{id}: patch: tags: - 손님과 출입 summary: 회원권 수정 description: 보낸 필드만 바뀝니다. 기간(startsAt·endsAt)·메모 등을 수정할 수 있습니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: memo: 연장 협의 parameters: - name: id in: path required: true schema: type: string security: - bearerAuth: [] /space/v1/memberships/{id}/cancel: post: tags: - 손님과 출입 summary: 회원권 해지 responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' parameters: - name: id in: path required: true schema: type: string security: - bearerAuth: [] /space/v1/memberships/{id}/hold: post: tags: - 손님과 출입 summary: 회원권 일시정지 responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' parameters: - name: id in: path required: true schema: type: string security: - bearerAuth: [] /space/v1/memberships/{id}/resume: post: tags: - 손님과 출입 summary: 회원권 재개 responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' parameters: - name: id in: path required: true schema: type: string security: - bearerAuth: [] /space/v1/partner/entry-logs: get: tags: - 손님과 출입 summary: 출입 기록 조회 description: 누가 언제 어떤 방법(전화·QR)으로 들어왔는지 조회합니다. 최근 30일까지입니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' security: - bearerAuth: [] /space/v1/partner/entry-permits: get: tags: - 손님과 출입 summary: 발급한 허가 목록 description: 이 API로 발급한 허가만 돌려줍니다(콘솔 발급분 제외). 개인정보 보호를 위해 전화번호는 뒤 4자리만 담깁니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' security: - bearerAuth: [] post: tags: - 손님과 출입 summary: 출입 허가 발급 description: 전화번호와 이용 시간을 보내면 그 시간 동안 손님이 전화·QR로 문을 열 수 있습니다. 응답의 url을 손님에게 문자로 보내면 손님이 QR을 띄웁니다. externalRef가 같은 요청은 새로 만들지 않고 시간을 갱신하므로, 재전송이나 시간 변경도 같은 요청으로 처리하면 됩니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: phone: 01012345678 name: 홍길동 startsAt: '2026-09-04T14:00:00+09:00' endsAt: '2026-09-04T18:00:00+09:00' externalRef: order-1024 security: - bearerAuth: [] /space/v1/partner/entry-permits/revoke: post: tags: - 손님과 출입 summary: 출입 허가 회수 description: externalRef로 지정한 허가를 회수합니다. 회수 즉시 전화·QR이 거절됩니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: externalRef: order-1024 security: - bearerAuth: [] /space/v1/partner/entry-permits/{id}: get: tags: - 손님과 출입 summary: 허가 단건 조회 responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' parameters: - name: id in: path required: true schema: type: string security: - bearerAuth: [] /space/v1/partner/gate-config: get: tags: - 손님과 출입 summary: 출입 설정 조회 description: 전화 인증 사용 여부(phoneEnabled), 손님이 걸 출입 전화번호(entryPhone), 허가 한 건의 최대 길이(entryPermitMaxHours)를 돌려줍니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' security: - bearerAuth: [] /space/v1/partner/reservations: post: tags: - 손님과 출입 summary: 예약 등록 description: 방(자원)을 시간 단위로 예약합니다. resourceName에 "611호"처럼 이름으로 지정해도 됩니다. externalRef는 파트너 쪽 예약번호 — 같은 값을 다시 보내면 중복 등록되지 않습니다. phone을 넣으면 그 시간 동안 전화·QR 입장이 됩니다. responses: '200': $ref: '#/components/responses/Success' '400': $ref: '#/components/responses/Error' requestBody: content: application/json: schema: type: object example: resourceName: 611호 startsAt: '2026-09-04T14:00:00+09:00' endsAt: '2026-09-04T16:00:00+09:00' phone: 01012345678 name: 홍길동 externalRef: resv-2048 security: - bearerAuth: [] components: responses: Success: description: 요청이 처리됐습니다. 결과는 data에 담겨 옵니다. content: application/json: schema: type: object properties: success: type: boolean example: true data: {} Error: description: 요청이 거절됐습니다. error는 분기용 코드, message는 사람이 읽는 설명입니다. content: application/json: schema: type: object properties: success: type: boolean example: false error: type: string example: AUTH.TOKEN_INVALID message: type: string example: 토큰이 만료됐습니다 securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: POST /core/v1/auth/apikey/token 으로 spk_ 키를 교환한 15분 액세스 토큰