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

# GS2-Datastore SDK for Game Engine API Reference

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



## Models

### EzDataObject

Data Object

Data objects are data uploaded by game players.
Data is generation managed, with 30 days of historical data stored.

Access permissions can be set for the data.
There are three types of scopes:
- `public`: Accessible to anyone
- `protected`: Accessible only to game players with specified user IDs
- `private`: Accessible only to yourself

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| dataObjectId | string |  | * |  |  ~ 1024 chars | Data object GRN<br>* Set automatically by the server |
| name | string |  | ✓ | UUID |  ~ 128 chars | Data Object Name<br>A unique name identifying the data object. Automatically generated in UUID format by default. Used to reference and manage the uploaded data within the Namespace. |
| userId | string |  | ✓ |  |  ~ 128 chars | User ID |
| scope | string (enum)<br>enum {<br>&nbsp;&nbsp;"public",<br>&nbsp;&nbsp;"protected",<br>&nbsp;&nbsp;"private"<br>}<br> |  |  | "private" |  | File access permission<br>Controls who can access this data object. `public` allows anyone to access, `protected` restricts access to specified user IDs listed in allowUserIds, and `private` limits access to the owner only."public": Public / "protected": Only to specified users / "private": Private /  |
| allowUserIds | List&lt;string&gt; | {scope} == "protected" |  | [] | 0 ~ 100 items | List of user IDs to be published<br>Specifies which users can access this data object when the scope is set to `protected`. Only users whose IDs are included in this list will be granted read access.<br><br>* Enabled only if scope is "protected" |
| status | string (enum)<br>enum {<br>&nbsp;&nbsp;"ACTIVE",<br>&nbsp;&nbsp;"UPLOADING",<br>&nbsp;&nbsp;"DELETED"<br>}<br> |  | ✓ |  |  | Status<br>The current lifecycle state of the data object. `ACTIVE` indicates the data is available for access, `UPLOADING` indicates a new version is being uploaded, and `DELETED` indicates the object has been marked for deletion (actual removal occurs 30 days later)."ACTIVE": Active / "UPLOADING": Uploading / "DELETED": Deleted (Actual deletion 30 days after the deletion process) /  |
| generation | string |  |  |  |  ~ 128 chars | Data Generation<br>An identifier representing the current version of the uploaded data. Each time data is re-uploaded, a new generation ID is assigned. |
| createdAt | long |  | * | Current time |  | Creation Timestamp<br>Unix time, milliseconds<br>* Set automatically by the server |
| updatedAt | long |  | * | Current time |  | Last Updated Timestamp<br>Unix time, milliseconds<br>* Set automatically by the server |

**Related methods:**
deleteDataObject - Delete uploaded file
doneUpload - Finalize file upload
listMyDataObjects - List player's uploaded data
prepareDownload - Get download URL for file (by Data Object ID)
prepareDownloadByUserIdAndDataObjectName - Get download URL for another player's file (by user ID and name)
prepareDownloadOwnData - Get download URL for the player's own file (by name)
prepareReUpload - Prepare to re-upload (overwrite) existing file
prepareUpload - Prepare to upload new file
restoreDataObject - Repair Data Object's management information
updateDataObject - Update access settings of Data Object


---

### EzDataObjectHistory

Data Object History

You can check the update history of Data Objects.
Each time a data object is re-uploaded, a history record is created containing the generation ID and file size. Historical data is retained for 30 days, allowing rollback and audit of previous versions.

|  | Type | Condition | Required | Default | Value Limits | Description |
| --- | --- | --- | --- | --- | --- | --- |
| dataObjectHistoryId | string |  | * |  |  ~ 1024 chars | Data Object History GRN<br>* Set automatically by the server |
| generation | string |  | ✓ |  |  ~ 128 chars | Generation ID<br>A unique identifier for the specific version of the data object at the time of upload. Corresponds to the generation field in the DataObject and can be used with PrepareDownloadByGeneration to download this specific version. |
| contentLength | long |  | ✓ |  | 0 ~ 10485760 | File size<br>The size of the uploaded data in bytes for this generation. Maximum file size is 10 MB (10,485,760 bytes). |
| createdAt | long |  | * | Current time |  | Creation Timestamp<br>Unix time, milliseconds<br>* Set automatically by the server |

**Related methods:**
listDataObjectHistories - Get the version history of a data object


---

## Methods

### deleteDataObject

Delete uploaded file

Marks the specified data object for deletion. The actual file is removed after 30 days.
Use this when the player wants to delete save data or other uploaded content they no longer need.

#### 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 |
| dataObjectName | string |  | ✓| UUID |  ~ 128 chars | Data Object Name<br>A unique name identifying the data object. Automatically generated in UUID format by default. Used to reference and manage the uploaded data within the Namespace. |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzDataObject](#ezdataobject) | Data object|

#### Error

Special exceptions are defined in this API.
GS2-SDK for Game Engine provides specialized exceptions derived from general exceptions to facilitate handling of errors that may need to be handled in games.
Please refer to the documentation [here]() for more information on common error types and handling methods.

| Type | Base Type | Description |
| --- | --- | --- |
| InvalidStatusException | BadRequestException | DataObject is not in operable state. |

#### Implementation Example




**Unity (UniTask)**
```csharp

try {
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var result = await domain.DeleteDataObjectAsync(
    );
    var item = await result.ModelAsync();
} catch(Gs2.Gs2Datastore.Exception.InvalidStatusException e) {
    // DataObject is not in operable state.
}

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var future = domain.DeleteDataObjectFuture(
    );
    yield return future;
    if (future.Error != null)
    {
        if (future.Error is Gs2.Gs2Datastore.Exception.InvalidStatusException)
        {
            // DataObject is not in operable state.
        }
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.ModelFuture();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->DataObject(
        "dataObject-0001" // dataObjectName
    );
    const auto Future = Domain->DeleteDataObject(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        auto e = Future->GetTask().Error();
        if (e->IsChildOf(Gs2::Datastore::Error::FInvalidStatusError::Class))
        {
            // DataObject is not in operable state.
        }
        return false;
    }

    // obtain changed values / result values
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();

```


---

### doneUpload

Finalize file upload

Call this after you have finished uploading the file to the URL returned by PrepareUpload or PrepareReUpload.
This confirms the upload and makes the data object available for download (status changes to `ACTIVE`).
If you skip this step, the data object remains in `UPLOADING` status and cannot be downloaded.

#### 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 |
| dataObjectName | string |  | ✓| UUID |  ~ 128 chars | Data Object Name<br>A unique name identifying the data object. Automatically generated in UUID format by default. Used to reference and manage the uploaded data within the Namespace. |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzDataObject](#ezdataobject) | Data object|

#### Error

Special exceptions are defined in this API.
GS2-SDK for Game Engine provides specialized exceptions derived from general exceptions to facilitate handling of errors that may need to be handled in games.
Please refer to the documentation [here]() for more information on common error types and handling methods.

| Type | Base Type | Description |
| --- | --- | --- |
| InvalidStatusException | BadRequestException | DataObject is not in operable state. |
| NotUploadedException | BadRequestException | DataObject is not uploaded. |

#### Implementation Example




**Unity (UniTask)**
```csharp

try {
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var result = await domain.DoneUploadAsync(
    );
    var item = await result.ModelAsync();
} catch(Gs2.Gs2Datastore.Exception.InvalidStatusException e) {
    // DataObject is not in operable state.
} catch(Gs2.Gs2Datastore.Exception.NotUploadedException e) {
    // DataObject is not uploaded.
}

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var future = domain.DoneUploadFuture(
    );
    yield return future;
    if (future.Error != null)
    {
        if (future.Error is Gs2.Gs2Datastore.Exception.InvalidStatusException)
        {
            // DataObject is not in operable state.
        }
        if (future.Error is Gs2.Gs2Datastore.Exception.NotUploadedException)
        {
            // DataObject is not uploaded.
        }
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.ModelFuture();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->DataObject(
        "dataObject-0001" // dataObjectName
    );
    const auto Future = Domain->DoneUpload(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        auto e = Future->GetTask().Error();
        if (e->IsChildOf(Gs2::Datastore::Error::FInvalidStatusError::Class))
        {
            // DataObject is not in operable state.
        }
        if (e->IsChildOf(Gs2::Datastore::Error::FNotUploadedError::Class))
        {
            // DataObject is not uploaded.
        }
        return false;
    }

    // obtain changed values / result values
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();

```


---

### listMyDataObjects

List player's uploaded data

Retrieves a list of data objects (files) that the player has uploaded.
You can filter by status: `ACTIVE` (available for download), `UPLOADING` (upload in progress), or `DELETED` (scheduled for deletion).
Use this to show a save-data list screen or to check what files the player currently has stored.

#### 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 |
| status | string (enum)<br>enum {<br>&nbsp;&nbsp;"ACTIVE",<br>&nbsp;&nbsp;"UPLOADING",<br>&nbsp;&nbsp;"DELETED"<br>}<br> |  | |  |  | Status"ACTIVE": Active / "UPLOADING": Uploading / "DELETED": Deleted(Actual deletion 30 days after the deletion process) /  |
| pageToken | string |  | |  |  ~ 1024 chars | Token specifying the position from which to start acquiring data |
| limit | int |  | | 30 | 1 ~ 1000 | Number of data items to retrieve |

#### Result

|  | Type | Description |
| --- | --- | --- |
| items | [List&lt;EzDataObject&gt;](#ezdataobject) | List of Data object|
| nextPageToken | string | Page token to retrieve the rest of the listing|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var items = await domain.DataObjectsAsync(
        status: "ACTIVE"
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var it = domain.DataObjects(
        status: "ACTIVE"
    );
    List<EzDataObject> items = new List<EzDataObject>();
    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->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    const auto It = Domain->DataObjects(
        "ACTIVE" // status
    );
    TArray<Gs2::UE5::Datastore::Model::FEzDataObjectPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


##### Value change event handling




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

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

```

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

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

```

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

    // Stop event handling
    Domain->UnsubscribeDataObjects(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 %}}

---

### prepareDownload

Get download URL for file (by Data Object ID)

Returns a temporary download URL for the specified data object.
The data object is identified by its ID (GRN). Access control is applied — only the file owner or users in the allow-list can download.
Use the returned URL to download the file with an HTTP GET request.

#### 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 (.). |
| dataObjectId | string |  | ✓|  |  ~ 1024 chars | Data object GRN |
| gameSession | GameSession | | ✓|  |  | GameSession |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzDataObject](#ezdataobject) | Data object|
| fileUrl | string | URL to download the file|
| contentLength | long | File size|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var result = await domain.PrepareDownloadAsync(
        dataObjectId: "grn:gs2:ap-northeast-1:YourOwnerId:datastore:namespace-0001:user:user-0001:data:dataObject-0001"
    );
    var item = await result.ModelAsync();
    var fileUrl = result.FileUrl;
    var contentLength = result.ContentLength;

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var future = domain.PrepareDownloadFuture(
        dataObjectId: "grn:gs2:ap-northeast-1:YourOwnerId:datastore:namespace-0001:user:user-0001:data:dataObject-0001"
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.ModelFuture();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;
    var fileUrl = future.Result.FileUrl;
    var contentLength = future.Result.ContentLength;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    const auto Future = Domain->PrepareDownload(
        "grn:gs2:ap-northeast-1:YourOwnerId:datastore:namespace-0001:user:user-0001:data:dataObject-0001" // dataObjectId
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

    // obtain changed values / result values
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();
    const auto FileUrl = Result->FileUrl;
    const auto ContentLength = Result->ContentLength;

```


---

### prepareDownloadByUserIdAndDataObjectName

Get download URL for another player's file (by user ID and name)

Downloads another player's data by specifying their user ID and the data object name.
Access control is applied — the data must be `public`, or the requesting player must be in the owner's allow-list.
Use this when players share data with each other, such as custom levels or replays.

#### 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 (.). |
| userId | string |  | ✓|  |  ~ 128 chars | User ID |
| dataObjectName | string |  | ✓| UUID |  ~ 128 chars | Data Object Name<br>A unique name identifying the data object. Automatically generated in UUID format by default. Used to reference and manage the uploaded data within the Namespace. |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzDataObject](#ezdataobject) | Data object|
| fileUrl | string | URL to download the file|
| contentLength | long | File size|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var result = await domain.PrepareDownloadByUserIdAndDataObjectNameAsync(
    );
    var item = await result.ModelAsync();
    var fileUrl = result.FileUrl;
    var contentLength = result.ContentLength;

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var future = domain.PrepareDownloadByUserIdAndDataObjectNameFuture(
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.ModelFuture();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;
    var fileUrl = future.Result.FileUrl;
    var contentLength = future.Result.ContentLength;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->User(
        "user-0001" // userId
    )->DataObject(
        "dataObject-0001" // dataObjectName
    );
    const auto Future = Domain->PrepareDownloadByUserIdAndDataObjectName(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

    // obtain changed values / result values
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();
    const auto FileUrl = Result->FileUrl;
    const auto ContentLength = Result->ContentLength;

```


---

### prepareDownloadOwnData

Get download URL for the player's own file (by name)

A convenient way to download the player's own data by specifying the data object name instead of its ID.
Use this when the player wants to load their own save data or uploaded content.
Returns a temporary download URL and the file size.

#### 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 (.). |
| dataObjectName | string |  | ✓| UUID |  ~ 128 chars | Data Object Name<br>A unique name identifying the data object. Automatically generated in UUID format by default. Used to reference and manage the uploaded data within the Namespace. |
| gameSession | GameSession | | ✓|  |  | GameSession |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzDataObject](#ezdataobject) | Data object|
| fileUrl | string | URL to download the file|
| contentLength | long | File size|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var result = await domain.PrepareDownloadOwnDataAsync(
    );
    var item = await result.ModelAsync();
    var fileUrl = result.FileUrl;
    var contentLength = result.ContentLength;

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var future = domain.PrepareDownloadOwnDataFuture(
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.ModelFuture();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;
    var fileUrl = future.Result.FileUrl;
    var contentLength = future.Result.ContentLength;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->DataObject(
        "dataObject-0001" // dataObjectName
    );
    const auto Future = Domain->PrepareDownloadOwnData(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

    // obtain changed values / result values
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();
    const auto FileUrl = Result->FileUrl;
    const auto ContentLength = Result->ContentLength;

```


---


### prepareReUpload

Prepare to re-upload (overwrite) existing file

Returns a new upload URL for replacing the content of an existing data object.
The previous version of the file is kept in the history, so you can still download older versions by generation number.
After uploading the new file to the returned URL, call DoneUpload to finalize it.

**Re-upload flow:** PrepareReUpload → PUT file to returned URL → DoneUpload

#### 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 |
| dataObjectName | string |  | ✓| UUID |  ~ 128 chars | Data Object Name<br>A unique name identifying the data object. Automatically generated in UUID format by default. Used to reference and manage the uploaded data within the Namespace. |
| contentType | string |  | | "application/octet-stream" |  ~ 256 chars | MIME-Type of the data to be uploaded |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzDataObject](#ezdataobject) | Data object|
| uploadUrl | string | URL used to execute the upload process|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var result = await domain.PrepareReUploadAsync(
        contentType: "application/octet-stream"
    );
    var item = await result.ModelAsync();
    var uploadUrl = result.UploadUrl;

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var future = domain.PrepareReUploadFuture(
        contentType: "application/octet-stream"
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.ModelFuture();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;
    var uploadUrl = future.Result.UploadUrl;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->DataObject(
        "dataObject-0001" // dataObjectName
    );
    const auto Future = Domain->PrepareReUpload(
        "application/octet-stream" // contentType
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

    // obtain changed values / result values
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();
    const auto UploadUrl = Result->UploadUrl;

```


---

### prepareUpload

Prepare to upload new file

Creates a new data object and returns an upload URL.
After calling this API, upload the file to the returned URL using an HTTP PUT request, then call DoneUpload to finalize it.
You can set the access scope (`public` or `protected`) and specify which users are allowed to download the file.
If `updateIfExists` is true, uploading a file with the same name will update the existing one instead of returning an error.

**Upload flow:** PrepareUpload → PUT file to returned URL → DoneUpload

#### 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 |
| name | string |  | |  |  ~ 128 chars | Data Object name<br>If not specified, a UUID is automatically assigned. |
| scope | string (enum)<br>enum {<br>&nbsp;&nbsp;"public",<br>&nbsp;&nbsp;"protected",<br>&nbsp;&nbsp;"private"<br>}<br> |  | | "private" |  | File access permission<br>Controls who can access this data object. `public` allows anyone to access, `protected` restricts access to specified user IDs listed in allowUserIds, and `private` limits access to the owner only."public": Public / "protected": Only to specified users / "private": Private /  |
| contentType | string |  | | "application/octet-stream" |  ~ 256 chars | MIME-Type of the data to be uploaded |
| allowUserIds | List&lt;string&gt; | {scope} == "protected" | | [] | 0 ~ 100 items | List of user IDs to be published<br>Specifies which users can access this data object when the scope is set to `protected`. Only users whose IDs are included in this list will be granted read access. |
| updateIfExists | bool |  | | false |  | Whether to raise an error if data already exists or to update the data |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzDataObject](#ezdataobject) | Data Object|
| uploadUrl | string | URL used to execute the upload process|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var result = await domain.PrepareUploadAsync(
        name: "dataObject-0001",
        scope: "public",
        contentType: "application/octet-stream",
        allowUserIds: null,
        updateIfExists: null
    );
    var item = await result.ModelAsync();
    var uploadUrl = result.UploadUrl;

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var future = domain.PrepareUploadFuture(
        name: "dataObject-0001",
        scope: "public",
        contentType: "application/octet-stream",
        allowUserIds: null,
        updateIfExists: null
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.ModelFuture();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;
    var uploadUrl = future.Result.UploadUrl;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    const auto Future = Domain->PrepareUpload(
        "dataObject-0001", // name
        "public", // scope
        "application/octet-stream" // contentType
        // allowUserIds
        // updateIfExists
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

    // obtain changed values / result values
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();
    const auto UploadUrl = Result->UploadUrl;

```


---

### restoreDataObject

Repair Data Object's management information

Fixes inconsistencies between a data object's metadata and its actual file.
If the recorded file size or version number does not match the real file (e.g., due to an interrupted upload), this API corrects the metadata.
You normally do not need to call this — it is only needed for recovery when something goes wrong during an upload.

#### 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 (.). |
| dataObjectId | string |  | ✓|  |  ~ 1024 chars | Data object GRN |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzDataObject](#ezdataobject) | Data object|

#### Error

Special exceptions are defined in this API.
GS2-SDK for Game Engine provides specialized exceptions derived from general exceptions to facilitate handling of errors that may need to be handled in games.
Please refer to the documentation [here]() for more information on common error types and handling methods.

| Type | Base Type | Description |
| --- | --- | --- |
| InvalidStatusException | BadRequestException | DataObject is not in operable state. |

#### Implementation Example




**Unity (UniTask)**
```csharp

try {
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    );
    var result = await domain.RestoreDataObjectAsync(
        dataObjectId: "grn:gs2:ap-northeast-1:YourOwnerId:datastore:namespace-0001:user:user-0001:data:dataObject-0001"
    );
    var item = await result.ModelAsync();
} catch(Gs2.Gs2Datastore.Exception.InvalidStatusException e) {
    // DataObject is not in operable state.
}

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    );
    var future = domain.RestoreDataObjectFuture(
        dataObjectId: "grn:gs2:ap-northeast-1:YourOwnerId:datastore:namespace-0001:user:user-0001:data:dataObject-0001"
    );
    yield return future;
    if (future.Error != null)
    {
        if (future.Error is Gs2.Gs2Datastore.Exception.InvalidStatusException)
        {
            // DataObject is not in operable state.
        }
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.ModelFuture();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    );
    const auto Future = Domain->RestoreDataObject(
        "grn:gs2:ap-northeast-1:YourOwnerId:datastore:namespace-0001:user:user-0001:data:dataObject-0001" // dataObjectId
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        auto e = Future->GetTask().Error();
        if (e->IsChildOf(Gs2::Datastore::Error::FInvalidStatusError::Class))
        {
            // DataObject is not in operable state.
        }
        return false;
    }

    // obtain changed values / result values
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();

```


---

### updateDataObject

Update access settings of Data Object

Changes who can access an uploaded data object.
You can switch the scope between `public` (anyone can download) and `protected` (only specified users can download),
and update the list of allowed user IDs.
This does not change the file content itself — to update the file, use PrepareReUpload instead.

#### 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 |
| scope | string (enum)<br>enum {<br>&nbsp;&nbsp;"public",<br>&nbsp;&nbsp;"protected",<br>&nbsp;&nbsp;"private"<br>}<br> |  | | "private" |  | File access permission<br>Controls who can access this data object. `public` allows anyone to access, `protected` restricts access to specified user IDs listed in allowUserIds, and `private` limits access to the owner only."public": Public / "protected": Only to specified users / "private": Private /  |
| allowUserIds | List&lt;string&gt; | {scope} == "protected" | | [] | 0 ~ 100 items | List of user IDs to be published<br>Specifies which users can access this data object when the scope is set to `protected`. Only users whose IDs are included in this list will be granted read access. |

#### Result

|  | Type | Description |
| --- | --- | --- |
| item | [EzDataObject](#ezdataobject) | Data object|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var result = await domain.UpdateDataObjectAsync(
        scope: "public",
        allowUserIds: null
    );
    var item = await result.ModelAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var future = domain.UpdateDataObjectFuture(
        scope: "public",
        allowUserIds: null
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.ModelFuture();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;

```

**Unreal Engine 5**
```cpp
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->DataObject(
        "dataObject-0001" // dataObjectName
    );
    const auto Future = Domain->UpdateDataObject(
        "public" // scope
        // allowUserIds
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

    // obtain changed values / result values
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();

```


---

### listDataObjectHistories

Get the version history of a data object

Retrieves the list of past versions (generations) of a data object.
Every time you re-upload a file with PrepareReUpload, the previous version is saved in the history.
Each entry shows the file size and when it was created, so you can check what changed and when.
Use this to build a version history screen or to let the player revert to an older save.

#### 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 |
| dataObjectName | string |  | ✓| UUID |  ~ 128 chars | Data Object Name<br>A unique name identifying the data object. Automatically generated in UUID format by default. Used to reference and manage the uploaded data within the Namespace. |
| pageToken | string |  | |  |  ~ 1024 chars | Token specifying the position from which to start acquiring data |
| limit | int |  | | 30 | 1 ~ 1000 | Number of data items to retrieve |

#### Result

|  | Type | Description |
| --- | --- | --- |
| items | [List&lt;EzDataObjectHistory&gt;](#ezdataobjecthistory) | List of Data Object Histories|
| nextPageToken | string | Page token to retrieve the rest of the listing|

#### Implementation Example




**Unity (UniTask)**
```csharp
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var items = await domain.DataObjectHistoriesAsync(
    ).ToListAsync();

```

**Unity (Vanilla)**
```cs
    var domain = gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    );
    var it = domain.DataObjectHistories(
    );
    List<EzDataObjectHistory> items = new List<EzDataObjectHistory>();
    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->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->DataObject(
        "dataObject-0001" // dataObjectName
    );
    const auto It = Domain->DataObjectHistories(
    );
    TArray<Gs2::UE5::Datastore::Model::FEzDataObjectHistoryPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

```


##### Value change event handling




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

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

```

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

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

```

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

    // Stop event handling
    Domain->UnsubscribeDataObjectHistories(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 %}}

---



