# API 명세서

## 좌석유저 토큰 발급 API

<mark style="color:green;">`POST`</mark> `/tokens/concerts`

유저가 진입한 서비스의 대기열 토큰을 발급한다.

**Body**

| Name        | Type   | Description |
| ----------- | ------ | ----------- |
| `userId`    | Number | 유저 ID       |
| `concertId` | Number | 콘서트 ID      |

**Response**

{% tabs %}
{% tab title="200" %}
```json
{
    "id": 100,
    "userId": 1,
    "expiredAt": "2025-01-01T01:05:00Z" // 발급시간 기준 5분 후
}
```
{% endtab %}

{% tab title="400 (입력값)" %}
```json
{
  "code": "INVALID_INPUT",
  "reason": "토큰 발급에 필요한 요소가 누락되었습니다."
}
```
{% endtab %}
{% endtabs %}



***



## 예약 가능 날짜 조회 API

<mark style="color:blue;">`GET`</mark>`/concerts/{concertId}/available-dates`

콘서트의 예약 가능한 날짜를 조회한다.

**Headers**

| Name          | Value              |
| ------------- | ------------------ |
| Content-Type  | `application/json` |
| X-Queue-Token | `<token>`          |

**Response**

{% tabs %}
{% tab title="200" %}
```json
{
  "concertId": 1,
  "dates": [
    "2025-01-01",
    "2025-01-02",
    "2025-01-03",
    "2025-01-04",
  ]
}
```
{% endtab %}

{% tab title="200 (Empty)" %}
```json
{
    "concertId": 1,
    "dates": []
}
```
{% endtab %}

{% tab title="400 (입력값)" %}
```json
{
  "code": "INVALID_INPUT",
  "reason": "콘서트ID가 유효하지 않습니다."
}
```
{% endtab %}
{% endtabs %}



***



## 예약 가능 좌석 조회 API

<mark style="color:blue;">`GET`</mark>`/concerts/{concertId}/schedules/{concertScheduleId}/available-seats`

콘서트의 해당 일자에 예약 가능한 좌석을 조회한다.

**Headers**

| Name          | Value              |
| ------------- | ------------------ |
| Content-Type  | `application/json` |
| X-Queue-Token | `<token>`          |

**Query params**

| Name   | Type   | Description   |
| ------ | ------ | ------------- |
| `date` | String | YYYY-MM-DD 형식 |

**Response**

{% tabs %}
{% tab title="200" %}
```json
{
  "seats": [
    {
      "id": 550,
      "seatNum": 1,
      "price": 8000
    },
    {
      "id": 551,
      "seatNum": 2,
      "price": 10000
    }
  ]
}
```
{% endtab %}

{% tab title="200 (Empty)" %}
<pre class="language-json"><code class="lang-json">{
<strong>    "seats": []
</strong>}
</code></pre>
{% endtab %}

{% tab title="400 (입력값)" %}
```json
{
  "code": "INVALID_INPUT",
  "reason": "concertId가 유효하지않습니다."
}
```
{% endtab %}
{% endtabs %}



***



## 좌석 예약 요청 API

<mark style="color:green;">`POST`</mark> `/concerts/reservation`



**Headers**

| Name          | Value              |
| ------------- | ------------------ |
| Content-Type  | `application/json` |
| X-Queue-Token | `<token>`          |

**Body**

| Name        | Type   | Description |
| ----------- | ------ | ----------- |
| `concertId` | Number | 콘서트 ID      |
| `seatId`    | Number | 좌석 ID       |
| `date`      | String | 예매 일자       |

**Response**

{% tabs %}
{% tab title="200" %}
```json
{
    "reservationId": 1,
    "expireTime": "2025-01-01T01:00:00Z" // 만료시간
}
```
{% endtab %}

{% tab title="400 (입력값)" %}
```json
{
  "code": "INVALID_INPUT",
  "reason": "concertId가 유효하지않습니다."
}
```
{% endtab %}

{% tab title="403 (토큰 만료)" %}
```json
{
  "code": "TOKEN_EXPIRED",
  "reason": "대기열이 만료되었습니다."
}
```
{% endtab %}
{% endtabs %}



***



## 잔액 조회 API

<mark style="color:blue;">`GET`</mark>`/users/{userId}/points`



**Headers**

| Name          | Value              |
| ------------- | ------------------ |
| Content-Type  | `application/json` |
| X-Queue-Token | `<token>`          |

**Response**

{% tabs %}
{% tab title="200" %}
```json
{
    "userId": 1,
    "point": 10000
}
```
{% endtab %}

{% tab title="400 (입력값)" %}
```json
{
  "code": "INVALID_INPUT",
  "reason": "userId가 유효하지않습니다."
}
```
{% endtab %}

{% tab title="403 (토큰 만료)" %}
```json
{
  "code": "TOKEN_EXPIRED",
  "reason": "대기열이 만료되었습니다."
}
```
{% endtab %}
{% endtabs %}



***



## 잔액 충전 API

<mark style="color:green;">`POST`</mark> `/users/points/charge`



**Headers**

| Name          | Value              |
| ------------- | ------------------ |
| Content-Type  | `application/json` |
| X-Queue-Token | `<token>`          |

**Body**

| Name     | Type   | Description |
| -------- | ------ | ----------- |
| `userId` | Number | 유저 ID       |
| `amount` | Number | 충전 금액       |

**Response**

{% tabs %}
{% tab title="200" %}
```json
{
    "userId": 1,
    "point": 10000
}
```
{% endtab %}

{% tab title="400 (입력값)" %}
```json
{
  "code": "INVALID_INPUT",
  "reason": "userId가 유효하지 않습니다."
}
```
{% endtab %}

{% tab title="403 (토큰 만료)" %}
```json
{
  "code": "TOKEN_EXPIRED",
  "reason": "대기열이 만료되었습니다."
}
```
{% endtab %}
{% endtabs %}



***



## 결제 API

<mark style="color:green;">`POST`</mark> `/reservation/payments`



**Headers**

| Name          | Value              |
| ------------- | ------------------ |
| Content-Type  | `application/json` |
| X-Queue-Token | `<token>`          |

**Body**

| Name            | Type   | Description |
| --------------- | ------ | ----------- |
| `userId`        | Number | 유저 ID       |
| `reservationId` | Number | 예약 ID       |

**Response**

{% tabs %}
{% tab title="200" %}
```json
{
    "reservationId": 1, // 결제된 예약 ID
    "remainingPoint": 8000 // 남은 포인트
}
```
{% endtab %}

{% tab title="400 (입력값)" %}
```json
{
  code: "INVALID_INPUT",
  reason: "userId가 유효하지 않습니다."
}
```
{% endtab %}

{% tab title="400 (잔액부족)" %}
```json
{
  code: "INSUFFICIENT_POINT",
  reason: "잔액이 부족합니다."
}
```
{% endtab %}

{% tab title="403 (토큰 만료)" %}
```json
{
  code: "TOKEN_EXPIRED",
  reason: "대기열이 만료되었습니다."
}
```
{% endtab %}
{% endtabs %}

