Direct Blob Upload (Recommended)
Upload files directly to cloud storage using pre-signed URLs for optimal performance and reduced API server load.
Recommended for most use cases — This method is faster and more efficient than TUS or API-proxied uploads.
Why Direct Blob Upload?
Benefits
- Faster uploads: Direct connection to cloud storage (no API middleman)
- Better reliability: Global CDN and resumable uploads
- Scalability: No API server bottleneck for large files
When to Use
- Recommended: Files > 5MB, production workflows, automated pipelines
- Consider TUS: Unreliable networks requiring resumable uploads
- Consider PUT to API: Quick prototypes, files < 1MB
How It Works
Step-by-Step Guide
Step 1: Create a Session
Initialize a transcription session with your desired settings:
curl -X POST "https://api.scriptix.io/api/v3/speech-to-text/session" \
-H "x-zoom-s2t-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"language": "en-us",
"punctuation": true,
"diarization": true,
"webhook_url": "https://example.com/webhook"
}'
Response:
{
"result": {
"session_id": "1b8a70f1000001000002d1a37b",
"status": "new"
}
}
Step 2: Request an Upload URL
Get a pre-signed URL for uploading your file:
curl -X POST "https://api.scriptix.io/api/v3/speech-to-text/session/1b8a70f1000001000002d1a37b/upload-url" \
-H "x-zoom-s2t-key: YOUR_API_KEY"
Response:
{
"result": {
"upload_url": "https://scriptix.blob.core.windows.net/container/session-id/file.mp4?sv=2021-08-06&se=2025-12-08T12%3A00%3A00Z&sr=b&sp=cw&sig=...",
"expires_at": "2025-12-08T12:00:00Z",
"session_id": "1b8a70f1000001000002d1a37b",
"max_file_size": 5368709120
}
}
Note: The URL expires after 24 hours. Complete your upload before expiration.
Step 3: Upload Your File to Cloud Storage
Use a simple HTTP PUT request to upload your file directly to cloud storage:
cURL:
curl -X PUT "https://scriptix.blob.core.windows.net/container/..." \
-H "x-ms-blob-type: BlockBlob" \
-H "Content-Type: audio/mp4" \
--data-binary "@/path/to/recording.mp4"
Python:
import requests
upload_url = "https://scriptix.blob.core.windows.net/..."
file_path = "/path/to/recording.mp4"
with open(file_path, "rb") as f:
response = requests.put(
upload_url,
headers={
"x-ms-blob-type": "BlockBlob",
"Content-Type": "audio/mp4"
},
data=f
)
if response.status_code == 201:
print("Upload successful!")
else:
print(f"Upload failed: {response.status_code}")
TypeScript/JavaScript:
const uploadUrl = "https://scriptix.blob.core.windows.net/...";
const filePath = "/path/to/recording.mp4";
const fileBuffer = fs.readFileSync(filePath);
const response = await fetch(uploadUrl, {
method: "PUT",
headers: {
"x-ms-blob-type": "BlockBlob",
"Content-Type": "audio/mp4"
},
body: fileBuffer
});
if (response.status === 201) {
console.log("Upload successful!");
} else {
console.error(`Upload failed: ${response.status}`);
}
Expected Response: HTTP 201 Created
Step 4: Confirm Upload Completion
Notify the API that your upload is complete to trigger processing:
curl -X POST "https://api.scriptix.io/api/v3/speech-to-text/session/1b8a70f1000001000002d1a37b/upload-complete" \
-H "x-zoom-s2t-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "recording.mp4"
}'
Response:
{
"result": {
"session_id": "1b8a70f1000001000002d1a37b",
"status": "uploaded",
"filename": "recording.mp4",
"duration": 592,
"media_type": "audio"
}
}
The API will now:
- Verify the file exists in cloud storage
- Validate file format and duration
- Scan for malware (if enabled)
- Claim subscription credits
- Queue the transcription job
Advanced: Multipart Upload (Large Files)
For files > 100MB, you can use chunked uploads for better performance and reliability. Here's an example using the requests library with streaming:
import requests
# Upload in 10MB chunks
chunk_size = 10 * 1024 * 1024
def upload_file_chunked(upload_url, file_path):
"""Upload file in chunks for better reliability"""
with open(file_path, "rb") as f:
response = requests.put(
upload_url,
headers={
"x-ms-blob-type": "BlockBlob",
"Content-Type": "application/octet-stream"
},
data=f
)
if response.status_code == 201:
print("Upload successful!")
return True
else:
print(f"Upload failed: {response.status_code}")
return False
# Use the function
upload_file_chunked(upload_url, "/path/to/large-file.mp4")
Error Handling
| Error | Cause | Solution |
|---|---|---|
| invalid-state | Session already uploaded | Create a new session |
| file-not-found | Upload to cloud storage failed | Verify upload succeeded (check HTTP 201) |
| invalid-file | File has no audio | Check file format, ensure audio track exists |
| malware-detected | File contains malware | Remove malicious content, upload clean file |
| insufficient-credits | Not enough credits | Add credits at scriptix.app |
Comparison: Upload Methods
| Method | Speed | Reliability | Use Case |
|---|---|---|---|
| Direct Blob | Fast | Excellent | Recommended for production |
| TUS | Medium | Best (resumable) | Unreliable networks |
| PUT to API | Slow | Good | Quick prototypes |
FAQs
How long is the upload URL valid?
24 hours from generation. If expired, request a new URL.
Can I reuse the same URL for multiple files?
No. Each URL is scoped to a specific session and file path.
What happens if upload fails?
The session remains in "new" status. Request a new upload URL and retry.
Can I upload files larger than 5GB?
The maximum file size is 5GB per upload.
Do I need to call /upload-complete?
Yes! The API doesn't know upload is done until you call this endpoint.
Can I upload while transcription is running?
No. Each session processes one file. Create multiple sessions for parallel uploads.