> ## Documentation Index
> Fetch the complete documentation index at: https://gcore-doc-1894.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Create and manage an object or SFTP storage

export const MethodSection = ({children}) => children ?? null;

export const MethodSwitch = ({children}) => {
  const tabs = React.Children.toArray(children).map(c => {
    if (!c || !c.props) return null;
    if (c.props.id) return c;
    const inner = c.props.children;
    if (inner && inner.props && inner.props.id) return inner;
    return null;
  }).filter(Boolean);
  const firstId = tabs.length > 0 ? tabs[0].props.id : "";
  const [active, setActive] = React.useState(firstId);
  React.useEffect(() => {
    try {
      const saved = localStorage.getItem("gcore_docs_method");
      if (saved && tabs.find(t => t.props.id === saved)) {
        setActive(saved);
      }
    } catch (_) {}
  }, []);
  React.useEffect(() => {
    try {
      document.querySelectorAll("h2[id], h3[id]").forEach(heading => {
        const visible = heading.offsetParent !== null;
        document.querySelectorAll(`a[href="#${heading.id}"]`).forEach(link => {
          if (link.closest("h1,h2,h3,h4,h5,h6")) return;
          const li = link.closest("li");
          if (li) li.style.display = visible ? "" : "none";
        });
      });
    } catch (_) {}
    window.dispatchEvent(new Event("scroll"));
  }, [active]);
  const handleClick = id => {
    setActive(id);
    try {
      localStorage.setItem("gcore_docs_method", id);
    } catch (_) {}
  };
  return <div>
      <div className="not-prose flex gap-0 border-b border-zinc-200 dark:border-zinc-800 mb-8 mt-2" role="tablist">
        {tabs.map(tab => {
    const isActive = active === tab.props.id;
    return <button key={tab.props.id} role="tab" aria-selected={isActive} onClick={() => handleClick(tab.props.id)} className={["px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors cursor-pointer", isActive ? "border-primary text-primary" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"].join(" ")}>
              {tab.props.label}
            </button>;
  })}
      </div>

      {tabs.map(tab => <div key={tab.props.id} style={{
    display: active === tab.props.id ? "" : "none"
  }}>
          {tab.props.children}
        </div>)}
    </div>;
};

<MethodSwitch>
  <MethodSection id="portal" label="Customer Portal">
    <p>Gcore Object Storage offers three storage types, each suited to different workloads and access protocols:</p>

    * **S3 Standard** — general-purpose S3-compatible storage for backups, content delivery, and most workloads
    * **S3 Fast** — high-performance S3-compatible storage optimized for AI/ML workloads, IoT telemetry, and latency-sensitive applications (available in Sines-2, Sines-3, and London-2)
    * **SFTP** — legacy file-based storage accessed via SFTP protocol, with the same pricing and billing terms as S3 Standard

    ## Create a storage

    <Steps>
      <Step title="Open Object Storages">
        In the [Gcore Customer Portal](https://portal.gcore.com), navigate to **Storage** > **Object Storages**.
      </Step>

      <Step title="Start creation">
        Click **Add new object storage** in the top-right corner.
      </Step>

      <Step title="Enter storage details">
        In the dialog, enter the storage name and select a location. The location name shows the storage type and data center — S3 Standard Luxembourg-2 or SFTP Amsterdam. SFTP locations appear and disappear based on available capacity.

        <Frame>
          <img src="https://mintcdn.com/gcore-doc-1894/WQHfSF35aNg40KtQ/images/docs/storage/create-an-s3-or-sftp-storage/add-object-storage-dialog.png?fit=max&auto=format&n=WQHfSF35aNg40KtQ&q=85&s=f662dd74422a8dd8b42cd02365a6dcda" alt="Add new object storage dialog with Name and Location fields" width="1400" height="756" data-path="images/docs/storage/create-an-s3-or-sftp-storage/add-object-storage-dialog.png" />
        </Frame>

        <Info>
          A maximum of 3600 storages can be created per account.
        </Info>
      </Step>
    </Steps>

    ### S3 Standard and S3 Fast

    <p>S3 Standard and S3 Fast use the same creation flow — the only difference is the location selected in the dropdown. Each S3 storage supports up to 1000 buckets and 10 million objects per bucket. For optimal performance, keep under 100K objects per bucket and distribute data across multiple buckets.</p>

    <p>In the **Location** dropdown, select an **S3 Standard** or **S3 Fast** location, then click **Create** at the bottom of the dialog.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore-doc-1894/WQHfSF35aNg40KtQ/images/docs/storage/create-an-s3-or-sftp-storage/location-dropdown.png?fit=max&auto=format&n=WQHfSF35aNg40KtQ&q=85&s=101db4c53068290c6f4eeed73acc70d2" alt="Location dropdown in the Add new object storage dialog showing S3 and SFTP location options" width="504" height="510" data-path="images/docs/storage/create-an-s3-or-sftp-storage/location-dropdown.png" />
    </Frame>

    <p>A **Details** dialog opens immediately, showing the storage credentials: access key, secret key, hostname, and location. Click **Copy object storage data** to copy all credentials at once.</p>

    <p>Store the secret key, because it is returned only when a key is created. The initial key has read-write access. Additional [access keys](/storage/manage-object-storage/manage-s3-access-keys) — read-write or read-only — can be created after the storage exists. Read-only keys are supported on S3 Standard only.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore-doc-1894/WQHfSF35aNg40KtQ/images/docs/storage/create-an-s3-or-sftp-storage/s3-storage-created-10.png?fit=max&auto=format&n=WQHfSF35aNg40KtQ&q=85&s=3cdb6261967d9e622542e14d9bc27354" alt="Details dialog showing S3 storage credentials including access key, secret key, and hostname" width="720" height="520" data-path="images/docs/storage/create-an-s3-or-sftp-storage/s3-storage-created-10.png" />
    </Frame>

    **S3 management options**

    <p>The created storage appears in the storage list. To manage it, click **...** (three dots) next to the storage name and select an option:</p>

    | Option                | Description                                                                                                                                                                                                                         |
    | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Details               | View **Object Storage User name**, **Location**, and **Hostname**.                                                                                                                                                                  |
    | Access keys           | Create and delete read-write or read-only S3 access keys. S3 Standard supports up to 10 access keys; S3 Fast supports up to 2. Read-only keys are supported on S3 Standard only. The secret is returned only when a key is created. |
    | Buckets               | Manage the storage's [buckets](/storage/manage-object-storage/manage-buckets-via-the-control-panel).                                                                                                                                |
    | Delete object storage | Permanently delete the storage and all its contents. This action cannot be undone.                                                                                                                                                  |

    ### SFTP storage

    <p>SFTP storage requires choosing an authentication method during creation — password or SSH key. Both can be managed after creation.</p>

    <p>In the **Location** dropdown, select an **SFTP** location and enter a name as described in the general steps above. Then select the authentication method:</p>

    <Steps>
      <Step title="Select authentication method">
        Select **Password** or **SSH Key**. Leave the password field empty to generate one automatically.
      </Step>

      <Step title="Create">
        Click **Create** at the bottom of the dialog.

        <Frame>
          <img src="https://mintcdn.com/gcore-doc-1894/WQHfSF35aNg40KtQ/images/docs/storage/create-an-s3-or-sftp-storage/sftp-storage-created-30.png?fit=max&auto=format&n=WQHfSF35aNg40KtQ&q=85&s=ea806aae1ec4ea6a7b1917b44a2bf762" alt="Add new object storage dialog with SFTP Amsterdam location and password authentication fields" width="500" height="520" data-path="images/docs/storage/create-an-s3-or-sftp-storage/sftp-storage-created-30.png" />
        </Frame>
      </Step>
    </Steps>

    #### SFTP management options

    <p>After creation, manage the SFTP storage by clicking **...** (three dots) next to the storage name and selecting an option:</p>

    | Option                | Description                                                                                                                                                         |
    | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | Details               | View the hostname and connection path. Use port 2200 to connect via SFTP.                                                                                           |
    | Edit                  | Configure the server alias and the HTTP `Expires` response header for files served over HTTP. Configuration details are in the [Edit dialog](#edit-dialog) section. |
    | Set/Update password   | Set or replace the password used to authenticate SFTP connections.                                                                                                  |
    | Remove password       | Remove password authentication from the storage. After removal, only SSH key authentication is accepted.                                                            |
    | SSH keys manager      | Add or remove [SSH keys](/storage/manage-sftp-storage/create-and-add-an-ssh-key-to-your-storage) for SFTP authentication. Up to five keys are allowed per storage.  |
    | Delete object storage | Permanently delete the storage and all its contents. This action cannot be undone.                                                                                  |

    <Frame>
      <img src="https://mintcdn.com/gcore-doc-1894/WQHfSF35aNg40KtQ/images/docs/storage/create-an-s3-or-sftp-storage/sftp-storage-settings-40.png?fit=max&auto=format&n=WQHfSF35aNg40KtQ&q=85&s=58e5e024fea8869c88a149df5f7358d3" alt="SFTP storage actions dropdown showing Details, Edit, password management, SSH keys manager, and Delete options" width="1111" height="358" data-path="images/docs/storage/create-an-s3-or-sftp-storage/sftp-storage-settings-40.png" />
    </Frame>

    #### Edit dialog

    <p>The **Edit** dialog for SFTP storage has two fields. Open it by clicking **...** > **Edit** next to the storage name.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore-doc-1894/WQHfSF35aNg40KtQ/images/docs/storage/create-an-s3-or-sftp-storage/sftp-expires-header-50.png?fit=max&auto=format&n=WQHfSF35aNg40KtQ&q=85&s=f2edf551aabf7cefb5d987d43308e880" alt="Edit dialog for SFTP storage with Server alias and Expires fields" width="500" height="340" data-path="images/docs/storage/create-an-s3-or-sftp-storage/sftp-expires-header-50.png" />
    </Frame>

    <p>In the **Server alias** field, enter a domain name (subdomains are supported), then add a CNAME record in DNS settings: `<server_name>.<host>`. For a storage named `12345-test` in Amsterdam, the record would be `CNAME 12345-test.ams.origin.gcdn.co`.</p>

    <p>In the **Expires** field, set the value of the HTTP `Expires` response header for files served over HTTP. Use the format `N years|months|weeks|days|hours|minutes|seconds`. The default is one year.</p>

    ## Storage status indicator

    <p>Each storage row shows a colored circle to the left of the ID.</p>

    <p>After creation or a settings update — adding keys or changing a password — the storage enters a processing state shown by an orange circle. A green circle indicates the storage is ready.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore-doc-1894/WQHfSF35aNg40KtQ/images/docs/storage/create-an-s3-or-sftp-storage/storage-status-indicator-60.png?fit=max&auto=format&n=WQHfSF35aNg40KtQ&q=85&s=bf620ae7130ba1421f5c14070044ebc4" alt="Storage list showing orange and green status circles next to storage entries" width="1107" height="567" data-path="images/docs/storage/create-an-s3-or-sftp-storage/storage-status-indicator-60.png" />
    </Frame>
  </MethodSection>

  <MethodSection id="api" label="REST API">
    <p>Each S3-compatible or SFTP storage is provisioned with a single API call. S3 and SFTP use different endpoints. For S3 storage, the secret key is returned only at creation time and cannot be retrieved later.</p>

    <Info>
      An [API token](/account-settings/api-tokens) is required.
    </Info>

    ```bash theme={null}
    export GCORE_API_KEY="{YOUR_API_KEY}"
    ```

    ## Quickstart

    <p>The scripts below list available locations, create an S3 storage, and print the credentials.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        from gcore import Gcore

        client = Gcore()

        # Step 1. List available locations and select an S3-compatible one
        locations = client.storage.locations.list()
        s3_location = next(loc for loc in locations if loc.type == "s3_compatible")

        # Step 2. Create S3 storage — access key and secret key are returned only here
        storage = client.storage.object_storages.create(
            location_name=s3_location.name,
            name="my-storage",
        )
        print(f"Storage ID: {storage.id}")
        print(f"Endpoint:   {storage.address}")
        print(f"Full name:  {storage.full_name}")
        print(f"Access key: {storage.access_keys[0].access_key}")
        print(f"Secret key: {storage.access_keys[0].secret_key}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "log"

            gcore "github.com/G-Core/gcore-go"
            "github.com/G-Core/gcore-go/storage"
        )

        func main() {
            client := gcore.NewClient()
            ctx := context.Background()

            // Step 1. List available locations and select an S3-compatible one
            locations, err := client.Storage.Locations.List(ctx, storage.LocationListParams{})
            if err != nil {
                log.Fatalf("list locations: %v", err)
            }
            var locationName string
            for _, loc := range locations.Results {
                if loc.Type == "s3_compatible" {
                    locationName = loc.Name
                    break
                }
            }

            // Step 2. Create S3 storage — access key and secret key are returned only here
            s3, err := client.Storage.ObjectStorages.New(ctx, storage.ObjectStorageNewParams{
                Name:         "my-storage",
                LocationName: locationName,
            })
            if err != nil {
                log.Fatalf("create storage: %v", err)
            }
            fmt.Printf("Storage ID: %d\n", s3.ID)
            fmt.Printf("Endpoint:   %s\n", s3.Address)
            fmt.Printf("Full name:  %s\n", s3.FullName)
            fmt.Printf("Access key: %s\n", s3.AccessKeys[0].AccessKey)
            fmt.Printf("Secret key: %s\n", s3.AccessKeys[0].SecretKey)
        }
        ```
      </Tab>
    </Tabs>

    <p>The sections below cover the individual API operations: S3 creation with step-by-step detail, SFTP creation, SFTP password updates, and deletion for both storage types.</p>

    ## Step-by-step

    <p>Each step below explains what the call does, which parameters matter, and what the response looks like.</p>

    <Accordion title="Show all steps">
      ### Step 1. List available locations

      <p>The locations endpoint returns all regions where Object Storage is available, including their type and S3 endpoint hostname. Pass the `name` field as `location_name` when creating storage.</p>

      <Tabs>
        <Tab title="Python SDK">
          ```python theme={null}
          from gcore import Gcore

          client = Gcore()

          locations = client.storage.locations.list()
          for loc in locations:
              print(f"{loc.name}  type={loc.type}  endpoint={loc.address}")
          ```
        </Tab>

        <Tab title="Go SDK">
          ```go theme={null}
          package main

          import (
              "context"
              "fmt"
              "log"

              gcore "github.com/G-Core/gcore-go"
              "github.com/G-Core/gcore-go/storage"
          )

          func main() {
              client := gcore.NewClient()
              ctx := context.Background()

              locations, err := client.Storage.Locations.List(ctx, storage.LocationListParams{})
              if err != nil {
                  log.Fatalf("list locations: %v", err)
              }
              for _, loc := range locations.Results {
                  fmt.Printf("%s  type=%s  endpoint=%s\n", loc.Name, loc.Type, loc.Address)
              }
          }
          ```
        </Tab>

        <Tab title="curl">
          ```bash theme={null}
          curl https://api.gcore.com/storage/v4/locations \
            -H "Authorization: APIKey $GCORE_API_KEY"
          ```

          Response:

          ```json theme={null}
          {
            "count": 9,
            "results": [
              {
                "technical_name": "s-ed1",
                "name": "luxembourg-2",
                "type": "s3_compatible",
                "address": "luxembourg-2.storage.gcore.dev",
                "title": "S3 Standard Luxembourg-2"
              },
              {
                "technical_name": "ams",
                "name": "ams",
                "type": "sftp",
                "address": "ams.origin.gcdn.co",
                "title": "SFTP Amsterdam"
              }
            ]
          }
          ```
        </Tab>
      </Tabs>

      ### Step 2. Create S3 storage

      <p>Pass the `name` from the locations response as `location_name`. The response includes the access key and secret key — this is the only time the secret key is returned. Save it immediately.</p>

      | Parameter       | Required | Description                                                                                                                                                                                         |
      | --------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
      | `location_name` | Yes      | Location `name` value from Step 1. S3 Standard and S3 Fast use the same endpoint — the storage type is determined by the location name (e.g. `luxembourg-2` for S3 Standard, `sines-2` for S3 Fast) |
      | `name`          | Yes      | Storage name. The API prefixes it with the account ID to form `full_name`, which is the storage identifier used as the path prefix in S3 client connections                                         |

      <Tabs>
        <Tab title="Python SDK">
          ```python theme={null}
          from gcore import Gcore

          client = Gcore()

          storage = client.storage.object_storages.create(
              location_name="luxembourg-2",
              name="my-storage",
          )
          print(f"Storage ID: {storage.id}")
          print(f"Endpoint:   {storage.address}")
          print(f"Full name:  {storage.full_name}")
          print(f"Access key: {storage.access_keys[0].access_key}")
          print(f"Secret key: {storage.access_keys[0].secret_key}")
          ```
        </Tab>

        <Tab title="Go SDK">
          ```go theme={null}
          package main

          import (
              "context"
              "fmt"
              "log"

              gcore "github.com/G-Core/gcore-go"
              "github.com/G-Core/gcore-go/storage"
          )

          func main() {
              client := gcore.NewClient()
              ctx := context.Background()

              s3, err := client.Storage.ObjectStorages.New(ctx, storage.ObjectStorageNewParams{
                  Name:         "my-storage",
                  LocationName: "luxembourg-2",
              })
              if err != nil {
                  log.Fatalf("create storage: %v", err)
              }
              fmt.Printf("Storage ID: %d\n", s3.ID)
              fmt.Printf("Endpoint:   %s\n", s3.Address)
              fmt.Printf("Full name:  %s\n", s3.FullName)
              fmt.Printf("Access key: %s\n", s3.AccessKeys[0].AccessKey)
              fmt.Printf("Secret key: %s\n", s3.AccessKeys[0].SecretKey)
          }
          ```
        </Tab>

        <Tab title="curl">
          ```bash theme={null}
          curl -X POST https://api.gcore.com/storage/v4/object_storages \
            -H "Authorization: APIKey $GCORE_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{"location_name": "luxembourg-2", "name": "my-storage"}'
          ```

          Response:

          ```json theme={null}
          {
            "id": 13864,
            "name": "my-storage",
            "full_name": "1000503-my-storage",
            "location_name": "luxembourg-2",
            "type": "standard",
            "address": "luxembourg-2.storage.gcore.dev",
            "provisioning_status": "active",
            "access_keys": [
              {
                "access_key": "L1M3FSX3T0B3TWDVINKT",
                "secret_key": "Qt5mbsZWv6F6q4QySDmWuCfgQIBAHnkVefsPfATf"
              }
            ],
            "created_at": "2026-07-13T13:06:54Z"
          }
          ```

          Save the storage ID:

          ```bash theme={null}
          export STORAGE_ID=13864
          ```
        </Tab>
      </Tabs>
    </Accordion>

    <p>The initial key in the response has read-write access. Additional keys — read-write or read-only — can be created using the [access keys](/storage/manage-object-storage/manage-s3-access-keys) endpoint. S3 Standard supports up to 10 access keys per storage; S3 Fast supports up to 2. Read-only keys are supported on S3 Standard only.</p>

    <p>The access key request body uses the field name <code>read\_only</code>. The response returns the same concept as <code>is\_read\_only</code> — note this naming difference when building API clients.</p>

    ## List S3 storages

    <p>Use <code>GET /storage/v4/object\_storages</code> to retrieve all S3 storages in the account. Each item includes a <code>type</code> field reporting the performance tier: <code>standard</code> for CEPH-backed storages and <code>fast</code> for VAST-backed storages. Pass <code>?type=standard</code> or <code>?type=fast</code> to filter the list to a specific tier.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        from gcore import Gcore

        client = Gcore()

        storages = client.storage.object_storages.list()
        for s in storages.results:
            print(f"{s.id}  {s.name}  {s.location_name}  type={s.type}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "log"

            gcore "github.com/G-Core/gcore-go"
            "github.com/G-Core/gcore-go/storage"
        )

        func main() {
            client := gcore.NewClient()
            ctx := context.Background()

            result, err := client.Storage.ObjectStorages.List(ctx, storage.ObjectStorageListParams{})
            if err != nil {
                log.Fatalf("list storages: %v", err)
            }
            for _, s := range result.Results {
                fmt.Printf("%d  %s  %s\n", s.ID, s.Name, s.LocationName)
            }
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        # List all storages
        curl https://api.gcore.com/storage/v4/object_storages \
          -H "Authorization: APIKey $GCORE_API_KEY"

        # List only S3 Standard (CEPH-backed) storages
        curl "https://api.gcore.com/storage/v4/object_storages?type=standard" \
          -H "Authorization: APIKey $GCORE_API_KEY"

        # List only S3 Fast (VAST-backed) storages
        curl "https://api.gcore.com/storage/v4/object_storages?type=fast" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

        The API returns:

        ```json theme={null}
        {
          "count": 1,
          "results": [
            {
              "id": 12345,
              "name": "my-storage",
              "full_name": "123456-my-storage",
              "location_name": "luxembourg-2",
              "type": "standard",
              "address": "luxembourg-2.storage.gcore.com",
              "provisioning_status": "active",
              "created_at": "2024-01-15T10:30:00Z"
            }
          ]
        }
        ```
      </Tab>
    </Tabs>

    <Note>
      Backblaze- and Wasabi-backed storages report `type=standard` in the response but are not returned by the `?type=standard` filter. The filter selects CEPH-backed storages only. Omitting `type` returns all storages regardless of backend.
    </Note>

    ## Create SFTP storage

    <p>SFTP storage uses a different endpoint and requires a `password_mode` field. Setting it to `auto` generates a random password returned in the creation response — the only time it is visible. Use `set` to provide a custom password, or `none` to disable password authentication and use SSH keys instead.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        from gcore import Gcore

        client = Gcore()

        sftp = client.storage.sftp_storages.create(
            location_name="ams",
            name="my-sftp-storage",
            password_mode="auto",
        )
        print(f"Storage ID: {sftp.id}")
        print(f"Hostname:   {sftp.address}")
        print(f"Password:   {sftp.password}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "log"

            gcore "github.com/G-Core/gcore-go"
            "github.com/G-Core/gcore-go/storage"
        )

        func main() {
            client := gcore.NewClient()
            ctx := context.Background()

            sftp, err := client.Storage.SftpStorages.New(ctx, storage.SftpStorageNewParams{
                Name:         "my-sftp-storage",
                LocationName: "ams",
                PasswordMode: storage.SftpStorageNewParamsPasswordModeAuto,
            })
            if err != nil {
                log.Fatalf("create SFTP storage: %v", err)
            }
            fmt.Printf("Storage ID: %d\n", sftp.ID)
            fmt.Printf("Hostname:   %s\n", sftp.Address)
            fmt.Printf("Password:   %s\n", sftp.Password)
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X POST https://api.gcore.com/storage/v4/sftp_storages \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{"location_name": "ams", "name": "my-sftp-storage", "password_mode": "auto"}'
        ```

        Response:

        ```json theme={null}
        {
          "id": 13865,
          "name": "my-sftp-storage",
          "full_name": "1000503-my-sftp-storage",
          "location_name": "ams",
          "address": "ams.origin.gcdn.co",
          "provisioning_status": "creating",
          "has_password": true,
          "password": "SVaUEHefakmx",
          "created_at": "2026-07-13T13:08:43Z"
        }
        ```

        Connect to the storage using SFTP on port 2200:

        ```bash theme={null}
        sftp -P 2200 1000503-my-sftp-storage@ams.origin.gcdn.co
        ```
      </Tab>
    </Tabs>

    ## Update SFTP password

    <p>Use <code>PATCH /v4/sftp\_storages/{storage_id}</code> to replace an SFTP storage's password. Set <code>password\_mode</code> to <code>set</code> and provide the new value in <code>password</code>. The <code>password</code> field is only accepted when <code>password\_mode</code> is <code>set</code>.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        from gcore import Gcore

        client = Gcore()

        sftp_id = 13865
        client.storage.sftp_storages.update(
            sftp_id,
            password_mode="set",
            password="MyNewPassword123",
        )
        print("Password updated")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "log"

            gcore "github.com/G-Core/gcore-go"
            "github.com/G-Core/gcore-go/storage"
        )

        func main() {
            client := gcore.NewClient()
            ctx := context.Background()

            var sftpID int64 = 13865

            _, err := client.Storage.SftpStorages.Update(ctx, sftpID, storage.SftpStorageUpdateParams{
                PasswordMode: storage.SftpStorageUpdateParamsPasswordModeSet,
                Password:     gcore.String("MyNewPassword123"),
            })
            if err != nil {
                log.Fatalf("update SFTP password: %v", err)
            }
            fmt.Println("Password updated")
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X PATCH "https://api.gcore.com/storage/v4/sftp_storages/$SFTP_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{"password_mode": "set", "password": "MyNewPassword123"}'
        ```

        Returns HTTP 200 with the updated storage object.
      </Tab>
    </Tabs>

    ## Delete storage

    <p>Deleting a storage permanently removes all data it contains. S3 and SFTP storages use different endpoints.</p>

    <p>**Delete S3 storage:**</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        from gcore import Gcore

        client = Gcore()

        storage_id = 13864
        client.storage.object_storages.delete(storage_id)
        print("Storage deleted")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "log"

            gcore "github.com/G-Core/gcore-go"
        )

        func main() {
            client := gcore.NewClient()
            ctx := context.Background()

            var storageID int64 = 13864

            err := client.Storage.ObjectStorages.Delete(ctx, storageID)
            if err != nil {
                log.Fatalf("delete storage: %v", err)
            }
            fmt.Println("Storage deleted")
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X DELETE "https://api.gcore.com/storage/v4/object_storages/$STORAGE_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

        Returns HTTP 204 with no response body.
      </Tab>
    </Tabs>

    <p>**Delete SFTP storage** uses the SFTP endpoint:</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        from gcore import Gcore

        client = Gcore()

        sftp_id = 13865
        client.storage.sftp_storages.delete(sftp_id)
        print("SFTP storage deleted")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "log"

            gcore "github.com/G-Core/gcore-go"
        )

        func main() {
            client := gcore.NewClient()
            ctx := context.Background()

            var sftpID int64 = 13865

            err := client.Storage.SftpStorages.Delete(ctx, sftpID)
            if err != nil {
                log.Fatalf("delete SFTP storage: %v", err)
            }
            fmt.Println("SFTP storage deleted")
        }
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        curl -X DELETE "https://api.gcore.com/storage/v4/sftp_storages/$SFTP_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

        Returns HTTP 204 with no response body.
      </Tab>
    </Tabs>
  </MethodSection>

  <MethodSection id="terraform" label="Terraform">
    <p>Provision S3-compatible and SFTP storages declaratively using the Gcore [Terraform provider](/developer-tools/terraform/overview) v2.</p>

    ## Create S3 storage

    <p>Declares an S3 storage. The storage is provisioned with one access key automatically. To create an S3 Fast storage instead of S3 Standard, set `location_name` to an S3 Fast location name (e.g. `sines-2`) — the resource type is the same.</p>

    ```hcl theme={null}
    resource "gcore_storage_object_storage" "example" {
      location_name = "luxembourg-2"
      name          = "my-storage"
    }

    output "s3_endpoint" {
      value = gcore_storage_object_storage.example.address
    }

    output "s3_access_key" {
      value = gcore_storage_object_storage.example.access_keys[0].access_key
    }

    output "s3_secret_key" {
      value     = gcore_storage_object_storage.example.access_keys[0].secret_key
      sensitive = true
    }

    # terraform import gcore_storage_object_storage.example '<storage_id>'
    ```

    ```bash theme={null}
    terraform apply
    ```

    ## Delete S3 storage

    <p>Remove the resource block. Terraform deletes the storage on the next apply.</p>

    <Warning>
      Deleting the storage permanently removes all buckets and objects it contains. This action cannot be undone.
    </Warning>

    ```hcl theme={null}
    # Remove or comment out this block:
    # resource "gcore_storage_object_storage" "example" { ... }
    ```

    ```bash theme={null}
    terraform apply
    ```

    ## Create SFTP storage

    <p>Declares an SFTP storage with an auto-generated password. After apply, use `full_name` as the login username when connecting on port 2200.</p>

    ```hcl theme={null}
    resource "gcore_storage_sftp" "example" {
      location_name = "ams"
      name          = "my-sftp-storage"
      password_mode = "auto"
    }

    output "sftp_address" {
      value = gcore_storage_sftp.example.address
    }

    output "sftp_full_name" {
      value = gcore_storage_sftp.example.full_name
    }

    output "sftp_password" {
      value     = gcore_storage_sftp.example.password
      sensitive = true
    }

    # terraform import gcore_storage_sftp.example '<storage_id>'
    ```

    ```bash theme={null}
    terraform apply
    ```

    ## Update SFTP password

    <p>To change the SFTP storage password, set <code>password\_mode</code> to <code>set</code> and add a <code>password</code> attribute, then apply.</p>

    ```hcl theme={null}
    resource "gcore_storage_sftp" "example" {
      location_name = "ams"
      name          = "my-sftp-storage"
      password_mode = "set"
      password      = var.sftp_password
    }
    ```

    ```bash theme={null}
    terraform apply
    ```

    ## Delete SFTP storage

    <p>Remove the resource block — Terraform deletes the storage on the next apply.</p>

    <Warning>
      Deleting the storage permanently removes all its contents. This action cannot be undone.
    </Warning>

    ```hcl theme={null}
    # Remove or comment out this block:
    # resource "gcore_storage_sftp" "example" {
    #   location_name = "ams"
    #   name          = "my-sftp-storage"
    #   password_mode = "auto"
    # }
    ```

    ```bash theme={null}
    terraform apply
    ```
  </MethodSection>
</MethodSwitch>
