> For the complete documentation index, see [llms.txt](/llms.txt)

# GS2-SerialKey

시리얼 코드 기능




게임 외부의 물품 판매나 오프라인 이벤트, SNS 캠페인, 콜라보 캠페인 등을 통해 게임 내 아이템을 배포하고 싶은 경우에 사용할 수 있습니다.
종이 패키지나 QR 코드에 인쇄한 코드, 이메일/SNS로 배포하는 문자열 모두 동일한 구조로 다룰 수 있습니다.

단, 이 기능은 일부 플랫폼 사업자가 구현을 허용하지 않는 경우가 있으므로, 채택할 때는 플랫폼 사업자의 가이드라인을 확인하도록 하십시오.

## 시리얼 코드의 종류

시리얼 코드에는 다음 두 가지 종류가 있습니다.

- 시리얼 키: 1회 사용하면 재사용할 수 없는 코드
- 캠페인 코드: 하나의 코드를 여러 사람이 공유할 수 있는 코드

```mermaid
graph TD
  SerialCode["시리얼 코드"]
  SerialCode --> SerialKey["시리얼 키<br/>1인 1회 한정"]
  SerialCode --> CampaignCode["캠페인 코드<br/>여러 명이 공용"]
  SerialKey --> SerialKeyUse["RPCLP-FP7N-NCDMJ-FLVA-IRI4"]
  CampaignCode --> CampaignCodeUse["NEWYEAR2026"]
```

### 시리얼 키

1회 사용하면 두 번 다시 사용할 수 없게 되는 코드 입니다.

시리얼 키는 "RPCLP-FP7N-NCDMJ-FLVA-IRI4"와 같은 형식으로 발행되며, 데이터 길이를 변경할 수 없습니다.
시리얼 키 내부에는 캠페인 종류에 대한 정보도 포함되어 있으며, 시리얼 키를 사용할 때는 네임스페이스를 지정하는 것만으로 사용할 수 있습니다.

### 캠페인 코드

"할로윈2025", "SUMMER"와 같이 사람이 기억하기 쉬운 문자열을, 운영 측에서 임의로 설정할 수 있는 코드 입니다.
하나의 코드를 다수의 플레이어가 공유하여 교환에 사용하는 것을 상정하고 있습니다.

캠페인 코드는 캠페인에 연결하여 발행하는 시리얼 키와는 달리, 캠페인 이름 자체가 코드로서 교환 가능해집니다.

## 캠페인

"시리얼 키"도 "캠페인 코드"도 모두 캠페인에 속합니다.

캠페인에는 다음을 설정합니다.

- `name`: 캠페인 이름(캠페인 코드로도 사용됨)
- `metadata`: 임의의 메타데이터
- `enableCampaignCode`: 캠페인 코드(캠페인 이름 자체를 사용한 교환)를 활성화할지 여부

캠페인은 GS2-Schedule 의 이벤트와 연결하여 유효 기간을 설정할 수 있습니다.
유효 기간의 검증은 트랜잭션 액션을 조합하여 실현할 수 있습니다.

### 시리얼 키 발행

대상 캠페인과 발행 수량을 지정하여 시리얼 키 발행 처리를 실행하면 시리얼 키가 발행됩니다.
발행 처리는 비동기 작업으로 실행되며, `IssueJob` 을 통해 진행 상황을 확인할 수 있습니다.
발행된 시리얼 키 목록은 CSV 형식으로 다운로드할 수 있습니다.

물품 패키지에 인쇄하는 등 대량으로 발행하는 용도로는 수십만 건 단위의 발행도 가능합니다.

### 시리얼 키의 상태

시리얼 키는 다음과 같은 상태를 가집니다.

| 상태 | 설명 |
| --- | --- |
| `ACTIVE` | 플레이어가 사용 가능한 상태 |
| `USED` | 이미 사용됨(재사용 불가) |
| `INACTIVE` | 운영에 의해 무효화된 상태 |

실제로 플레이어가 사용할 수 있는 상태가 `ACTIVE`이며, 사용하면 `USED`가 됩니다.
운영 측에서 시리얼 키를 무효화하면 `INACTIVE`가 됩니다.

## 트랜잭션 액션

GS2-SerialKey 에서는 다음과 같은 트랜잭션 액션을 제공하고 있습니다.

- 검증 액션: 시리얼 코드의 유효성 검증, 시리얼 코드가 지정된 캠페인에 속하는지 검증
- 소비 액션: 시리얼 코드의 사용 완료 처리
- 획득 액션: 시리얼 코드의 미사용화(취소용), 시리얼 코드 발행

"시리얼 코드 발행"을 획득 액션으로 활용하면, 게임 내 특정 미션을 달성했을 때나 상위 입상 보상으로서 플레이어별 고유한 시리얼 코드(타인에게 양도 가능)를 자동으로 발행하여 지급하는 처리를, 트랜잭션 내에서 안전하게 완결시킬 수 있습니다. 이를 통해 게임 외부에서의 팬 교류나 플레이어 간 선물 요소를 촉진하는 시책을 손쉽게 구현할 수 있습니다.

### 코드에 의한 교환 횟수 제한

캠페인 코드에 의한 교환은 아무 조치도 하지 않으면 몇 번이든 교환이 가능합니다.

보통은 "한 번 교환을 실행하면 두 번 다시 교환할 수 없게 한다"거나 "일정 기간 교환을 할 수 없게 하고 싶다"와 같은 요건이 있을 것이며,
캠페인 코드든 시리얼 키든 "동일 캠페인에서 교환 가능한 총 횟수에 제한을 두고 싶다"는 등 다양한 요건이 있을 것입니다.

GS2-SerialKey 는 그러한 제한 기능을 가지고 있지 않으며, 순수하게 입력된 시리얼 키가 유효한지만 판단하는 기능을 제공합니다.
그렇기 때문에 GS2-SerialKey 자체는 교환을 실행했을 때 얻을 수 있는 보상도 가지고 있지 않습니다.

시리얼 키를 사용하는 경우의 구현 예제를 아래에 나타냅니다.

```plantuml
actor Player
participant "GS2-Exchange#Rate"
participant "GS2-SerialKey#SerialKey"
participant "GS2-Limit#Counter"
participant "GS2-Inventory#Item"
Player -> "GS2-Exchange#Rate" : Exchange
"GS2-Exchange#Rate" -[#f00]-> "GS2-SerialKey#SerialKey" : Use
"GS2-Exchange#Rate" -> "GS2-Limit#Counter" : Increase
"GS2-Exchange#Rate" -> "GS2-Inventory#Item" : Acquire
"GS2-Exchange#Rate" -> Player
```

GS2-Exchange 에 의해 시리얼 키를 사용했을 때 얻을 수 있는 보상이 정의되고,
GS2-Limit 에 의해 횟수 제한이 적용되어 몇 번이든 아이템을 얻을 수 없게 됩니다.

보상을 구성할 때는 GS2-Schedule 에 의한 캠페인 기간 체크나 GS2-Inventory 에서의 경품 지급 등, 여러 마이크로서비스를 트랜잭션으로 연결하여 복잡한 요건을 실현할 수 있습니다.

## 마스터 데이터 관리

마스터 데이터를 등록하면 마이크로서비스에서 사용 가능한 데이터나 동작을 설정할 수 있습니다.

마스터 데이터의 종류에는 다음이 있습니다.

- `CampaignModel`: 캠페인(시리얼 키/캠페인 코드의 모집단) 정의

다음은 마스터 데이터의 JSON 예입니다.

```json
{
  "version": "2019-08-19",
  "campaigns": [
    {
      "name": "newyear-2026",
      "metadata": "새해 캠페인",
      "enableCampaignCode": true
    },
    {
      "name": "package-promo",
      "metadata": "패키지 동봉용 (캠페인 코드 비활성화)",
      "enableCampaignCode": false
    }
  ]
}
```

마스터 데이터의 등록은 관리 콘솔에서 등록하는 것 외에도, GitHub에서 데이터를 반영하거나 GS2-Deploy를 사용해 CI에서 등록하는 워크플로우를 구성할 수 있습니다.

## 구현 예제

### 시리얼 키를 사용

이 API로 직접 시리얼 키를 사용하는 처리를 하는 것은 권장하지 않습니다.

GS2-Exchange 와 같은 서비스를 통해 시리얼 키 사용을 수행함으로써, 시리얼 키의 사용과 보상 지급·횟수 제한 체크를 하나의 트랜잭션으로 처리할 수 있습니다.



**Unity**
```csharp

    var result = await gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).SerialKey(
        code: "code-0001"
    ).UseSerialCodeAsync(
    );
    var item = await result.ModelAsync();
```
**Unreal Engine**
```cpp

    const auto Future = Gs2->SerialKey->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->SerialKey(
        "code-0001" // code
    )->UseSerialCode(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
```
**Godot**
```gdscript

var domain = ez.serial_key.namespace_(
    "namespace-0001"
).me(game_session).serial_key("code-0001")
var async_result = await domain.use_serial_code()
if async_result.error != null:
    push_error(str(async_result.error))
    return
var item = async_result.result

```


### 시리얼 키의 정보 취득

시리얼 키의 코드를 지정하여, 해당 코드가 속한 캠페인이나 현재 상태(`ACTIVE` / `USED` / `INACTIVE`)를 확인할 수 있습니다.
교환 화면에서 "입력한 코드는 이미 사용되었습니다"와 같은 오류 메시지를 표시하는 용도로도 사용할 수 있습니다.



**Unity**
```csharp

    var item = await gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).SerialKey(
        code: "code-0001"
    ).ModelAsync();
```
**Unreal Engine**
```cpp

    const auto Domain = Gs2->SerialKey->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->SerialKey(
        "code-0001" // code
    );
    const auto Item = Domain->Model();
```
**Godot**
```gdscript

var domain = ez.serial_key.namespace_(
        "namespace-0001"
    ).user(
        "user-0001"
    ).serial_key(
        "code-0001"
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


### 캠페인 정보 취득

특정 캠페인의 정의(메타데이터, 캠페인 코드의 활성화·비활성화 등)를 취득합니다.



**Unity**
```csharp

    var item = await gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).CampaignModel(
        campaignModelName: "newyear-2026"
    ).ModelAsync();
```
**Unreal Engine**
```cpp

    const auto Domain = Gs2->SerialKey->Namespace(
        "namespace-0001" // namespaceName
    )->CampaignModel(
        "newyear-2026" // campaignModelName
    );
    const auto Item = Domain->Model();
```
**Godot**
```gdscript

var domain = ez.serial_key.namespace_(
        "namespace-0001"
    ).campaign_model(
        "campaign-0001"
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result

```


## 상세 레퍼런스

[GS2-SerialKey API 레퍼런스](../../api_reference/serial_key)



