SDX API Documentation
Storage Data eXchange • Version 1.0.0
Welcome to the official documentation for the Storage Data eXchange (SDX) API by Shulker. SDX is an advanced object storage technology that enables blazing-fast uploads to public nodes (buckets) distributed globally.
With SDX, you can upload files of up to 1TB using chunked uploads, create folders (sub-buckets) for better organization, and manage your objects through a comprehensive RESTful API. All responses are in standard JSON
format.
Authentication
The SDX API uses a simple key-based authentication system. Every request must include your unique key
as a URL query parameter.
Security & Node Assignment
Your SDX key is tied to a specific node (e.g., in0
). The API will verify that your key matches the node you're accessing. You can find your API endpoint URL in your SDX Management Panel.
Without a valid key, the API will return a 400 Bad Request
error.
Endpoint URL
The API endpoint URL varies based on your assigned node (bucket). You can find your specific endpoint in your SDX Management Panel. Here's an example for the in0
node:
Important
Always use your actual endpoint URL from your management panel. The example above is for illustration purposes only.
API Endpoints
The SDX API provides comprehensive file management capabilities through various action endpoints. All endpoints use the action
query parameter to specify the operation.
Initialize Upload
Initialize a chunked file upload. This endpoint validates storage space and prepares the system for receiving file chunks.
/?key=YOUR_KEY&action=upload-init&path=/
Parameters
Parameter | Type | Description |
---|---|---|
fileName |
String | Name of the file to upload |
fileSize |
Integer | Total file size in bytes (max 1TB) |
totalChunks |
Integer | Number of chunks (5MB each) |
mimeType |
String | File MIME type (optional) |
Example Requests
async function initializeUpload(file, sdxKey, path = '/') {
const totalChunks = Math.ceil(file.size / (5 * 1024 * 1024));
const formData = new FormData();
formData.append('fileName', file.name);
formData.append('fileSize', file.size);
formData.append('totalChunks', totalChunks);
formData.append('mimeType', file.type);
const response = await fetch(
`https://node-in0-bucket.shulker.in/?key=${sdxKey}&action=upload-init&path=${path}`,
{
method: 'POST',
body: formData
}
);
return await response.json();
}
import requests
import math
def initialize_upload(file_path, sdx_key, path='/'):
file_size = os.path.getsize(file_path)
file_name = os.path.basename(file_path)
total_chunks = math.ceil(file_size / (5 * 1024 * 1024))
data = {
'fileName': file_name,
'fileSize': file_size,
'totalChunks': total_chunks,
'mimeType': 'application/octet-stream'
}
response = requests.post(
f'https://node-in0-bucket.shulker.in/?key={sdx_key}&action=upload-init&path={path}',
data=data
)
return response.json()
curl -X POST "https://node-in0-bucket.shulker.in/?key=YOUR_KEY&action=upload-init&path=/" \
-F "fileName=example.mp4" \
-F "fileSize=104857600" \
-F "totalChunks=20" \
-F "mimeType=video/mp4"
Success Response
{
"success": true,
"upload_id": "sdx_67890abcdef",
"chunk_size": 5242880,
"message": "Upload initialized successfully"
}
Upload Chunk
Upload individual file chunks. Each chunk should be 5MB (except the last chunk which may be smaller).
/?key=YOUR_KEY&action=upload-chunk
Headers
Header | Description |
---|---|
X-Upload-ID |
Upload ID from init response |
X-Chunk-Index |
Zero-based chunk index |
Example Requests
async function uploadChunk(file, uploadId, chunkIndex, sdxKey) {
const CHUNK_SIZE = 5 * 1024 * 1024;
const start = chunkIndex * CHUNK_SIZE;
const end = Math.min(start + CHUNK_SIZE, file.size);
const chunk = file.slice(start, end);
const response = await fetch(
`https://node-in0-bucket.shulker.in/?key=${sdxKey}&action=upload-chunk`,
{
method: 'POST',
headers: {
'X-Upload-ID': uploadId,
'X-Chunk-Index': chunkIndex.toString()
},
body: chunk
}
);
return await response.json();
}
def upload_chunk(file_path, upload_id, chunk_index, sdx_key):
CHUNK_SIZE = 5 * 1024 * 1024
with open(file_path, 'rb') as f:
f.seek(chunk_index * CHUNK_SIZE)
chunk_data = f.read(CHUNK_SIZE)
headers = {
'X-Upload-ID': upload_id,
'X-Chunk-Index': str(chunk_index)
}
response = requests.post(
f'https://node-in0-bucket.shulker.in/?key={sdx_key}&action=upload-chunk',
headers=headers,
data=chunk_data
)
return response.json()
curl -X POST "https://node-in0-bucket.shulker.in/?key=YOUR_KEY&action=upload-chunk" \
-H "X-Upload-ID: sdx_67890abcdef" \
-H "X-Chunk-Index: 0" \
--data-binary "@chunk_0.bin"
Success Response
{
"success": true,
"chunk_index": 0,
"uploaded_chunks": 1,
"total_chunks": 20,
"progress_percent": 5.0,
"bytes_uploaded": 5242880,
"bytes_remaining": 99614720
}
Complete Upload
Finalize the upload by merging all chunks into the final file. This validates chunk integrity and updates storage usage.
/?key=YOUR_KEY&action=upload-complete
Parameters
Parameter | Description |
---|---|
uploadId |
Upload ID from init response |
Example Requests
async function completeUpload(uploadId, sdxKey) {
const formData = new FormData();
formData.append('uploadId', uploadId);
const response = await fetch(
`https://node-in0-bucket.shulker.in/?key=${sdxKey}&action=upload-complete`,
{
method: 'POST',
body: formData
}
);
return await response.json();
}
def complete_upload(upload_id, sdx_key):
data = {'uploadId': upload_id}
response = requests.post(
f'https://node-in0-bucket.shulker.in/?key={sdx_key}&action=upload-complete',
data=data
)
return response.json()
curl -X POST "https://node-in0-bucket.shulker.in/?key=YOUR_KEY&action=upload-complete" \
-F "uploadId=sdx_67890abcdef"
Success Response
{
"success": true,
"message": "Upload completed successfully",
"file_name": "example.mp4",
"file_size": 104857600,
"file_size_formatted": "100 MB",
"path": "example.mp4",
"full_path": "/your_key/example.mp4",
"mime_type": "video/mp4",
"checksum": "d41d8cd98f00b204e9800998ecf8427e",
"upload_time_seconds": 45.32,
"merge_time_seconds": 2.15,
"average_speed_mbps": 2.21,
"chunks_uploaded": 20,
"started_at": "2025-10-15 12:30:00",
"completed_at": "2025-10-15 12:30:45",
"storage_used_gb": 0.0977,
"storage_limit_gb": 100
}
Resume Upload
Check if an incomplete upload exists and get the list of already uploaded chunks to resume from where you left off.
/?key=YOUR_KEY&action=upload-resume&path=/
Example Requests
async function resumeUpload(fileName, sdxKey, path = '/') {
const formData = new FormData();
formData.append('fileName', fileName);
const response = await fetch(
`https://node-in0-bucket.shulker.in/?key=${sdxKey}&action=upload-resume&path=${path}`,
{
method: 'POST',
body: formData
}
);
return await response.json();
}
def resume_upload(file_name, sdx_key, path='/'):
data = {'fileName': file_name}
response = requests.post(
f'https://node-in0-bucket.shulker.in/?key={sdx_key}&action=upload-resume&path={path}',
data=data
)
return response.json()
curl -X POST "https://node-in0-bucket.shulker.in/?key=YOUR_KEY&action=upload-resume&path=/" \
-F "fileName=example.mp4"
Success Response
{
"success": true,
"can_resume": true,
"upload_id": "sdx_67890abcdef",
"uploaded_chunks": [0, 1, 2, 3, 4],
"total_chunks": 20,
"progress_percent": 25.0,
"bytes_uploaded": 26214400,
"bytes_remaining": 78643200
}
List Contents
List all files and folders in a specified directory path.
/?key=YOUR_KEY&action=list-contents&path=/
Example Requests
async function listContents(sdxKey, path = '/') {
const response = await fetch(
`https://node-in0-bucket.shulker.in/?key=${sdxKey}&action=list-contents&path=${path}`
);
return await response.json();
}
def list_contents(sdx_key, path='/'):
response = requests.get(
f'https://node-in0-bucket.shulker.in/?key={sdx_key}&action=list-contents&path={path}'
)
return response.json()
curl "https://node-in0-bucket.shulker.in/?key=YOUR_KEY&action=list-contents&path=/"
Success Response
{
"success": true,
"path": "",
"full_path": "/your_key/",
"items": [
{
"name": "videos",
"path": "videos",
"type": "folder",
"size": 0,
"size_formatted": "-",
"modified": 1697385600,
"modified_formatted": "2025-10-15 12:00:00"
},
{
"name": "example.mp4",
"path": "example.mp4",
"type": "file",
"size": 104857600,
"size_formatted": "100 MB",
"modified": 1697385645,
"modified_formatted": "2025-10-15 12:00:45",
"mime_type": "video/mp4",
"can_read": false
}
],
"total_items": 2,
"folders": 1,
"files": 1
}
Download File
Download a file from your SDX storage. Returns the file as a binary stream.
/?key=YOUR_KEY&action=download&path=/file.ext
Example Requests
async function downloadFile(sdxKey, filePath) {
const response = await fetch(
`https://node-in0-bucket.shulker.in/?key=${sdxKey}&action=download&path=${filePath}`
);
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filePath.split('/').pop();
a.click();
}
def download_file(sdx_key, file_path, save_path):
response = requests.get(
f'https://node-in0-bucket.shulker.in/?key={sdx_key}&action=download&path={file_path}',
stream=True
)
with open(save_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
curl "https://node-in0-bucket.shulker.in/?key=YOUR_KEY&action=download&path=/example.mp4" \
-o example.mp4
Read File Content
Read the contents of a text-based file (max 100MB). Only works with readable file types.
/?key=YOUR_KEY&action=read-file&path=/file.txt
Example Requests
async function readFile(sdxKey, filePath) {
const response = await fetch(
`https://node-in0-bucket.shulker.in/?key=${sdxKey}&action=read-file&path=${filePath}`
);
return await response.json();
}
def read_file(sdx_key, file_path):
response = requests.get(
f'https://node-in0-bucket.shulker.in/?key={sdx_key}&action=read-file&path={file_path}'
)
return response.json()
curl "https://node-in0-bucket.shulker.in/?key=YOUR_KEY&action=read-file&path=/config.json"
Success Response
{
"success": true,
"file_name": "config.json",
"file_size": 1024,
"mime_type": "application/json",
"content": "{\"setting\": \"value\"}",
"encoding": "UTF-8"
}
Delete File/Folder
Delete a file or folder (including all contents). This action is irreversible.
/?key=YOUR_KEY&action=delete&path=/file.ext
Example Requests
async function deleteItem(sdxKey, itemPath) {
const response = await fetch(
`https://node-in0-bucket.shulker.in/?key=${sdxKey}&action=delete&path=${itemPath}`,
{
method: 'DELETE'
}
);
return await response.json();
}
def delete_item(sdx_key, item_path):
response = requests.delete(
f'https://node-in0-bucket.shulker.in/?key={sdx_key}&action=delete&path={item_path}'
)
return response.json()
curl -X DELETE "https://node-in0-bucket.shulker.in/?key=YOUR_KEY&action=delete&path=/example.mp4"
Success Response
{
"success": true,
"message": "Deleted successfully",
"path": "example.mp4",
"size_freed": 104857600,
"size_freed_formatted": "100 MB"
}
Rename File/Folder
Rename a file or folder to a new name within the same directory.
/?key=YOUR_KEY&action=rename&path=/oldname.ext
Parameters
Parameter | Description |
---|---|
newName |
New name for the file or folder |
Example Requests
async function renameItem(sdxKey, oldPath, newName) {
const formData = new FormData();
formData.append('newName', newName);
const response = await fetch(
`https://node-in0-bucket.shulker.in/?key=${sdxKey}&action=rename&path=${oldPath}`,
{
method: 'POST',
body: formData
}
);
return await response.json();
}
def rename_item(sdx_key, old_path, new_name):
data = {'newName': new_name}
response = requests.post(
f'https://node-in0-bucket.shulker.in/?key={sdx_key}&action=rename&path={old_path}',
data=data
)
return response.json()
curl -X POST "https://node-in0-bucket.shulker.in/?key=YOUR_KEY&action=rename&path=/old.mp4" \
-F "newName=new.mp4"
Success Response
{
"success": true,
"message": "Renamed successfully",
"old_name": "old.mp4",
"new_name": "new.mp4",
"new_path": "new.mp4"
}
Create Folder
Create a new folder (sub-bucket) to organize your files better.
/?key=YOUR_KEY&action=create-folder&path=/
Parameters
Parameter | Description |
---|---|
folderName |
Name of the folder to create |
Example Requests
async function createFolder(sdxKey, folderName, path = '/') {
const formData = new FormData();
formData.append('folderName', folderName);
const response = await fetch(
`https://node-in0-bucket.shulker.in/?key=${sdxKey}&action=create-folder&path=${path}`,
{
method: 'POST',
body: formData
}
);
return await response.json();
}
def create_folder(sdx_key, folder_name, path='/'):
data = {'folderName': folder_name}
response = requests.post(
f'https://node-in0-bucket.shulker.in/?key={sdx_key}&action=create-folder&path={path}',
data=data
)
return response.json()
curl -X POST "https://node-in0-bucket.shulker.in/?key=YOUR_KEY&action=create-folder&path=/" \
-F "folderName=videos"
Success Response
{
"success": true,
"message": "Folder created successfully",
"folder_name": "videos",
"path": "videos"
}
Get File/Folder Info
Get detailed information about a specific file or folder including size, type, and modification date.
/?key=YOUR_KEY&action=info&path=/file.ext
Example Requests
async function getInfo(sdxKey, itemPath) {
const response = await fetch(
`https://node-in0-bucket.shulker.in/?key=${sdxKey}&action=info&path=${itemPath}`
);
return await response.json();
}
def get_info(sdx_key, item_path):
response = requests.get(
f'https://node-in0-bucket.shulker.in/?key={sdx_key}&action=info&path={item_path}'
)
return response.json()
curl "https://node-in0-bucket.shulker.in/?key=YOUR_KEY&action=info&path=/example.mp4"
Success Response (File)
{
"success": true,
"name": "example.mp4",
"path": "example.mp4",
"type": "file",
"modified": 1697385645,
"modified_formatted": "2025-10-15 12:00:45",
"size": 104857600,
"size_formatted": "100 MB",
"mime_type": "video/mp4",
"checksum": "d41d8cd98f00b204e9800998ecf8427e",
"can_read": false
}
Get Account Info
Retrieve information about your SDX account including storage usage and limits.
/?key=YOUR_KEY&action=account-info
Example Requests
async function getAccountInfo(sdxKey) {
const response = await fetch(
`https://node-in0-bucket.shulker.in/?key=${sdxKey}&action=account-info`
);
return await response.json();
}
def get_account_info(sdx_key):
response = requests.get(
f'https://node-in0-bucket.shulker.in/?key={sdx_key}&action=account-info'
)
return response.json()
curl "https://node-in0-bucket.shulker.in/?key=YOUR_KEY&action=account-info"
Success Response
{
"success": true,
"account": {
"sdx_key": "your_key_here",
"owner": "[email protected]",
"storage_used_gb": 10.5,
"storage_limit_gb": 100,
"storage_used_percent": 10.5,
"storage_available_gb": 89.5,
"billing_amount": "5.00",
"billing_period": "monthly",
"next_billing": "2025-11-15",
"created_at": "2025-01-01 00:00:00"
}
}
Error Handling
The SDX API uses standard HTTP status codes and returns detailed error messages in JSON format to help you diagnose issues quickly.
Status Code | Meaning | Common Causes |
---|---|---|
400 | Bad Request | Invalid SDX key, missing parameters, or data validation failed |
401 | Unauthorized | Billing overdue or inactive account |
403 | Forbidden | Node mismatch - key doesn't match the node being accessed |
404 | Not Found | File or folder doesn't exist |
500 | Internal Server Error | Database connection failed or server-side issue |
Error Response Format
{
"success": false,
"error": "Insufficient storage space. Used: 95.5GB, Limit: 100GB, Required: 5GB",
"timestamp": 1697385645
}
SDX API Tester
Try the Interactive API Tester
Want to test the SDX API without writing code? Use our interactive API tester tool to explore all endpoints, upload files, manage folders, and see real-time responses.
The tester provides a user-friendly interface to experiment with all API actions, view formatted responses, and learn by doing.
Need help or have questions? Contact Support