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

# GS2-SerialKey トランザクションアクション

検証/消費/入手の各トランザクションアクションの仕様




## アクションの組み合わせと同時実行

すべてのサービスに共通する前提は [トランザクションアクションの組み合わせ]() にまとめています。先にそちらを読んでください。この節の残りは GS2-SerialKey 固有の内容です。

GS2-SerialKey のトランザクションアクションは、ネームスペースとシリアルコードの組で決まる 1 つのシリアルキーを対象にします。シリアルキーは使用済みかどうかと誰が使ったかを記録するもので、更新のたびに全体が書き換わります。

操作 | 同じ行を重ねたとき | 入れ子越し | 別の対象になる境界 | 直列実行モード有効時
--- | --- | --- | --- | ---
キーの使用<br>`UseByUserId` | まったく同じ指定でも発行時にエラー | 失敗する | ネームスペース・コード | 同じキーへの使用どうしは変わらない。この拒否はどのアクションも実行される前、発行時に働くため。取り消しとの衝突も、直接並べた場合も入れ子から届いた場合も解消しない（後述）
使用の取り消し<br>`RevertUseByUserId` | まったく同じ指定でも発行時にエラー | 失敗する | ネームスペース・コード | 同じキーへの取り消しどうしは同じ理由で変わらない。使用との衝突も解消しない（後述）
キーの発行<br>`IssueOnce` | それぞれが新しいキーを発行する。衝突しない | 衝突しない | 発行のたびに別の対象 | 変わらない。もともと衝突しない
コードの検証<br>`VerifyCodeByUserId` | まったく同じ検証は 1 件にまとめられる | 読み取りだけなので衝突しない | コード・検証タイプ・ユーザー・キャンペーン | 変わらない。読み取りだけなのでもともと衝突しない

使用と取り消しは行が違い、境界が同じです。1 つのキーを同じトランザクションで使用して取り消すことはできません。キーが違えば別の対象なので、複数のキーを使うのは問題ありません。同じキーへの取り消しを 1 つのトランザクションに 2 件置いた場合も、使用と同じく発行時にエラーになります。1 つのトランザクションに 2 件並べる用途が無いうえ、1 件目で未使用に戻った以上 2 件目は必ず失敗するからです。**直列実行モード（`enableSequentialExecution` または `TransactionSettingV2`）を有効にしても、この組み合わせは成立しません。使用は消費アクションで取り消し（入手アクション）より先に実行されるため、取り消し自身のチェックは通ります。しかしその 2 件は同じトランザクションでキーの状態を逆の値に書き込むことになり、まとめられずにトランザクションが失敗します (400)。同じキーへの取り消しを 2 件置いた場合の発行時エラーは変わりません。これはトランザクションの発行時に働く拒否だからです。**

シリアルキーは 1 度しか使えません。それがシリアルキーの存在理由です。同じキーの 2 回目の使用は、同じトランザクションからであれ後のトランザクションからであれ失敗します。**同じキーの使用を 1 つのトランザクションに 2 件置いた場合は、発行時にエラーになります。** 2 件目を 1 件目に合成することはできないので、1 つのトランザクションに 1 件だけ置いてください。境界にユーザーは含まれません。シリアルキーは誰が使ったかを記録しますが、たどり着く先はネームスペースとコードだけで決まる 1 行なので、同じコードの使用を違うユーザーに対して 2 件並べても 1 つの対象として扱われ、同じくエラーになります。シリアルキーを使う陳列商品を数量 2 以上で購入した場合も、アクションが個数ぶん積まれるためこれに当たります。同じコードを要求する複数のスキルツリーノードをまとめて解放した場合も同様です。

キーを発行して同じトランザクションで使うことはできません。使用はトランザクション開始時点の状態から動くため、その時点ではキーがまだ存在しないからです。検証アクションも同じ開始時点の状態を見るため、同じトランザクションで使用したコードも未使用として読まれます。

キーの使用は、そのキャンペーンが与えるものを配ります。それは自身のトランザクションとして発行されるため、与えるものが属するサービスの制限がそのまま当てはまり、下記も当てはまります。1 つのトランザクションで複数のシリアルキーを使うこと自体は GS2-SerialKey の側では問題ありませんが、それらが与えるものはすべて同じトランザクションに集まります。2 つのキャンペーンが同じアイテムや同じ通貨を配る場合は、そのサービスのページを確認してください。

### 入れ子になったトランザクションに注意

同じシリアルキーが内側で使用され外側で取り消されると、トランザクションが失敗します。 直列実行モードを有効にしても、これは解消しません。どちらが先に実行されるかはアクション名で決まります（外側の取り消しと、内側の使用を起動する入手アクションは、どちらも入手アクションです）が、どちらの順序でも成立しません。使用が先に実行された場合、取り消し自身のチェックは通りますが、2 件がキーの状態を逆の値に書き込むことになり、まとめられずに失敗します (400)。取り消しが先に実行された場合は、キーがまだ使用されていないため失敗します。

### 制限を回避したい場合

キーの使用は消費アクション、使用の取り消しと発行は入手アクションです。`acquireActionUseJobQueue` で分離できるのは付与どうしだけで、使用そのものからは分離されません。`enableAtomicCommit` を無効にすれば衝突は解消しますが、この判断は慎重に行ってください。使用済みになったシリアルキーは、その後に付与が失敗しても再び使うことはできません。

同じキーの使用どうしにも、取り消しどうしにも抜け道はありません。検査はどちらの設定よりも前に走りますし、シリアルコードは 1 度しか使えないものなので、有効にしても何も変わりません。検査はネームスペースとコードだけを見るため、何度でも使えるキャンペーンコードであっても、同じコードを 2 件並べれば同じくエラーになります。トランザクションを分け、シリアルキーを使う陳列商品は 1 個ずつ購入し、同じコードを要求するスキルツリーノードは別々に解放してください。

### 同時実行とリトライ

シリアルキーの使用は、すでに使われていないことを確認します。そのため同じコードを同時に使おうとすると、後から確定した側が失敗します。これが 1 つのコードを二重に使わせないための仕組みで、使用済みになった以上リトライしても変わりません。

シリアルキーが違えば別の対象なので、異なるコードを同時に使っても GS2-SerialKey 自身の中ではコンフリクトしません。

---


## Verify Action

検証アクション

### Gs2SerialKey:VerifyCodeByUserId

ユーザーIDを指定してシリアルコードの有効性を確認<br>

指定されたユーザーのシリアルコードを消費せずに検証します。特定のキャンペーンモデル名に対する検証をサポートし、コードがactive（未使用）かinactive（使用済み）かを確認できます。

**数量指定可能なアクション：いいえ**

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| userId | string |  | ✓|  |  ~ 128文字 | ユーザーID<br>`#{userId}` と設定することでログイン中のユーザーIDに置換されます。 |
| code | string |  | ✓|  |  ~ 48文字 | シリアルコード<br>「XXXXX-XXXX-XXXXX-XXXX-XXXX」形式のシリアルコード文字列です。各コードは一意で、キャンペーン識別情報が含まれています。コードの形式とデータ長は固定で変更できません。 |
| campaignModelName | string |  | |  |  ~ 128文字 | キャンペーン名<br>このシリアルコードが属するキャンペーンモデルの名前です。キャンペーン情報はシリアルコード自体に埋め込まれているため、コード使用時にはネームスペースを指定するだけで利用できます。 |
| verifyType | 文字列列挙型<br>enum {<br>"active",<br>"inactive"<br>}<br> |  | ✓|  |  | 検証タイプactive: 有効 / inactive: 無効 /  |
| timeOffsetToken | string |  | |  |  ~ 1024文字 | タイムオフセットトークン |




**JSON**
```json
{
    "action": "Gs2SerialKey:VerifyCodeByUserId",
    "request": {
        "namespaceName": "[string]ネームスペース名",
        "userId": "[string]ユーザーID",
        "code": "[string]シリアルコード",
        "campaignModelName": "[string]キャンペーン名",
        "verifyType": "[string]検証タイプ",
        "timeOffsetToken": "[string]タイムオフセットトークン"
    }
}
```

**YAML**
```yaml

action: Gs2SerialKey:VerifyCodeByUserId
request:
  namespaceName: "[string]ネームスペース名"
  userId: "[string]ユーザーID"
  code: "[string]シリアルコード"
  campaignModelName: "[string]キャンペーン名"
  verifyType: "[string]検証タイプ"
  timeOffsetToken: "[string]タイムオフセットトークン"
```

**GS2-Script**
```lua

transaction.service("serialKey").verify.verify_code_by_user_id({
    namespaceName="[string]ネームスペース名",
    userId="[string]ユーザーID",
    code="[string]シリアルコード",
    campaignModelName="[string]キャンペーン名",
    verifyType="[string]検証タイプ",
    timeOffsetToken="[string]タイムオフセットトークン",
})
```


---

## Consume Action

消費アクション

### Gs2SerialKey:UseByUserId

ユーザーIDを指定してシリアルコードの使用済み化<br>

指定されたユーザーによりシリアルコードを使用済みとしてマークします。コードが存在し、まだ使用されていないことを検証します。

**数量指定可能なアクション：いいえ**

**反転可能なアクション：はい**

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| userId | string |  | ✓|  |  ~ 128文字 | ユーザーID<br>`#{userId}` と設定することでログイン中のユーザーIDに置換されます。 |
| code | string |  | ✓|  |  ~ 48文字 | シリアルコード<br>「XXXXX-XXXX-XXXXX-XXXX-XXXX」形式のシリアルコード文字列です。各コードは一意で、キャンペーン識別情報が含まれています。コードの形式とデータ長は固定で変更できません。 |
| timeOffsetToken | string |  | |  |  ~ 1024文字 | タイムオフセットトークン |




**JSON**
```json
{
    "action": "Gs2SerialKey:UseByUserId",
    "request": {
        "namespaceName": "[string]ネームスペース名",
        "userId": "[string]ユーザーID",
        "code": "[string]シリアルコード",
        "timeOffsetToken": "[string]タイムオフセットトークン"
    }
}
```

**YAML**
```yaml

action: Gs2SerialKey:UseByUserId
request:
  namespaceName: "[string]ネームスペース名"
  userId: "[string]ユーザーID"
  code: "[string]シリアルコード"
  timeOffsetToken: "[string]タイムオフセットトークン"
```

**GS2-Script**
```lua

transaction.service("serialKey").consume.use_by_user_id({
    namespaceName="[string]ネームスペース名",
    userId="[string]ユーザーID",
    code="[string]シリアルコード",
    timeOffsetToken="[string]タイムオフセットトークン",
})
```


---

## Acquire Action

入手アクション

### Gs2SerialKey:RevertUseByUserId

ユーザーIDを指定してシリアルコードを未使用化<br>

使用済みのシリアルコードを未使用状態に戻します。リバート前にコードが現在使用済み状態であることを検証します。

**数量指定可能なアクション：いいえ**

**反転可能なアクション：はい**

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| userId | string |  | ✓|  |  ~ 128文字 | ユーザーID<br>`#{userId}` と設定することでログイン中のユーザーIDに置換されます。 |
| code | string |  | ✓|  |  ~ 48文字 | シリアルコード<br>「XXXXX-XXXX-XXXXX-XXXX-XXXX」形式のシリアルコード文字列です。各コードは一意で、キャンペーン識別情報が含まれています。コードの形式とデータ長は固定で変更できません。 |
| timeOffsetToken | string |  | |  |  ~ 1024文字 | タイムオフセットトークン |




**JSON**
```json
{
    "action": "Gs2SerialKey:RevertUseByUserId",
    "request": {
        "namespaceName": "[string]ネームスペース名",
        "userId": "[string]ユーザーID",
        "code": "[string]シリアルコード",
        "timeOffsetToken": "[string]タイムオフセットトークン"
    }
}
```

**YAML**
```yaml

action: Gs2SerialKey:RevertUseByUserId
request:
  namespaceName: "[string]ネームスペース名"
  userId: "[string]ユーザーID"
  code: "[string]シリアルコード"
  timeOffsetToken: "[string]タイムオフセットトークン"
```

**GS2-Script**
```lua

transaction.service("serialKey").acquire.revert_use_by_user_id({
    namespaceName="[string]ネームスペース名",
    userId="[string]ユーザーID",
    code="[string]シリアルコード",
    timeOffsetToken="[string]タイムオフセットトークン",
})
```


---

### Gs2SerialKey:IssueOnce

シリアルコードを1件発行<br>

シリアルコードを1件即座に発行します。コードはAES暗号化とbase32エンコーディングを使用してXXXXX-XXXX-XXXXX-XXXX-XXXXXの形式で生成されます。バッチ発行ジョブとは異なり、同期的にコードを生成して返却します。

**数量指定可能なアクション：いいえ**

**反転可能なアクション：いいえ**

|  | 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128文字 | ネームスペース名<br>ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 |
| campaignModelName | string |  | ✓|  |  ~ 128文字 | キャンペーンモデル名 |
| metadata | string |  | |  |  ~ 2048文字 | メタデータ<br>メタデータには任意の値を設定できます。<br>これらの値は GS2 の動作には影響しないため、ゲーム内で利用する情報の保存先として使用できます。 |




**JSON**
```json
{
    "action": "Gs2SerialKey:IssueOnce",
    "request": {
        "namespaceName": "[string]ネームスペース名",
        "campaignModelName": "[string]キャンペーンモデル名",
        "metadata": "[string]メタデータ"
    }
}
```

**YAML**
```yaml

action: Gs2SerialKey:IssueOnce
request:
  namespaceName: "[string]ネームスペース名"
  campaignModelName: "[string]キャンペーンモデル名"
  metadata: "[string]メタデータ"
```

**GS2-Script**
```lua

transaction.service("serialKey").acquire.issue_once({
    namespaceName="[string]ネームスペース名",
    campaignModelName="[string]キャンペーンモデル名",
    metadata="[string]メタデータ",
})
```


---



