> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tornadoapi.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Get S3 Storage

> Retrieve the current S3-compatible storage configuration for your API key

## Overview

Returns the S3-compatible storage configuration currently saved for your API key — whatever was last set via [`POST /user/s3`](/api-reference/user/configure-s3) (or the deprecated [`/user/bucket`](/api-reference/user/update-bucket) endpoint). Use this to confirm what's configured, or to check whether a key has any custom storage at all, without needing to run a test job.

<Info>
  If nothing is configured, this returns `200 OK` with `"configured": false` — not an error. A key with no custom storage is a normal state; it simply falls back to Tornado's managed storage.
</Info>

<Warning>
  This endpoint never returns your `secret_key`, and never returns a full `access_key` — see [Security](#security) below.
</Warning>

## Header Parameters

<ParamField header="x-api-key" type="string" required>
  Your API key for authentication
</ParamField>

## Response

<ResponseField name="configured" type="boolean">
  Whether this key has any S3 storage configured. All other fields are only present when `true`.
</ResponseField>

<ResponseField name="provider" type="string">
  Storage provider type: `s3`
</ResponseField>

<ResponseField name="container_or_bucket" type="string">
  The configured bucket name
</ResponseField>

<ResponseField name="folder_prefix" type="string">
  The configured folder prefix, if any
</ResponseField>

<ResponseField name="base_folder" type="string">
  The configured base folder (only present when set via the modern `/user/s3` path)
</ResponseField>

<ResponseField name="endpoint" type="string">
  The configured S3 endpoint URL. Only present in **legacy** mode (the `source` field below explains the difference) — the modern, Key Vault-backed path doesn't hold the endpoint outside the vault.
</ResponseField>

<ResponseField name="region" type="string">
  The configured region. Only present in **legacy** mode.
</ResponseField>

<ResponseField name="access_key_masked" type="string">
  The last 4 characters of your access key ID, prefixed with `****` (e.g. `****MPLE`). Only present in **legacy** mode. Never the full key — see [Security](#security).
</ResponseField>

<ResponseField name="last_modified" type="integer">
  Unix timestamp (seconds) of when this configuration was last saved. Only present in modern (Key Vault) mode.
</ResponseField>

<ResponseField name="source" type="string">
  Which storage location this configuration came from:

  * `keyvault` — saved via `POST /user/s3` with Key Vault enabled (the default, modern path). Credentials live in Azure Key Vault; this service never holds them outside of upload time, so `endpoint`, `region`, and `access_key_masked` aren't available to return.
  * `legacy` — saved via the fallback path used when Key Vault is disabled (or the deprecated `/user/bucket` endpoint). Credentials are stored on the API key document; `access_key` is shown masked, `secret_key` is never returned.

  If both happen to exist for a key, `keyvault` always wins — this matches exactly which one is actually used for uploads.
</ResponseField>

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.tornadoapi.io/user/s3" \
    -H "x-api-key: sk_your_api_key"
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://api.tornadoapi.io/user/s3",
      headers={"x-api-key": "sk_your_api_key"}
  )
  print(response.json())
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.tornadoapi.io/user/s3", {
    method: "GET",
    headers: { "x-api-key": "sk_your_api_key" }
  });
  const data = await response.json();
  ```

  ```json Response (configured, Key Vault) theme={null}
  {
    "configured": true,
    "provider": "s3",
    "container_or_bucket": "my-tornado-downloads",
    "folder_prefix": "videos/",
    "base_folder": "videos",
    "last_modified": 1751980800,
    "source": "keyvault"
  }
  ```

  ```json Response (configured, legacy) theme={null}
  {
    "configured": true,
    "provider": "s3",
    "container_or_bucket": "my-tornado-downloads",
    "endpoint": "https://s3.us-east-1.amazonaws.com",
    "region": "us-east-1",
    "access_key_masked": "****MPLE",
    "source": "legacy"
  }
  ```

  ```json Response (not configured) theme={null}
  {
    "configured": false
  }
  ```
</CodeGroup>

## Success Response

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "configured": true,
    "provider": "s3",
    "container_or_bucket": "my-tornado-downloads",
    "folder_prefix": "videos/",
    "base_folder": "videos",
    "last_modified": 1751980800,
    "source": "keyvault"
  }
  ```
</ResponseExample>

## Error Responses

<ResponseExample>
  ```json 401 Unauthorized theme={null}
  {
    "error": "Invalid API Key"
  }
  ```
</ResponseExample>

## Security

<AccordionGroup>
  <Accordion title="secret_key is never returned">
    There is no `secret_key` or `secret_key_masked` field in the response at all, in either mode. It's write-only from the API's perspective — set it via `POST /user/s3`, but it can never be read back.
  </Accordion>

  <Accordion title="access_key is never returned in full">
    In legacy mode, only the last 4 characters are returned (`access_key_masked`, e.g. `****MPLE`). Values 4 characters or shorter are fully masked (`****`) rather than echoed whole. In Key Vault mode, the access key isn't returned at all — this service doesn't hold it outside of upload time.
  </Accordion>

  <Accordion title="The Key Vault secret reference is never returned">
    The internal Key Vault secret name (an infrastructure detail, not a credential, but still sensitive) is never included in the response.
  </Accordion>
</AccordionGroup>

## Checking Configuration Programmatically

```python theme={null}
import requests

def get_storage_config(api_key):
    response = requests.get(
        "https://api.tornadoapi.io/user/s3",
        headers={"x-api-key": api_key}
    )
    data = response.json()

    if not data["configured"]:
        print("No custom S3 storage configured — using Tornado's managed storage")
        return

    print(f"Bucket: {data['container_or_bucket']}")
    print(f"Source: {data['source']}")  # "keyvault" or "legacy"
    if "access_key_masked" in data:
        print(f"Access key: {data['access_key_masked']}")

get_storage_config("sk_your_api_key")
```

## Related Endpoints

<CardGroup cols={2}>
  <Card title="Configure S3 Storage" icon="upload" href="/api-reference/user/configure-s3">
    Set or update your S3-compatible storage configuration
  </Card>

  <Card title="Remove S3 Storage" icon="trash" href="/api-reference/user/delete-s3">
    Remove your S3 configuration and revert to Tornado's managed storage
  </Card>
</CardGroup>
