Update Bucket Config (Legacy)
curl --request POST \
--url https://api.tornadoapi.io/user/bucket \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '
{
"endpoint": "<string>",
"bucket": "<string>",
"region": "<string>",
"access_key": "<string>",
"secret_key": "<string>"
}
'import requests
url = "https://api.tornadoapi.io/user/bucket"
payload = {
"endpoint": "<string>",
"bucket": "<string>",
"region": "<string>",
"access_key": "<string>",
"secret_key": "<string>"
}
headers = {
"x-api-key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
endpoint: '<string>',
bucket: '<string>',
region: '<string>',
access_key: '<string>',
secret_key: '<string>'
})
};
fetch('https://api.tornadoapi.io/user/bucket', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tornadoapi.io/user/bucket",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'endpoint' => '<string>',
'bucket' => '<string>',
'region' => '<string>',
'access_key' => '<string>',
'secret_key' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.tornadoapi.io/user/bucket"
payload := strings.NewReader("{\n \"endpoint\": \"<string>\",\n \"bucket\": \"<string>\",\n \"region\": \"<string>\",\n \"access_key\": \"<string>\",\n \"secret_key\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.tornadoapi.io/user/bucket")
.header("x-api-key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"endpoint\": \"<string>\",\n \"bucket\": \"<string>\",\n \"region\": \"<string>\",\n \"access_key\": \"<string>\",\n \"secret_key\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tornadoapi.io/user/bucket")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"endpoint\": \"<string>\",\n \"bucket\": \"<string>\",\n \"region\": \"<string>\",\n \"access_key\": \"<string>\",\n \"secret_key\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"message": "Bucket configuration updated successfully"
}
User
Update Bucket Config (Legacy)
Configure your own S3-compatible storage bucket (deprecated)
POST
/
user
/
bucket
Update Bucket Config (Legacy)
curl --request POST \
--url https://api.tornadoapi.io/user/bucket \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '
{
"endpoint": "<string>",
"bucket": "<string>",
"region": "<string>",
"access_key": "<string>",
"secret_key": "<string>"
}
'import requests
url = "https://api.tornadoapi.io/user/bucket"
payload = {
"endpoint": "<string>",
"bucket": "<string>",
"region": "<string>",
"access_key": "<string>",
"secret_key": "<string>"
}
headers = {
"x-api-key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
endpoint: '<string>',
bucket: '<string>',
region: '<string>',
access_key: '<string>',
secret_key: '<string>'
})
};
fetch('https://api.tornadoapi.io/user/bucket', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tornadoapi.io/user/bucket",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'endpoint' => '<string>',
'bucket' => '<string>',
'region' => '<string>',
'access_key' => '<string>',
'secret_key' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.tornadoapi.io/user/bucket"
payload := strings.NewReader("{\n \"endpoint\": \"<string>\",\n \"bucket\": \"<string>\",\n \"region\": \"<string>\",\n \"access_key\": \"<string>\",\n \"secret_key\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.tornadoapi.io/user/bucket")
.header("x-api-key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"endpoint\": \"<string>\",\n \"bucket\": \"<string>\",\n \"region\": \"<string>\",\n \"access_key\": \"<string>\",\n \"secret_key\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tornadoapi.io/user/bucket")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"endpoint\": \"<string>\",\n \"bucket\": \"<string>\",\n \"region\": \"<string>\",\n \"access_key\": \"<string>\",\n \"secret_key\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"message": "Bucket configuration updated successfully"
}
Deprecated: This endpoint only supports S3-compatible storage. Use the dedicated endpoints instead:
POST /user/s3for S3-compatible storagePOST /user/blobfor Azure Blob StoragePOST /user/gcsfor Google Cloud StoragePOST /user/ossfor Alibaba Cloud OSS
Overview
Configure a custom S3-compatible storage bucket for your downloads. Credentials are verified before saving.Header Parameters
string
required
Your API key for authentication
Request
string
required
S3 endpoint URL (e.g.,
https://s3.us-east-1.amazonaws.com)string
required
Bucket name
string
required
AWS region (e.g.,
us-east-1, auto for R2)string
required
AWS Access Key ID or equivalent
string
required
AWS Secret Access Key or equivalent
Response
string
Success confirmation message
Example
curl -X POST "https://api.tornadoapi.io/user/bucket" \
-H "x-api-key: sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"endpoint": "https://s3.us-east-1.amazonaws.com",
"bucket": "my-tornado-downloads",
"region": "us-east-1",
"access_key": "AKIAIOSFODNN7EXAMPLE",
"secret_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}'
curl -X POST "https://api.tornadoapi.io/user/bucket" \
-H "x-api-key: sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"endpoint": "https://ACCOUNT_ID.r2.cloudflarestorage.com",
"bucket": "my-downloads",
"region": "auto",
"access_key": "R2_ACCESS_KEY_ID",
"secret_key": "R2_SECRET_ACCESS_KEY"
}'
{
"message": "Bucket configuration updated successfully"
}
Success Response
{
"message": "Bucket configuration updated successfully"
}
Error Responses
{
"error": "Verification failed: Access Denied"
}
{
"error": "Verification failed: NoSuchBucket"
}
{
"error": "Invalid API Key"
}
Verification Process
When you submit bucket configuration, Tornado:- Creates an S3 client with your credentials
- Uploads a small uniquely named credential-probe object, then attempts best-effort deletion
- If upload validation succeeds, saves the legacy configuration on the API key document. This does not replace a modern saved storage entry
Allow writes and cleanup deletes for the probe, plus reads for delivery. The upload probe does not verify every permission needed by later operations.
Required IAM Permissions
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::your-bucket-name",
"arn:aws:s3:::your-bucket-name/*"
]
}
]
}
Supported Providers
| Provider | Endpoint Format | Region |
|---|---|---|
| AWS S3 | https://s3.{region}.amazonaws.com | Your region |
| Cloudflare R2 | https://{account_id}.r2.cloudflarestorage.com | auto |
| OVH Object Storage | https://s3.{region}.cloud.ovh.net | Your region |
| MinIO | Your MinIO URL | Your region |
| DigitalOcean Spaces | https://{region}.digitaloceanspaces.com | Your region |
| Backblaze B2 | https://s3.{region}.backblazeb2.com | Your region |
| Wasabi | https://s3.{region}.wasabisys.com | Your region |
Was this page helpful?