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

# GS2-Exchange SDK for Game Engine API Reference

Specifications of models and API references for GS2-Exchange SDK for Game Engine



## Models

### EzAwait

Exchange Await

Represents the execution state of an exchange that requires real-time to elapse before rewards can be claimed. Created when a player initiates an exchange with `await` timing type, and tracks the waiting period until the rewards become available. Supports skip functionality to shorten or eliminate the waiting time, and stores default configuration values for reward acquisition.

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| userId | string |  | ✓ |  |  ~ 128 chars | User ID |
| rateName | string |  | ✓ |  |  ~ 128 chars | Exchange Rate Model name<br>Unique Exchange Rate Model name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| name | string |  | ✓ | UUID |  ~ 36 chars | Exchange Await name<br>Maintains a unique name for each Exchange Await.<br>The name is automatically generated in UUID (Universally Unique Identifier) format and used to identify each Exchange Await. |
| skipSeconds | int |  |  | 0 | 0 ~ 2147483646 | Skip seconds<br>The number of seconds to subtract from the waiting time. When skip seconds are applied, the acquirableAt timestamp is moved earlier by this amount. Used to implement mechanics where players can pay resources to speed up the waiting process. |
| config | [List&lt;EzConfig&gt;](#ezconfig) |  |  | [] | 0 ~ 32 items | Default configuration values applied when obtaining rewards<br>Key-value pairs used as transaction placeholder variables when the await completes and rewards are distributed. These values are set at the time of exchange initiation and applied to the acquire actions' transaction parameters. |
| exchangedAt | long |  |  |  |  | Exchange time<br>The timestamp when the exchange was initiated and the await was created. Used as the base time for calculating when rewards become available (acquirableAt = exchangedAt + lockTime - skipSeconds). |
| acquirableAt | long |  |  |  |  | Time when rewards become claimable<br>The timestamp at which the waiting period expires and rewards become claimable. Calculated as exchangedAt + lockTime - skipSeconds. The player can call the acquire API once the current time has passed this timestamp. |

**Related methods:**
acquire - Claim the reward from a completed time-delayed exchange
deleteAwait - Cancel a pending time-delayed exchange
getAwait - Get a specific pending time-delayed exchange
listAwaits - List pending time-delayed exchanges


---

### EzRateModel

Exchange Rate Model

Exchange Rate Model is an entity that defines the rate used to exchange one resource for another.

In addition to the rate at which a resource can be exchanged immediately, a rate can also be set at which a resource can be exchanged after a certain amount of time in real time has elapsed.
Exchange rates that require a certain period of real time to elapse can also define the resources required to perform an immediate exchange.

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| name | string |  | ✓ |  |  ~ 128 chars | Exchange Rate Model name<br>Unique Exchange Rate Model name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| metadata | string |  |  |  |  ~ 2048 chars | Metadata<br>Arbitrary values can be set in the metadata.<br>Since they do not affect GS2’s behavior, they can be used to store information used in the game. |
| timingType | string (enum)<br>enum {<br>"immediate",<br>"await"<br>}<br> |  |  | "immediate" |  | Type of exchange<br>Determines when rewards are delivered after performing the exchange. `immediate` delivers rewards instantly upon exchange execution. `await` requires real-time to elapse before rewards can be claimed, creating a waiting period (e.g., crafting time)."immediate": Immediate / "await": Waiting for real time to pass /  |
| lockTime | int | {timingType} == "await" | ✓* |  | 0 ~ 538214400 | Waiting time (minutes) from the execution of the exchange until the reward is actually received<br>Only applicable when timingType is `await`. Specifies the number of minutes that must elapse in real time after the exchange is initiated before the player can claim the rewards. The waiting time can be shortened by using the skip mechanism.<br><br>* Required if timingType is "await" |
| verifyActions | [List&lt;EzVerifyAction&gt;](#ezverifyaction) |  |  | [] | 0 ~ 10 items | List of Verify Actions<br>Precondition checks that must all pass before the exchange is executed. If any verify action fails, the exchange is aborted without consuming resources. Used to enforce conditions such as level requirements or inventory capacity. |
| consumeActions | [List&lt;EzConsumeAction&gt;](#ezconsumeaction) |  |  | [] | 0 ~ 10 items | List of Consume Actions<br>Defines the resources (cost) that the player must pay to perform this exchange. Multiple consume actions can be specified, allowing complex exchange costs such as requiring both gold and items. These actions are executed as consume actions within a distributed transaction. |
| acquireActions | [List&lt;EzAcquireAction&gt;](#ezacquireaction) |  |  | [] | 0 ~ 100 items | List of Acquire Actions<br>Defines the resources (rewards) that the player receives upon completing the exchange. Multiple acquire actions can be specified to grant various resource types simultaneously. These actions are executed as acquire actions within a distributed transaction. |

**Related methods:**
getRateModel - Get an exchange rate model by name
listRateModels - List exchange rate models
exchange - Perform an exchange


---

### EzIncrementalRateModel

Incremental Cost Exchange Rate Model

Normal exchange rates always provide exchanges at a constant rate.
With incremental exchange rates, you can define a rate that increases in cost as the number of exchanges increases.
For example, the first exchange is performed at a rate of 1:1, but the second exchange is performed at a rate of 2:1.
By defining such a rate, you can increase the value of the resources obtained by the player as the game progresses.

The number of exchanges can be reset after a certain period of real time has elapsed.
This is useful for resetting the number of exchanges on a daily or weekly basis.

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| name | string |  | ✓ |  |  ~ 128 chars | Incremental Cost Exchange Rate Model name<br>Unique Incremental Cost Exchange Rate Model name. Specified using alphanumeric characters, hyphen (-), underscore (_), and period (.). |
| metadata | string |  |  |  |  ~ 2048 chars | Metadata<br>Arbitrary values can be set in the metadata.<br>Since they do not affect GS2’s behavior, they can be used to store information used in the game. |
| calculateType | string (enum)<br>enum {<br>"linear",<br>"power",<br>"gs2_script"<br>}<br> |  | ✓ |  |  | Calculation method for cost increase amount<br>Determines how the exchange cost escalates with each exchange. `linear` calculates cost as baseValue + (coefficientValue * exchangeCount). `power` calculates cost as coefficientValue * (exchangeCount + 1)^2. `gs2_script` delegates the calculation to a custom GS2-Script for arbitrary logic."linear": Base Value + (Coefficient * Number of Exchanges) / "power": Coefficient * (Number of Exchanges + 1) ^ 2 / "gs2_script": Custom logic implemented with GS2-Script /  |
| consumeAction | [EzConsumeAction](#ezconsumeaction) |  | ✓ |  |  | Consume Action (Quantity and Value are overwritten automatically)<br>Defines the type of resource consumed as cost for the exchange. The actual quantity is calculated dynamically based on the exchange count and the calculation type (linear, power, or script). Only the action type and target resource need to be specified; the quantity field is overwritten automatically. |
| baseValue | long | {calculateType} == "linear" | ✓* |  | 0 ~ 9223372036854775805 | Base Value<br>The initial cost for the first exchange when using the `linear` calculation type. The total cost is calculated as: baseValue + (coefficientValue * exchangeCount).<br><br>* Required if calculateType is "linear" |
| coefficientValue | long | {calculateType} in ["linear", "power"] | ✓* |  | 0 ~ 9223372036854775805 | Coefficient Value<br>The multiplier that controls how quickly costs escalate with each exchange. In `linear` mode, each exchange adds this value to the cost. In `power` mode, the cost is calculated as: coefficientValue * (exchangeCount + 1)^2.<br><br>* Required if calculateType is "linear","power" |
| exchangeCountId | string |  | ✓ |  |  ~ 1024 chars | GS2-Limit Usage Limit Model GRN for managing exchange execution counts<br>References a GS2-Limit limit model that tracks how many times each user has performed this incremental exchange. The count is used to calculate the escalating cost and can be reset periodically (e.g., daily or weekly) using GS2-Limit's reset timing. |
| maximumExchangeCount | int |  |  | 2147483646 | 0 ~ 2147483646 | Maximum number of exchanges<br>The maximum number of times this incremental exchange can be performed by a user. Once the exchange count reaches this limit, further exchanges are denied until the count is reset via GS2-Limit. |
| acquireActions | [List&lt;EzAcquireAction&gt;](#ezacquireaction) |  |  | [] | 0 ~ 100 items | List of Acquire Actions<br>Defines the resources (rewards) that the player receives upon completing the incremental exchange. The rewards remain constant regardless of the exchange count; only the cost increases with each exchange. |

**Related methods:**
getIncrementalRateModel - Get an incremental cost exchange rate model by name
listIncrementalRateModels - List Incremental Cost Exchange Rate Models
incrementalExchange - Perform an incremental cost exchange


---

### EzConfig

Configuration

Configuration values applied to transaction variables

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| key | string |  | ✓ |  |  ~ 64 chars | Name |
| value | string |  |  |  |  ~ 51200 chars | Value |

**Related methods:**
exchange - Perform an exchange
incrementalExchange - Perform an incremental cost exchange


**Related models:**
EzAwait - Exchange Await



---

### EzAcquireAction

Acquire Action

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| action | string (enum)<br>enum {<br>}<br> |  | ✓ |  |  | Type of Acquire Action |
| request | string |  | ✓ |  |  ~ 524288 chars | JSON string of the request used when executing the action |


**Related models:**
EzRateModel - Exchange Rate Model
EzIncrementalRateModel - Incremental Cost Exchange Rate Model



---

### EzConsumeAction

Consume Action

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| action | string (enum)<br>enum {<br>}<br> |  | ✓ |  |  | Type of Consume Action |
| request | string |  | ✓ |  |  ~ 524288 chars | JSON string of the request used when executing the action |


**Related models:**
EzRateModel - Exchange Rate Model
EzIncrementalRateModel - Incremental Cost Exchange Rate Model



---

### EzVerifyAction

Verify Action

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| action | string (enum)<br>enum {<br>}<br> |  | ✓ |  |  | Type of Verify Action |
| request | string |  | ✓ |  |  ~ 524288 chars | JSON string of the request used when executing the action |


**Related models:**
EzRateModel - Exchange Rate Model



---

### EzVerifyActionResult

Verify Action execution result

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| action | string (enum)<br>enum {<br>}<br> |  | ✓ |  |  | Type of Verify Action |
| verifyRequest | string |  | ✓ |  |  ~ 524288 chars | JSON string of the request used when executing the action |
| statusCode | int |  |  |  | 0 ~ 999 | Status code |
| verifyResult | string |  |  |  |  ~ 1048576 chars | Result content |


**Related models:**
EzTransactionResult - Transaction Execution Result



---

### EzConsumeActionResult

Consume Action execution result

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| action | string (enum)<br>enum {<br>}<br> |  | ✓ |  |  | Type of Consume Action |
| consumeRequest | string |  | ✓ |  |  ~ 524288 chars | JSON string of the request used when executing the action |
| statusCode | int |  |  |  | 0 ~ 999 | Status code |
| consumeResult | string |  |  |  |  ~ 1048576 chars | Result content |


**Related models:**
EzTransactionResult - Transaction Execution Result



---

### EzAcquireActionResult

Acquire Action execution result

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| action | string (enum)<br>enum {<br>}<br> |  | ✓ |  |  | Type of Acquire Action |
| acquireRequest | string |  | ✓ |  |  ~ 524288 chars | JSON string of the request used when executing the action |
| statusCode | int |  |  |  | 0 ~ 999 | Status code |
| acquireResult | string |  |  |  |  ~ 1048576 chars | Result content |


**Related models:**
EzTransactionResult - Transaction Execution Result



---

### EzTransactionResult

Transaction Execution Result

Result of a transaction executed using the server-side automatic execution feature

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| transactionId | string |  | ✓ |  | 36 ~ 36 chars | Transaction ID |
| verifyResults | [List&lt;EzVerifyActionResult&gt;](#ezverifyactionresult) |  |  |  | 0 ~ 10 items | List of verify action execution results |
| consumeResults | [List&lt;EzConsumeActionResult&gt;](#ezconsumeactionresult) |  |  | [] | 0 ~ 10 items | List of Consume Action execution results |
| acquireResults | [List&lt;EzAcquireActionResult&gt;](#ezacquireactionresult) |  |  | [] | 0 ~ 100 items | List of Acquire Action execution results |

**Related methods:**
acquire - Claim the reward from a completed time-delayed exchange
exchange - Perform an exchange
incrementalExchange - Perform an incremental cost exchange


---

## Methods

### acquire

Claim the reward from a completed time-delayed exchange

Claims the reward from a time-delayed exchange after the required wait time has passed.
If the wait time hasn't elapsed yet, this call will fail — check the remaining time first using GetAwait.
Once claimed, the await record is consumed and the player receives the reward defined in the rate model.
For example, after waiting 3 hours for an "Iron Sword" to be crafted, calling this gives the player the sword.

#### Request

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128 chars | Namespace name<br>Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| gameSession | GameSession | | ✓|  |  | GameSession |
| awaitName | string |  | ✓| UUID |  ~ 36 chars | Exchange Await name<br>Maintains a unique name for each Exchange Await.<br>The name is automatically generated in UUID (Universally Unique Identifier) format and used to identify each Exchange Await. |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzAwait](#ezawait) | Exchange Await|
| transactionId | string | Issued transaction ID|
| stampSheet | string | Stamp sheet used to execute the reward acquisition process|
| stampSheetEncryptionKeyId | string | Cryptographic key GRN used for stamp sheet signature calculations|
| autoRunStampSheet | bool | Whether automatic transaction execution is enabled|
| atomicCommit | bool | Whether to commit the transaction atomically|
| transaction | string | Issued transaction|
| transactionResult | [EzTransactionResult](#eztransactionresult) | Transaction Execution Result|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Await(
        awaitName: "await-0001"
    );
    var result = await domain.AcquireAsync(
    );
    // In New Experience, stamp sheets are automatically executed at the SDK level.
    // If an error occurs, a TransactionException is thrown.
    // You can retry with TransactionException::Retry().

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Await(
        awaitName: "await-0001"
    );
    var future = domain.AcquireFuture(
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    // In New Experience, stamp sheets are automatically executed at the SDK level.
    // If an error occurs, a TransactionException is thrown.
    // You can retry with TransactionException::Retry().

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Await(
        "await-0001" // awaitName
    );
    const auto Future = Domain->Acquire(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```


---

### deleteAwait

Cancel a pending time-delayed exchange

Deletes a pending exchange await record, effectively canceling the exchange.
The reward will NOT be granted, and any resources already paid at the start of the exchange are NOT refunded.
Use this when the player wants to cancel a pending craft or building order — make sure to show a confirmation dialog since the cost is not returned.

#### Request

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128 chars | Namespace name<br>Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| gameSession | GameSession | | ✓|  |  | GameSession |
| awaitName | string |  | ✓| UUID |  ~ 36 chars | Exchange Await name<br>Maintains a unique name for each Exchange Await.<br>The name is automatically generated in UUID (Universally Unique Identifier) format and used to identify each Exchange Await. |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzAwait](#ezawait) | Exchange Await|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Await(
        awaitName: "await-0001"
    );
    var result = await domain.DeleteAwaitAsync(
    );

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Await(
        awaitName: "await-0001"
    );
    var future = domain.DeleteAwaitFuture(
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Await(
        "await-0001" // awaitName
    );
    const auto Future = Domain->DeleteAwait(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
    const auto Result = Future->GetTask().Result();

```


---

### getAwait

Get a specific pending time-delayed exchange

Retrieves the details of a specific exchange await record.
The returned information includes the exchange type, how many were requested, when it was started, and how much wait time remains.
Use this to show a detail screen for a specific pending exchange — for example, "Crafting Iron Sword... 2h 30m remaining".

#### Request

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128 chars | Namespace name<br>Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| gameSession | GameSession | | ✓|  |  | GameSession |
| awaitName | string |  | ✓| UUID |  ~ 36 chars | Exchange Await name<br>Maintains a unique name for each Exchange Await.<br>The name is automatically generated in UUID (Universally Unique Identifier) format and used to identify each Exchange Await. |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzAwait](#ezawait) | Exchange Await|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Await(
        awaitName: "await-0001"
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Await(
        awaitName: "await-0001"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Await(
        "await-0001" // awaitName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```


##### Value change event handling




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Await(
        awaitName: "await-0001"
    );
    
    // Start event handling
    var callbackId = domain.Subscribe(
        value => {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Await(
        awaitName: "await-0001"
    );
    
    // Start event handling
    var callbackId = domain.Subscribe(
        value => {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Await(
        "await-0001" // awaitName
    );
    
    // Start event handling
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Exchange::Model::FAwait> value) {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    Domain->Unsubscribe(CallbackId);

```


{{% alert title="Warning" color="warning" %}}This event is triggered when the value stored in the SDK's local cache changes.

The local cache is updated only when executing the SDK's API, or by executing stamp sheets via GS2-Distributor with GS2-Gateway notification enabled, or by executing jobs via GS2-JobQueue with GS2-Gateway notification enabled.

Therefore, callbacks will not be invoked if the value is changed in any other way.
{{% /alert %}}

---

### listAwaits

List pending time-delayed exchanges

Retrieves the player's exchange await records — these are exchanges that require waiting before the reward can be claimed (like crafting or building).
You can filter by rate name to show only awaits for a specific exchange type.
Use this to build a "pending crafts" or "in-progress" list that shows the player what they're waiting for and how much time is left.

#### Request

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128 chars | Namespace name<br>Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| rateName | string |  | |  |  ~ 128 chars | Exchange Rate Model name<br>Unique Exchange Rate Model name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| gameSession | GameSession | | ✓|  |  | GameSession |
| pageToken | string |  | |  |  ~ 1024 chars | Token specifying the position from which to start acquiring data |

#### Result

|  | Type | Description |
| --- | --- | --- |
| items | [List&lt;EzAwait&gt;](#ezawait) | List of Exchange Awaits|
| nextPageToken | string | Page token to retrieve the rest of the listing|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var items = await domain.AwaitsAsync(
        rateName: "material_n_to_r"
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var it = domain.Awaits(
        rateName: "material_n_to_r"
    );
    List<EzAwait> items = new List<EzAwait>();
    while (it.HasNext())
    {
        yield return it.Next();
        if (it.Error != null)
        {
            onError.Invoke(it.Error, null);
            break;
        }
        if (it.Current != null)
        {
            items.Add(it.Current);
        }
        else
        {
            break;
        }
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    const auto It = Domain->Awaits(
        "material_n_to_r" // rateName
    );
    TArray<Gs2::UE5::Exchange::Model::FEzAwaitPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


##### Value change event handling




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // Start event handling
    var callbackId = domain.SubscribeAwaits(
        () => {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    domain.UnsubscribeAwaits(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // Start event handling
    var callbackId = domain.SubscribeAwaits(
        () => {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    domain.UnsubscribeAwaits(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    
    // Start event handling
    const auto CallbackId = Domain->SubscribeAwaits(
        []() {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    Domain->UnsubscribeAwaits(CallbackId);

```


{{% alert title="Warning" color="warning" %}}This event is triggered when the value stored in the SDK's local cache changes.

The local cache is updated only when executing the SDK's API, or by executing stamp sheets via GS2-Distributor with GS2-Gateway notification enabled, or by executing jobs via GS2-JobQueue with GS2-Gateway notification enabled.

Therefore, callbacks will not be invoked if the value is changed in any other way.
{{% /alert %}}

---

### getRateModel

Get an exchange rate model by name

Retrieves a single exchange rate model by specifying its name.
The returned information includes what the player needs to pay, what they receive, and whether it's an instant exchange or requires waiting.
Use this to display the details of a specific exchange — for example, showing "Cost: 100 Gold -> Reward: 1 Healing Potion" on a shop item detail screen.

#### Request

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128 chars | Namespace name<br>Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| rateName | string |  | ✓|  |  ~ 128 chars | Exchange Rate Model name<br>Unique Exchange Rate Model name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzRateModel](#ezratemodel) | Exchange Rate Model|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).RateModel(
        rateName: "character-level"
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).RateModel(
        rateName: "character-level"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->RateModel(
        "character-level" // rateName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```


##### Value change event handling




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).RateModel(
        rateName: "character-level"
    );
    
    // Start event handling
    var callbackId = domain.Subscribe(
        value => {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).RateModel(
        rateName: "character-level"
    );
    
    // Start event handling
    var callbackId = domain.Subscribe(
        value => {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->RateModel(
        "character-level" // rateName
    );
    
    // Start event handling
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Exchange::Model::FRateModel> value) {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    Domain->Unsubscribe(CallbackId);

```


{{% alert title="Warning" color="warning" %}}This event is triggered when the value stored in the SDK's local cache changes.

The local cache is updated only when executing the SDK's API, or by executing stamp sheets via GS2-Distributor with GS2-Gateway notification enabled, or by executing jobs via GS2-JobQueue with GS2-Gateway notification enabled.

Therefore, callbacks will not be invoked if the value is changed in any other way.
{{% /alert %}}

---

### listRateModels

List exchange rate models

Retrieves all exchange rate models registered in this Namespace.
A rate model defines an exchange recipe — what resources the player pays (e.g., 100 gold coins) and what they receive in return (e.g., 1 healing potion).
There are two timing types: "immediate" exchanges happen instantly, while "await" exchanges require the player to wait a certain amount of time before claiming the reward (like crafting).
Use this to build a shop or crafting UI that shows all available exchange options to the player.

#### Request

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128 chars | Namespace name<br>Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |

#### Result

|  | Type | Description |
| --- | --- | --- |
| items | [List&lt;EzRateModel&gt;](#ezratemodel) | List of Exchange Rate Models|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    );
    var items = await domain.RateModelsAsync(
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    );
    var it = domain.RateModels(
    );
    List<EzRateModel> items = new List<EzRateModel>();
    while (it.HasNext())
    {
        yield return it.Next();
        if (it.Error != null)
        {
            onError.Invoke(it.Error, null);
            break;
        }
        if (it.Current != null)
        {
            items.Add(it.Current);
        }
        else
        {
            break;
        }
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    );
    const auto It = Domain->RateModels(
    );
    TArray<Gs2::UE5::Exchange::Model::FEzRateModelPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


##### Value change event handling




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // Start event handling
    var callbackId = domain.SubscribeRateModels(
        () => {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    domain.UnsubscribeRateModels(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // Start event handling
    var callbackId = domain.SubscribeRateModels(
        () => {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    domain.UnsubscribeRateModels(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    );
    
    // Start event handling
    const auto CallbackId = Domain->SubscribeRateModels(
        []() {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    Domain->UnsubscribeRateModels(CallbackId);

```


{{% alert title="Warning" color="warning" %}}This event is triggered when the value stored in the SDK's local cache changes.

The local cache is updated only when executing the SDK's API, or by executing stamp sheets via GS2-Distributor with GS2-Gateway notification enabled, or by executing jobs via GS2-JobQueue with GS2-Gateway notification enabled.

Therefore, callbacks will not be invoked if the value is changed in any other way.
{{% /alert %}}

---

### getIncrementalRateModel

Get an incremental cost exchange rate model by name

Retrieves a single incremental cost exchange rate model by specifying its name.
The returned information includes the cost calculation method (linear formula or custom script), the base cost, the cost increase per exchange, the maximum number of exchanges allowed, and what the player receives.
Use this to display the details of a specific incremental exchange — for example, showing "Stamina Refill: 30 gems (3rd purchase today, max 5)" on a shop screen.

#### Request

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128 chars | Namespace name<br>Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| rateName | string |  | ✓|  |  ~ 128 chars | Incremental Cost Exchange Rate Model name<br>Unique Incremental Cost Exchange Rate Model name. Specified using alphanumeric characters, hyphen (-), underscore (_), and period (.). |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzIncrementalRateModel](#ezincrementalratemodel) | Incremental Cost Exchange Rate Model|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).IncrementalRateModel(
        rateName: "character-level"
    );
    var item = await domain.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).IncrementalRateModel(
        rateName: "character-level"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->IncrementalRateModel(
        "character-level" // rateName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```


##### Value change event handling




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).IncrementalRateModel(
        rateName: "character-level"
    );
    
    // Start event handling
    var callbackId = domain.Subscribe(
        value => {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    domain.Unsubscribe(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).IncrementalRateModel(
        rateName: "character-level"
    );
    
    // Start event handling
    var callbackId = domain.Subscribe(
        value => {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    domain.Unsubscribe(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->IncrementalRateModel(
        "character-level" // rateName
    );
    
    // Start event handling
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Exchange::Model::FIncrementalRateModel> value) {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    Domain->Unsubscribe(CallbackId);

```


{{% alert title="Warning" color="warning" %}}This event is triggered when the value stored in the SDK's local cache changes.

The local cache is updated only when executing the SDK's API, or by executing stamp sheets via GS2-Distributor with GS2-Gateway notification enabled, or by executing jobs via GS2-JobQueue with GS2-Gateway notification enabled.

Therefore, callbacks will not be invoked if the value is changed in any other way.
{{% /alert %}}

---

### listIncrementalRateModels

List Incremental Cost Exchange Rate Models

Retrieves all incremental cost exchange rate models registered in this Namespace.
An incremental cost model defines an exchange where the price goes up each time the player uses it — for example, the first stamina refill costs 10 gems, the second costs 20 gems, the third costs 30 gems, and so on.
The cost increase can be calculated using a simple linear formula (base + coefficient * count) or a custom script.
Use this to build a UI that shows all available incremental exchanges and their current costs.

#### Request

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128 chars | Namespace name<br>Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |

#### Result

|  | Type | Description |
| --- | --- | --- |
| items | [List&lt;EzIncrementalRateModel&gt;](#ezincrementalratemodel) | List of Incremental Cost Exchange Rate Models|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    );
    var items = await domain.IncrementalRateModelsAsync(
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    );
    var it = domain.IncrementalRateModels(
    );
    List<EzIncrementalRateModel> items = new List<EzIncrementalRateModel>();
    while (it.HasNext())
    {
        yield return it.Next();
        if (it.Error != null)
        {
            onError.Invoke(it.Error, null);
            break;
        }
        if (it.Current != null)
        {
            items.Add(it.Current);
        }
        else
        {
            break;
        }
    }

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    );
    const auto It = Domain->IncrementalRateModels(
    );
    TArray<Gs2::UE5::Exchange::Model::FEzIncrementalRateModelPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


##### Value change event handling




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // Start event handling
    var callbackId = domain.SubscribeIncrementalRateModels(
        () => {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    domain.UnsubscribeIncrementalRateModels(callbackId);

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // Start event handling
    var callbackId = domain.SubscribeIncrementalRateModels(
        () => {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    domain.UnsubscribeIncrementalRateModels(callbackId);

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    );
    
    // Start event handling
    const auto CallbackId = Domain->SubscribeIncrementalRateModels(
        []() {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    Domain->UnsubscribeIncrementalRateModels(CallbackId);

```


{{% alert title="Warning" color="warning" %}}This event is triggered when the value stored in the SDK's local cache changes.

The local cache is updated only when executing the SDK's API, or by executing stamp sheets via GS2-Distributor with GS2-Gateway notification enabled, or by executing jobs via GS2-JobQueue with GS2-Gateway notification enabled.

Therefore, callbacks will not be invoked if the value is changed in any other way.
{{% /alert %}}

---

### exchange

Perform an exchange

Exchanges resources based on the specified rate model.
The player pays the cost defined in the rate model and receives the reward — for example, trading 100 gold coins for 1 healing potion.
You can specify a count to perform the same exchange multiple times at once (e.g., buy 5 potions for 500 gold).
If the rate model uses "await" timing, this starts a time-delayed exchange instead of completing immediately (see the Await APIs for claiming the reward later).

#### Request

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128 chars | Namespace name<br>Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| rateName | string |  | ✓|  |  ~ 128 chars | Exchange Rate Model name<br>Unique Exchange Rate Model name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| gameSession | GameSession | | ✓|  |  | GameSession |
| count | int |  | ✓|  | 1 ~ 1073741821 | Number of exchanges |
| config | [List&lt;EzConfig&gt;](#ezconfig) |  | | [] | 0 ~ 32 items | Configuration values applied to transaction variables |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzRateModel](#ezratemodel) | Exchange Rate Model|
| transactionId | string | Issued transaction ID|
| stampSheet | string | Stamp sheet used to execute the exchange process|
| stampSheetEncryptionKeyId | string | Cryptographic key GRN used for stamp sheet signature calculations|
| autoRunStampSheet | bool | Whether automatic transaction execution is enabled|
| atomicCommit | bool | Whether to commit the transaction atomically|
| transaction | string | Issued transaction|
| transactionResult | [EzTransactionResult](#eztransactionresult) | Transaction Execution Result|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Exchange(
    );
    var result = await domain.ExchangeAsync(
        rateName: "rate-0001",
        count: 1,
        config: null
    );
    // In New Experience, stamp sheets are automatically executed at the SDK level.
    // If an error occurs, a TransactionException is thrown.
    // You can retry with TransactionException::Retry().

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Exchange(
    );
    var future = domain.ExchangeFuture(
        rateName: "rate-0001",
        count: 1,
        config: null
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    // In New Experience, stamp sheets are automatically executed at the SDK level.
    // If an error occurs, a TransactionException is thrown.
    // You can retry with TransactionException::Retry().

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Exchange(
    );
    const auto Future = Domain->Exchange(
        "rate-0001", // rateName
        1 // count
        // config
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```


---

### incrementalExchange

Perform an incremental cost exchange

Exchanges resources using a rate model where the cost goes up each time.
The cost is automatically calculated based on how many times the player has already used this exchange — for example, the first stamina refill costs 10 gems, the second costs 20 gems, and so on.
You can specify a count to perform multiple exchanges at once; the total cost will be the sum of each step's price.
Use this for mechanics like daily stamina refills, limited shop purchases, or anything where you want the price to escalate with repeated use.

#### Request

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| namespaceName | string |  | ✓|  |  ~ 128 chars | Namespace name<br>Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). |
| rateName | string |  | ✓|  |  ~ 128 chars | Incremental Cost Exchange Rate Model name<br>Unique Incremental Cost Exchange Rate Model name. Specified using alphanumeric characters, hyphen (-), underscore (_), and period (.). |
| gameSession | GameSession | | ✓|  |  | GameSession |
| count | int |  | ✓|  | 1 ~ 1073741821 | Number of exchanges |
| config | [List&lt;EzConfig&gt;](#ezconfig) |  | | [] | 0 ~ 32 items | Configuration values applied to transaction variables |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzIncrementalRateModel](#ezincrementalratemodel) | Incremental Cost Exchange Rate Model|
| transactionId | string | Issued transaction ID|
| stampSheet | string | Stamp sheet used to execute the exchange process|
| stampSheetEncryptionKeyId | string | Cryptographic key GRN used for stamp sheet signature calculations|
| autoRunStampSheet | bool | Whether automatic transaction execution is enabled|
| atomicCommit | bool | Whether to commit the transaction atomically|
| transaction | string | Issued transaction|
| transactionResult | [EzTransactionResult](#eztransactionresult) | Transaction Execution Result|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Exchange(
    );
    var result = await domain.IncrementalExchangeAsync(
        rateName: "rate-0001",
        count: 1,
        config: null
    );
    // In New Experience, stamp sheets are automatically executed at the SDK level.
    // If an error occurs, a TransactionException is thrown.
    // You can retry with TransactionException::Retry().

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Exchange(
    );
    var future = domain.IncrementalExchangeFuture(
        rateName: "rate-0001",
        count: 1,
        config: null
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    // In New Experience, stamp sheets are automatically executed at the SDK level.
    // If an error occurs, a TransactionException is thrown.
    // You can retry with TransactionException::Retry().

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Exchange(
    );
    const auto Future = Domain->IncrementalExchange(
        "rate-0001", // rateName
        1 // count
        // config
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

```


---



