---
title: "Engine instances"
url: /docs/en-us/cloud/guides/instance
last_updated: 2026-06-19T03:26:15Z
description: "Explains how to use Open Cloud APIs to access the Roblox Engine Instances."
---

# Engine instances

The Engine Open Cloud APIs let you manage `Class.Instance` objects in your Roblox experiences from the web.

## Beta restrictions

These APIs are currently in beta and have the following restrictions:

- You can only read and update `Class.Script`, `Class.LocalScript`, and `Class.ModuleScript` objects.
- You can't update scripts that are currently open in Roblox Studio.
- You can't update scripts that are part of a [package](/docs/en-us/projects/assets/packages.md).
- You can only use API key authentication. Create an [API key](/docs/en-us/cloud/auth/api-keys.md) with **universe-place-instances** added as an API system. You must specify the experiences you want the key to have access to as well as the desired read and write permission scopes.![The Creator Hub API key screen](../../assets/open-cloud/instance-api.png)
- You must have a [collaborative](/docs/en-us/projects/collaboration.md) session enabled for the experience that you want to access.
- Request bodies, such as to [Update Instance](/docs/en-us/cloud/reference/Instance.md#Cloud_UpdateInstance), are limited to 200 KB.

## List children

List all children of a specific instance by specifying an instance ID and calling the [List Instance Children](/docs/en-us/cloud/reference/Instance.md#Cloud_ListInstanceChildren) method.

> **Info:** The first time you use these methods, specify `root` for the instance ID. After you receive the list of top-level children and their IDs, you can make additional calls to find instances deeper within your place's instance hierarchy.

#### Python

```python
import requests

# Generate at https://create.roblox.com/dashboard/credentials
apiKey = "<API_KEY>"
# Find at https://create.roblox.com/dashboard/creations in the overflow menu of an experience tile
universeId = "<UNIVERSE_ID>"
# Find Start Place ID at https://create.roblox.com/dashboard/creations in the overflow menu of an experience tile
placeId = "<PLACE_ID>"
# The default ID for the root of any place's data model
instanceId = "root"

# Request header
apiKeyHeaderKey = "x-api-key"
# Endpoint URL for List Children method
listChildrenUrl = "https://apis.roblox.com/cloud/v2/universes/%s/places/%s/instances/%s:listChildren"

def ListChildren():
  url = listChildrenUrl % (universeId, placeId, instanceId)
  headerData = {apiKeyHeaderKey: apiKey}
  results = requests.get(url, headers = headerData)
  return results

response = ListChildren()
print("Operation Results:", response.status_code, response.text)

# Parse the Operation object's path to later obtain the Instance resource. See the Polling for Results section for more information.
operationPath = response.json()['path']
```

#### cURL

```bash
curl --include --location --request GET "https://apis.roblox.com/cloud/v2/universes/<universeId>/places/<placeId>/instances/<instanceId>:listChildren" --header "x-api-key: <api-key>"
```

Rather than just listing the children, the response includes an `Operation` object with a different endpoint. [Poll this endpoint](#poll-for-results) to asynchronously retrieve the actual list of children. A more complete code sample looks like this:

```python
import requests
import time

apiKey = "<API_KEY>"
universeId = "<UNIVERSE_ID>"
placeId = "<PLACE_ID>"
instanceId = "root"

apiKeyHeaderKey = "x-api-key"

listChildrenUrl = "https://apis.roblox.com/cloud/v2/universes/%s/places/%s/instances/%s:listChildren"
getOperationUrl = "https://apis.roblox.com/cloud/v2/%s"

numberOfRetries = 10
retryPollingCadence = 5

doneJSONKey = "done"

def ListChildren():
  url = listChildrenUrl % (universeId, placeId, instanceId)
  headerData = {apiKeyHeaderKey: apiKey}
  results = requests.get(url, headers = headerData)
  return results

def GetOperation(operationPath):
  url = getOperationUrl % (operationPath)
  headerData = {apiKeyHeaderKey: apiKey}
  results = requests.get(url, headers = headerData)
  return results

def PollForResults(operationPath):
  currentRetries = 0
  while (currentRetries < numberOfRetries):
    time.sleep(retryPollingCadence)
    results = GetOperation(operationPath)
    currentRetries += 1

    if (results.status_code != 200 or results.json()[doneJSONKey]):
      return results

response = ListChildren()
print("Operation Results:", response.status_code, response.text)
# Parse the Operation object's path to use in polling for the instance resource.
operationPath = response.json()['path']
response = PollForResults(operationPath)
print("Response:", response.status_code, response.text)
```

The final response might look something like this:

```json
{
  "path": "universes/1234567890/places/98765432109/instances/root/operations/a1a2a3a4-a1a2-a1a2-a1a2-a1a2a3a4a5a6",
  "done": true,
  "response": {
    "@type": "type.googleapis.com/roblox.open_cloud.cloud.v2.ListInstanceChildrenResponse",
    "instances": [
      {
        "path": "universes/1234567890/places/98765432109/instances/b1b2b3b4-b1b2-b1b2-b1b2-b1b2b3b4b5b6",
        "hasChildren": true,
        "engineInstance": {
          "Id": "b1b2b3b4-b1b2-b1b2-b1b2-b1b2b3b4b5b6",
          "Parent": "a1a2a3a4-a1a2-a1a2-a1a2-a1a2a3a4a5a6",
          "Name": "Workspace",
          "Details": {}
        }
      },

      ...

    ]
  }
}
```

You can then iterate over the JSON to find a particular instance ID:

```python
instances = response.json()['response']['instances']
replicatedStorageId = ""
for i in instances:
  if i['engineInstance']['Name'] == "ReplicatedStorage":
    replicatedStorageId = i['engineInstance']['Id']

if replicatedStorageId:
  # You now have an instance ID and can get or update it.
else:
  # The name wasn't found.
```

Scripts contain some additional information in the `Details` object, such as the script type, source, and whether they're enabled.

## Get an instance

This method returns a single [Instance](/docs/en-us/cloud/reference/Instance.md).

#### Python

```python
import requests

# Generate at https://create.roblox.com/dashboard/credentials
apiKey = "<API_KEY>"
# Find at https://create.roblox.com/dashboard/creations in the overflow menu of an experience tile
universeId = "<UNIVERSE_ID>"
# Find Start Place ID at https://create.roblox.com/dashboard/creations in the overflow menu of an experience tile
placeId = "<PLACE_ID>"
# The default ID for the root of any place's data model
instanceId = "<INSTANCE_ID>"

# Request header
apiKeyHeaderKey = "x-api-key"
# Endpoint URL for Get Instance method
getInstanceUrl = "https://apis.roblox.com/cloud/v2/universes/%s/places/%s/instances/%s"

def GetInstance():
  url = getInstanceUrl % (universeId, placeId, instanceId)
  headerData = {apiKeyHeaderKey: apiKey}
  return requests.get(url, headers = headerData)

response = GetInstance()
print("Response:", response.status_code, response.text)

# Parse the Operation object's path from response. See the Polling for Results section for more information.
operationPath = response.json()['path']
```

#### cURL

```bash
curl --include --location --request GET "https://apis.roblox.com/cloud/v2/universes/<universeId>/places/<placeId>/instances/<instanceId>" --header "x-api-key: <api-key>"
```

Just like the List Instance Children method, the response includes an `Operation` object that you poll to retrieve the actual instance. See [Poll for results](#poll-for-results) for more information.

## Update instances

After you obtain the appropriate instance ID, you can update it. [Poll for results](#poll-for-results) after making the initial update request.

#### Python

```python
import json
import requests

# Generate at https://create.roblox.com/dashboard/credentials
apiKey = "<API_KEY>"
# Find at https://create.roblox.com/dashboard/creations in the overflow menu of an experience tile
universeId = "<UNIVERSE_ID>"
# Find Start Place ID at https://create.roblox.com/dashboard/creations in the overflow menu of an experience tile
placeId = "<PLACE_ID>"
instanceId = "<INSTANCE_ID>"
instanceType = ""
propertyName = ""
propertyValue = ""

# Request header
apiKeyHeaderKey = "x-api-key"
contentTypeHeaderKey = "Content-type"
contentTypeHeaderValue = "application/json"
# Endpoint URL for Update Instance method
updateInstanceUrl = "https://apis.roblox.com/cloud/v2/universes/%s/places/%s/instances/%s"
# JSON keys
detailsJSONKey = "Details"
engineInstanceJSONKey = "engineInstance"

def GeneratePostData():
  propertiesDict = {propertyName: propertyValue}
  detailsDict = {instanceType: propertiesDict}
  instanceDict = {detailsJSONKey: detailsDict}
  outerDict = {engineInstanceJSONKey: instanceDict}
  return json.dumps(outerDict)

def UpdateInstance(postData):
    url = updateInstanceUrl % (universeId, placeId, instanceId)
    headerData = {apiKeyHeaderKey: apiKey,
    contentTypeHeaderKey: contentTypeHeaderValue}
    return requests.patch(url, headers = headerData, data = postData)

postData = GeneratePostData()
response = UpdateInstance(postData)
print("Response:", response.status_code, response.text)

# Parse the Operation object's path from response. Poll for results to perform
# the update.
operationPath = response.json()['path']
```

#### cURL

```bash
curl --include --location --request PATCH "https://apis.roblox.com/cloud/v2/universes/<universeId>/places/<placeId>/instances/<instanceId>" --header "x-api-key: <api key>" --header "Content-Type: application/json" --data '{"engineInstance": {"details": {"<instanceType>": {"<propertyName>": "<propertyValue>"}}}}'
```

> **Info:** If you receive a `TypeError` when attempting to update a script, verify that the script isn't open in Roblox Studio. If it is, close its Script Editor tab. You can also check the Studio output for additional errors, such as `Engine_OC_API: Processing Error - Live scripting session is active`.
## Poll for results

All current [Instance](/docs/en-us/cloud/reference/Instance.md) methods return an `Operation` object instead of the resource you requested. This object lets you asynchronously perform the original operation. Use the `Operation` object's path (included in the initial response) to poll for when the resource is ready.

You can use a variety of polling strategies, such as using exponential backoff or a fixed delay in between requests. The following example polls every five seconds, up to 10 times.

#### Python

```python
import requests
import time

# Generate at https://create.roblox.com/dashboard/credentials
apiKey = "<API_KEY>"
# Use the Operation path from your initial request
# Takes the form of "universes/<UNIVERSE_ID>/places/<PLACE_ID>/instances/<INSTANCE_ID>/operations/<OPERATION_ID>"
operationPath = "<OPERATION_PATH>"

# Polling constants
numberOfRetries = 10
retryPollingCadence = 5

# Request header
apiKeyHeaderKey = "x-api-key"
# Endpoint URL for long-running operation polling
getOperationUrl = "https://apis.roblox.com/cloud/v2/%s"
# JSON keys
doneJSONKey = "done"

def GetOperation(operationPath):
  url = getOperationUrl % (operationPath)
  headerData = {apiKeyHeaderKey: apiKey}
  results = requests.get(url, headers = headerData)
  return results

def PollForResults(operationPath):
  currentRetries = 0
  while (currentRetries < numberOfRetries):
    time.sleep(retryPollingCadence)
    results = GetOperation(operationPath)
    currentRetries += 1

    if (results.status_code != 200 or results.json()[doneJSONKey]):
      return results

response = PollForResults(operationPath)
print("Response:", response.status_code, response.text)
```

#### cURL

```bash
curl --include --location --request GET "https://apis.roblox.com/cloud/v2/universes/<universeId>/places/<placeId>/instances/<instanceId>/operations/<operationId>" --header "x-api-key:<api key>"
```

## Potion Shop demo

The Potion Shop Google Sheets demo shows you to update an experience's script from the web. The demo consists of the following:

- An uncopylocked place with a mock UI that displays various potions and their prices.
- A `.ods` file that you import into Google Sheets. This spreadsheet lets you specify and update values for properties within the experience.
- Code for a Google Apps Script that reads data from the Google Sheet and updates the **ReplicatedStorage > ItemList** script in the Potion Shop experience.

### Set up the demo

1. Go to the [Potion Shop Demo](https://www.roblox.com/games/14215142052/Potion-Shop-Demo) Discover page. Click on the overflow menu, and then **Edit in Studio**. Studio opens with a copy of the place.
2. Click **File** → **Save to Roblox** and fill out the necessary information to save the Potion Shop Demo as the default place for your experience. Test the experience. You should see the UI for the Potion Shop Demo. Make a note of the name, cost, and colors of the potions. You'll change them later using Open Cloud!

### Set up the sheet

1. [Download](../../assets/open-cloud/open-cloud-potion-shop-demo.ods) the Potion Shop spreadsheet file.
2. Go to [Google Sheets](https://sheets.google.com/) and click **Blank Spreadsheet**.
3. In the sheet that appears, click **File > Import**, and click the **Upload** tab.
4. Drag the Potion Shop spreadsheet file into the upload window.
5. Choose **Replace spreadsheet** and then **Import data**.
6. In the AppScript tab of the sheet, copy the code in cell A1.
7. Click the **Extensions > Apps Script** menu and paste the code into the `Code.gs` file. Then save the project.
8. Back in the spreadsheet, select the **Update Potion Shop** tab. Click the **Update Script** button, click the overflow menu, and select **Assign script**.
9. In the **Assign script** window, enter `UpdateScript` and click **OK**.

### Create an API key

1. Go to the [Creator Hub Open Cloud API Keys](https://create.roblox.com/dashboard/credentials?activeTab=ApiKeysTab) page and click **Create API Key**.
2. Fill out the form with the following information.
  - **Name**: PotionShop
  - **API System**: Add the **universe-place-instances** API system. Add your Potion Shop experience to the system. For **Experience Operations**, add read and write access.
  - **Accepted IP Addresses**: Add 0.0.0.0/0 as an IP Address
  - **Expiration**: No Expiration
  - Click **Save & Generate Key** and then **Copy Key to Clipboard**.
3. Paste the API key to the API Key cell (D2) on the Intro tab of your Google Sheet.

### Obtain the universe and place ID

1. Go to the [Creator Hub Creations](https://create.roblox.com/dashboard/creations) page, hover over the Potion Shop's experience tile, and click the overflow menu.
2. Select **Copy Universe ID** and paste it into the **Universe ID** cell (E2) on the Intro tab of your Google Sheet.
3. Select **Copy Start Place ID** and paste it into the **Place ID** cell (F2) on the Intro tab of your Google Sheet.

### Update the script values

1. In the **Update Potion Shop** tab of the sheet, modify any values you'd like and click the **Update Script** button.
2. If Google Sheets prompts you to for authorization, click **OK** and allow your account to run the script.
3. In Studio, playtest the Potion Shop to see any reflected changes. From the **Explorer** window, you can also open the **ReplicatedStorage > ItemList** script to inspect the changes.