Configure Google Drive
curl --request POST \
--url https://api.tornadoapi.io/user/gdrive \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '
{
"service_account_json": "<string>",
"folder_id": "<string>",
"folder_prefix": "<string>",
"base_folder": "<string>"
}
'import requests
url = "https://api.tornadoapi.io/user/gdrive"
payload = {
"service_account_json": "<string>",
"folder_id": "<string>",
"folder_prefix": "<string>",
"base_folder": "<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({
service_account_json: '<string>',
folder_id: '<string>',
folder_prefix: '<string>',
base_folder: '<string>'
})
};
fetch('https://api.tornadoapi.io/user/gdrive', 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/gdrive",
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([
'service_account_json' => '<string>',
'folder_id' => '<string>',
'folder_prefix' => '<string>',
'base_folder' => '<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/gdrive"
payload := strings.NewReader("{\n \"service_account_json\": \"<string>\",\n \"folder_id\": \"<string>\",\n \"folder_prefix\": \"<string>\",\n \"base_folder\": \"<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/gdrive")
.header("x-api-key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"service_account_json\": \"<string>\",\n \"folder_id\": \"<string>\",\n \"folder_prefix\": \"<string>\",\n \"base_folder\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tornadoapi.io/user/gdrive")
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 \"service_account_json\": \"<string>\",\n \"folder_id\": \"<string>\",\n \"folder_prefix\": \"<string>\",\n \"base_folder\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"message": "Google Drive configured successfully",
"provider": "gdrive",
"folder_id": "1AbCdEfGhIjKlMnOpQrStUvWxYz",
"folder_prefix": null
}
User
Configure Google Drive
Configure Google Drive delivery for your downloads
POST
/
user
/
gdrive
Configure Google Drive
curl --request POST \
--url https://api.tornadoapi.io/user/gdrive \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '
{
"service_account_json": "<string>",
"folder_id": "<string>",
"folder_prefix": "<string>",
"base_folder": "<string>"
}
'import requests
url = "https://api.tornadoapi.io/user/gdrive"
payload = {
"service_account_json": "<string>",
"folder_id": "<string>",
"folder_prefix": "<string>",
"base_folder": "<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({
service_account_json: '<string>',
folder_id: '<string>',
folder_prefix: '<string>',
base_folder: '<string>'
})
};
fetch('https://api.tornadoapi.io/user/gdrive', 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/gdrive",
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([
'service_account_json' => '<string>',
'folder_id' => '<string>',
'folder_prefix' => '<string>',
'base_folder' => '<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/gdrive"
payload := strings.NewReader("{\n \"service_account_json\": \"<string>\",\n \"folder_id\": \"<string>\",\n \"folder_prefix\": \"<string>\",\n \"base_folder\": \"<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/gdrive")
.header("x-api-key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"service_account_json\": \"<string>\",\n \"folder_id\": \"<string>\",\n \"folder_prefix\": \"<string>\",\n \"base_folder\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tornadoapi.io/user/gdrive")
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 \"service_account_json\": \"<string>\",\n \"folder_id\": \"<string>\",\n \"folder_prefix\": \"<string>\",\n \"base_folder\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"message": "Google Drive configured successfully",
"provider": "gdrive",
"folder_id": "1AbCdEfGhIjKlMnOpQrStUvWxYz",
"folder_prefix": null
}
Overview
Deliver uploaded videos to a Google Drive folder using a service account. Credentials are verified with a live Drive API call before saving.Google Drive uses service account authentication (the same kind of JSON key as GCS) and resumable uploads. The service account must have access to the target folder — share the Drive folder with the service account’s email address.
Header Parameters
string
required
Your API key for authentication
Request Body
string
required
Service account JSON credentials (the entire JSON file content as a string).
string
Target Drive folder ID (the part after
/folders/ in the folder URL). Leave empty to upload to the service account’s own Drive root. Default: "" (root).string
Optional folder prefix for organizing uploads (e.g.,
downloads/2024/)string
default:"videos"
Base folder name for uploaded files. Defaults to
videos if not specified.Response
string
Success confirmation message
string
Storage provider type:
gdrivestring
The configured target folder ID (empty when using the service account root)
string
The configured folder prefix (if provided)
Examples
curl -X POST "https://api.tornadoapi.io/user/gdrive" \
-H "x-api-key: sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"folder_id": "1AbCdEfGhIjKlMnOpQrStUvWxYz",
"service_account_json": "{\"type\":\"service_account\",\"project_id\":\"my-gcp-project\",\"private_key\":\"-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n\",\"client_email\":\"tornado@my-gcp-project.iam.gserviceaccount.com\"}"
}'
import requests
import json
# Load service account JSON file (recommended)
with open("service-account.json") as f:
sa_json = json.dumps(json.load(f))
response = requests.post(
"https://api.tornadoapi.io/user/gdrive",
headers={"x-api-key": "sk_your_api_key"},
json={
"folder_id": "1AbCdEfGhIjKlMnOpQrStUvWxYz",
"service_account_json": sa_json
}
)
print(response.json())
{
"message": "Google Drive configured successfully",
"provider": "gdrive",
"folder_id": "1AbCdEfGhIjKlMnOpQrStUvWxYz",
"folder_prefix": null
}
Success Response
{
"message": "Google Drive configured successfully",
"provider": "gdrive",
"folder_id": "1AbCdEfGhIjKlMnOpQrStUvWxYz",
"folder_prefix": null
}
Error Responses
{
"error": "Invalid configuration: invalid service account JSON"
}
{
"error": "Credential validation failed: insufficient permissions on folder"
}
{
"error": "Invalid API Key"
}
{
"error": "Google Drive storage configuration is temporarily unavailable"
}
Setup
1
Create a service account
In Google Cloud Console, go to IAM & Admin > Service Accounts > Create Service Account, then create a JSON key under Keys > Add Key.
2
Enable the Drive API
Enable the Google Drive API for the service account’s project.
3
Share the target folder
In Google Drive, share the destination folder with the service account’s email address (
...@PROJECT.iam.gserviceaccount.com) and grant Editor access. Copy the folder ID from the URL (drive.google.com/drive/folders/<FOLDER_ID>).4
Configure Tornado
Send the
folder_id and the minified service_account_json to POST /user/gdrive.A service account has no Drive storage quota at all, and cannot own files.
Google states it plainly: service accounts “must upload files and folders into
shared drives, or use OAuth 2.0 to upload items on behalf of a human user”.So a folder shared from a personal My Drive does not work: the service account
owns whatever it creates, has no quota of its own, and the upload fails with
storageQuotaExceeded. Use a Shared Drive, where files are owned by the
drive and billed to the Workspace pooled storage, and add the service account
as Content manager so it can delete as well as create.Google Drive is available as a pre-configured delivery target via this endpoint only. It is not supported as inline
storage credentials in POST /jobs (inline storage supports S3, Azure Blob, GCS, and Alibaba OSS).Was this page helpful?