> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs.vpms.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 외부 연동 (Third Party Integration)

> 외부 시스템 통합 API

## 개요

Third Party 도메인은 외부 시스템과의 통합 기능을 제공합니다. PMS, CMS, 도어락, 주차 시스템 등 다양한 외부 서비스와의 연동을 지원합니다.

## Enums

### ThirdPartyProvider

지원하는 외부 서비스 제공자 목록입니다.

* `SamsungSmartAccess`: 삼성 스마트 도어락
* `SanhaWings`: 산하 Wings PMS
* `TheMR`: The MR 솔루션
* `AmanoKorea`: 아마노 주차 시스템
* `NicePark`: 나이스 주차 시스템
* `TlLincoln`: TL Lincoln 솔루션
* `V_Booking`: Vendit 부킹 엔진
* `HotelStory`: 호텔스토리 PMS
* `V_CMS`: Vendit CMS

***

### ThirdPartyProviderType

외부 서비스의 카테고리를 정의합니다.

* `CMS`: 채널 관리 시스템
* `PMS`: 숙박 관리 시스템
* `Facility`: 시설 관리
* `Parking`: 주차 관리
* `Guest`: 게스트 관리
* `BookingEngine`: 예약 엔진
* `DoorLock`: 도어락 시스템

***

## Types

### ThirdPartyApp

외부 서비스 앱 정보를 나타냅니다.

<ResponseField name="id" type="ID">
  앱 ID
</ResponseField>

<ResponseField name="provider" type="String!">
  서비스 제공자 이름
</ResponseField>

<ResponseField name="scope" type="String!">
  연동 범위 (숙박 시설 ID)
</ResponseField>

<ResponseField name="type" type="String">
  서비스 타입
</ResponseField>

<ResponseField name="createdAt" type="Date!">
  생성 일시
</ResponseField>

<ResponseField name="properties" type="[ThirdPartyProperty]">
  연동 속성 목록
</ResponseField>

***

### ThirdPartyProperty

외부 서비스의 속성 정보를 나타냅니다.

<ResponseField name="id" type="ID">
  속성 ID
</ResponseField>

<ResponseField name="provider" type="String!">
  서비스 제공자 이름
</ResponseField>

<ResponseField name="type" type="String!">
  속성 타입 (예: "room\_mapping", "config")
</ResponseField>

<ResponseField name="thirdPartyId" type="String">
  외부 시스템의 ID
</ResponseField>

<ResponseField name="relatedId" type="String">
  VPMS 내부 ID (예: 객실 ID)
</ResponseField>

<ResponseField name="name" type="String">
  속성 이름
</ResponseField>

<ResponseField name="description" type="String">
  속성 설명
</ResponseField>

<ResponseField name="data" type="String">
  추가 데이터 (JSON 문자열)
</ResponseField>

***

## Queries

### getAccommodationThirdPartyApps

특정 숙박 시설에 연동된 외부 서비스 목록을 조회합니다.

#### GraphQL Signature

```graphql theme={null}
query GetAccommodationThirdPartyApps(
  $accommodationId: ID!
  $type: ThirdPartyProviderType
) {
  getAccommodationThirdPartyApps(
    accommodationId: $accommodationId
    type: $type
  ) {
    id
    provider
    scope
    type
    createdAt
    properties {
      id
      provider
      type
      thirdPartyId
      relatedId
      name
      description
      data
    }
  }
}
```

#### 파라미터

<ParamField path="accommodationId" type="ID!" required>
  숙박 시설 ID
</ParamField>

<ParamField path="type" type="ThirdPartyProviderType">
  서비스 타입 필터 (선택사항)

  * `CMS`: CMS만 조회
  * `PMS`: PMS만 조회
  * `DoorLock`: 도어락만 조회
  * `Parking`: 주차 시스템만 조회
  * 등등...
</ParamField>

#### 응답

<ResponseField name="apps" type="[ThirdPartyApp!]!">
  연동된 외부 서비스 목록
</ResponseField>

#### 예제

<CodeGroup>
  ```graphql Request - 전체 조회 theme={null}
  query {
    getAccommodationThirdPartyApps(
      accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
    ) {
      id
      provider
      type
      createdAt
      properties {
        id
        type
        name
      }
    }
  }
  ```

  ```graphql Request - 타입별 조회 theme={null}
  query {
    getAccommodationThirdPartyApps(
      accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
      type: DoorLock
    ) {
      id
      provider
      type
      properties {
        id
        type
        thirdPartyId
        relatedId
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "getAccommodationThirdPartyApps": [
        {
          "id": "01HQKS9V8X",
          "provider": "SamsungSmartAccess",
          "type": "DoorLock",
          "createdAt": "2025-01-01T00:00:00Z",
          "properties": [
            {
              "id": "01HQKS9V8Y",
              "type": "room_mapping",
              "thirdPartyId": "SSA-ROOM-101",
              "relatedId": "01HQKS9V8Z"
            }
          ]
        }
      ]
    }
  }
  ```
</CodeGroup>

***

## Mutations

### thirdPartySignIn

외부 서비스에 로그인하고 연동을 설정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation ThirdPartySignIn(
  $provider: ThirdPartyProvider!
  $code: String
  $credential: String
  $scope: String!
  $accommodationId: ID!
  $isRenew: Boolean
) {
  thirdPartySignIn(
    provider: $provider
    code: $code
    credential: $credential
    scope: $scope
    accommodationId: $accommodationId
    isRenew: $isRenew
  )
}
```

#### 파라미터

<ParamField path="provider" type="ThirdPartyProvider!" required>
  외부 서비스 제공자

  예: `SamsungSmartAccess`, `HotelStory`, `AmanoKorea`
</ParamField>

<ParamField path="code" type="String">
  OAuth 인증 코드 (OAuth 방식 사용 시)
</ParamField>

<ParamField path="credential" type="String">
  인증 정보 (API 키 또는 토큰)
</ParamField>

<ParamField path="scope" type="String!" required>
  연동 범위 (일반적으로 숙박 시설 ID)
</ParamField>

<ParamField path="accommodationId" type="ID!" required>
  숙박 시설 ID
</ParamField>

<ParamField path="isRenew" type="Boolean">
  기존 연동을 갱신할지 여부 (기본값: false)
</ParamField>

#### 응답

<ResponseField name="result" type="Boolean">
  연동 성공 여부
</ResponseField>

#### 예제

<CodeGroup>
  ```graphql Request - OAuth 방식 theme={null}
  mutation {
    thirdPartySignIn(
      provider: SamsungSmartAccess
      code: "oauth_auth_code_xyz123"
      scope: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
      accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
    )
  }
  ```

  ```graphql Request - API 키 방식 theme={null}
  mutation {
    thirdPartySignIn(
      provider: AmanoKorea
      credential: "api_key_abc123"
      scope: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
      accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
    )
  }
  ```

  ```graphql Request - 갱신 theme={null}
  mutation {
    thirdPartySignIn(
      provider: HotelStory
      credential: "new_api_key_def456"
      scope: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
      accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
      isRenew: true
    )
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "thirdPartySignIn": true
    }
  }
  ```
</CodeGroup>

***

### deleteAccommodationThirdParty

특정 외부 서비스 연동을 해제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeleteAccommodationThirdParty(
  $accommodationId: ID!
  $provider: ThirdPartyProvider!
) {
  deleteAccommodationThirdParty(
    accommodationId: $accommodationId
    provider: $provider
  )
}
```

#### 파라미터

<ParamField path="accommodationId" type="ID!" required>
  숙박 시설 ID
</ParamField>

<ParamField path="provider" type="ThirdPartyProvider!" required>
  해제할 외부 서비스 제공자
</ParamField>

#### 응답

<ResponseField name="result" type="Boolean">
  해제 성공 여부
</ResponseField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    deleteAccommodationThirdParty(
      accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
      provider: SamsungSmartAccess
    )
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "deleteAccommodationThirdParty": true
    }
  }
  ```
</CodeGroup>

<Warning>
  연동 해제 시 해당 서비스와 관련된 모든 속성(properties)도 함께 삭제됩니다.
</Warning>

***

### registerThirdPartyProperty

외부 서비스 속성을 등록합니다.

#### GraphQL Signature

```graphql theme={null}
mutation RegisterThirdPartyProperty($input: ThirdPartyPropertyInput!) {
  registerThirdPartyProperty(input: $input) {
    id
    provider
    type
    thirdPartyId
    relatedId
    name
    description
    data
  }
}
```

#### 파라미터

<ParamField path="input.accommodationId" type="ID!" required>
  숙박 시설 ID
</ParamField>

<ParamField path="input.provider" type="String!" required>
  외부 서비스 제공자 이름
</ParamField>

<ParamField path="input.type" type="String!" required>
  속성 타입

  일반적인 타입:

  * `room_mapping`: 객실 매핑
  * `config`: 설정
  * `credential`: 인증 정보
  * `webhook`: 웹훅 설정
</ParamField>

<ParamField path="input.thirdPartyId" type="String">
  외부 시스템의 ID
</ParamField>

<ParamField path="input.relatedId" type="String">
  VPMS 내부 관련 ID
</ParamField>

<ParamField path="input.name" type="String">
  속성 이름
</ParamField>

<ParamField path="input.description" type="String">
  속성 설명
</ParamField>

<ParamField path="input.data" type="String">
  추가 데이터 (JSON 문자열)
</ParamField>

#### 응답

<ResponseField name="property" type="ThirdPartyProperty">
  등록된 속성 정보
</ResponseField>

#### 예제

<CodeGroup>
  ```graphql Request - 객실 매핑 theme={null}
  mutation {
    registerThirdPartyProperty(input: {
      accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
      provider: "SamsungSmartAccess"
      type: "room_mapping"
      thirdPartyId: "SSA-ROOM-101"
      relatedId: "01HQKS9V8Z"
      name: "101호 도어락 매핑"
      description: "101호 객실과 삼성 도어락 연결"
    }) {
      id
      type
      thirdPartyId
      relatedId
    }
  }
  ```

  ```graphql Request - 설정 theme={null}
  mutation {
    registerThirdPartyProperty(input: {
      accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
      provider: "AmanoKorea"
      type: "config"
      name: "주차 시스템 설정"
      data: "{\"apiEndpoint\": \"https://api.amano.kr\", \"timeout\": 30000}"
    }) {
      id
      type
      name
      data
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "registerThirdPartyProperty": {
        "id": "01HQKS9V8Y",
        "type": "room_mapping",
        "thirdPartyId": "SSA-ROOM-101",
        "relatedId": "01HQKS9V8Z"
      }
    }
  }
  ```
</CodeGroup>

***

### modifyThirdPartyProperty

외부 서비스 속성을 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation ModifyThirdPartyProperty(
  $id: ID!
  $input: ThirdPartyPropertyInput!
) {
  modifyThirdPartyProperty(id: $id, input: $input) {
    id
    provider
    type
    thirdPartyId
    relatedId
    name
    description
    data
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  수정할 속성 ID
</ParamField>

<ParamField path="input" type="ThirdPartyPropertyInput!" required>
  수정할 속성 정보 (변경할 필드만 포함)
</ParamField>

#### 응답

<ResponseField name="property" type="ThirdPartyProperty">
  수정된 속성 정보
</ResponseField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    modifyThirdPartyProperty(
      id: "01HQKS9V8Y"
      input: {
        accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
        provider: "SamsungSmartAccess"
        type: "room_mapping"
        thirdPartyId: "SSA-ROOM-102"
        name: "102호 도어락 매핑 (수정)"
      }
    ) {
      id
      thirdPartyId
      name
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "modifyThirdPartyProperty": {
        "id": "01HQKS9V8Y",
        "thirdPartyId": "SSA-ROOM-102",
        "name": "102호 도어락 매핑 (수정)"
      }
    }
  }
  ```
</CodeGroup>

***

### deleteThirdPartyProperty

외부 서비스 속성을 삭제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeleteThirdPartyProperty($id: ID!) {
  deleteThirdPartyProperty(id: $id)
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  삭제할 속성 ID
</ParamField>

#### 응답

<ResponseField name="result" type="Boolean">
  삭제 성공 여부
</ResponseField>

***

### devThirdPartyTest

개발/테스트 목적으로 외부 서비스 연동을 테스트합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DevThirdPartyTest($accommodationId: ID, $boolData: Boolean) {
  devThirdPartyTest(accommodationId: $accommodationId, boolData: $boolData)
}
```

#### 파라미터

<ParamField path="accommodationId" type="ID">
  테스트할 숙박 시설 ID
</ParamField>

<ParamField path="boolData" type="Boolean">
  테스트 플래그
</ParamField>

<Warning>
  이 API는 개발 환경에서만 사용 가능하며, 프로덕션 환경에서는 비활성화됩니다.
</Warning>

***

## 사용 흐름

### 외부 서비스 연동 설정

1. **서비스 연동**: `thirdPartySignIn`으로 외부 서비스 인증
2. **속성 등록**: `registerThirdPartyProperty`로 객실 매핑, 설정 등록
3. **연동 확인**: `getAccommodationThirdPartyApps`로 연동 상태 확인

### 객실-도어락 매핑 예시

<Steps>
  <Step title="도어락 시스템 연동">
    ```graphql theme={null}
    mutation {
      thirdPartySignIn(
        provider: SamsungSmartAccess
        credential: "api_key_xyz"
        scope: "01HQKS9V8X"
        accommodationId: "01HQKS9V8X"
      )
    }
    ```
  </Step>

  <Step title="객실별 매핑 등록">
    ```graphql theme={null}
    mutation {
      registerThirdPartyProperty(input: {
        accommodationId: "01HQKS9V8X"
        provider: "SamsungSmartAccess"
        type: "room_mapping"
        thirdPartyId: "SSA-ROOM-101"
        relatedId: "room_01HQKS9V8Z"
        name: "101호 매핑"
      }) {
        id
      }
    }
    ```
  </Step>

  <Step title="매핑 확인">
    ```graphql theme={null}
    query {
      getAccommodationThirdPartyApps(
        accommodationId: "01HQKS9V8X"
        type: DoorLock
      ) {
        properties {
          thirdPartyId
          relatedId
          name
        }
      }
    }
    ```
  </Step>
</Steps>

***

## 지원 서비스별 연동 방법

### 도어락 시스템

**삼성 스마트 도어락 (SamsungSmartAccess)**

* 인증 방식: API 키
* 필수 속성: `room_mapping` (객실-도어락 매핑)

**TL Lincoln**

* 인증 방식: OAuth 2.0
* 필수 속성: `room_mapping`, `config`

### 주차 시스템

**아마노 주차 (AmanoKorea)**

* 인증 방식: API 키
* 필수 속성: `config` (엔드포인트, 타임아웃 설정)

**나이스 파크 (NicePark)**

* 인증 방식: API 키
* 필수 속성: `config`, `webhook`

### PMS

**호텔스토리 (HotelStory)**

* 인증 방식: OAuth 2.0
* 필수 속성: `room_mapping`, `rate_mapping`

**산하 Wings (SanhaWings)**

* 인증 방식: API 키
* 필수 속성: `room_mapping`

***

## 에러 처리

### 연동 실패

<ResponseField name="INVALID_CREDENTIALS">
  인증 정보가 유효하지 않습니다. 올바른 API 키 또는 OAuth 코드를 사용하세요.
</ResponseField>

<ResponseField name="PROVIDER_NOT_AVAILABLE">
  외부 서비스가 현재 사용 불가능합니다. 나중에 다시 시도하세요.
</ResponseField>

<ResponseField name="DUPLICATE_INTEGRATION">
  이미 연동된 서비스입니다. `isRenew: true`를 사용하여 갱신하세요.
</ResponseField>

### 속성 등록 실패

<ResponseField name="INTEGRATION_NOT_FOUND">
  먼저 `thirdPartySignIn`으로 서비스를 연동해야 합니다.
</ResponseField>

<ResponseField name="INVALID_PROPERTY_TYPE">
  지원하지 않는 속성 타입입니다. 서비스 문서를 확인하세요.
</ResponseField>

***

## 관련 API

* [사용자 API](/api-reference/user-svc/user) - 직원 권한 관리
* [Core Service](/api-reference/core-svc/introduction) - 객실 및 예약 관리
