Storage
Studio endpoints that previously accepted multipart/form-data (audio transcribe, image batch) now take JSON bodies with URLs. For local files, use this endpoint to obtain a short-lived signed upload URL, PUT the bytes directly to storage, and then pass the returned fileUrlto any Studio method. This bypasses the 4.5 MB inbound body limit on the Studio function boundary.
POST /api/v1/storage/upload-url
Mint a pair of signed URLs: a 15-minute PUT URL that lets the caller upload bytes directly to GCS, and a 24-hour READ URL that Studio endpoints can fetch post-auth.
Request Body
contentTypestringrequiredMIME type of the file you're about to upload (e.g. audio/mpeg, image/png).
purposestringrequiredOne of audio, image, video, or file — decides which subdirectory the object lands in.
Example
curl -X POST https://terramind.com/api/v1/storage/upload-url \
-H "Authorization: Bearer sk-tm-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "contentType": "audio/mpeg", "purpose": "audio" }'curl -X PUT "<uploadUrl from step 1>" \
-H "Content-Type: audio/mpeg" \
--data-binary @recording.mp3curl -X POST https://terramind.com/api/v1/studio/audio/transcribe \
-H "Authorization: Bearer sk-tm-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "audioUrl": "<fileUrl from step 1>", "language": "en" }'Response
{
"id": "req_...",
"uploadUrl": "https://storage.googleapis.com/...",
"fileUrl": "https://storage.googleapis.com/...",
"storagePath": "<orgId>/direct-uploads/audio/<uuid>.mp3",
"expiresAt": 1714000000000,
"readExpiresAt": 1714086400000
}Both SDKs (@terramind/sdk and terramind) wrap this flow: pass a Blob/File (TypeScript) or raw bytes (Python) directly to audio.transcribe, or call storage.uploadFile() / storage.upload_file() explicitly when you need the fileUrl for other methods.