Skip to main content

BTIG Auto-Upload Agent

Automated upload of BTIG files to Sable using the User API Key system.

Authentication

Retrieve API Key

mcpammer_secrets_get name="SABLE_API_KEY_DANIEL" environment="dev" path="/"

Key format: sk_a5b6aac152e01d55066c0a1807eb4f81

Use in Requests

-H "x-api-key: $SABLE_API_KEY"

File Locations

DirectoryPurpose
~/Downloads/BTIG/Ready To Upload/Files ready for upload
~/Downloads/BTIG/Archive/Successfully uploaded
~/Downloads/BTIG/Failed/Failed uploads (for retry)

API Endpoint

Endpoint: POST https://sable.aicholdings.com/api/storage/upload

Form Fields:

FieldRequiredDescription
fileYesThe CSV file
org_idYes00000000-0000-0000-0000-000000000001
file_typeNopnl or performance

Example:

curl -X POST "https://sable.aicholdings.com/api/storage/upload" \
-H "x-api-key: $SABLE_API_KEY" \
-F "file=@/path/to/file.csv" \
-F "org_id=00000000-0000-0000-0000-000000000001"

Upload Script

import os
import shutil
import requests

API_KEY = os.environ.get("SABLE_API_KEY")
ORG_ID = "00000000-0000-0000-0000-000000000001"
UPLOAD_URL = "https://sable.aicholdings.com/api/storage/upload"

READY_DIR = os.path.expanduser("~/Downloads/BTIG/Ready To Upload")
ARCHIVE_DIR = os.path.expanduser("~/Downloads/BTIG/Archive")
FAILED_DIR = os.path.expanduser("~/Downloads/BTIG/Failed")

def upload_file(filepath):
filename = os.path.basename(filepath)
with open(filepath, "rb") as f:
response = requests.post(
UPLOAD_URL,
headers={"x-api-key": API_KEY},
files={"file": (filename, f, "text/csv")},
data={"org_id": ORG_ID}
)
return response.status_code == 200

def process_all():
for filename in os.listdir(READY_DIR):
if not filename.endswith(".csv"):
continue
filepath = os.path.join(READY_DIR, filename)
if upload_file(filepath):
shutil.move(filepath, os.path.join(ARCHIVE_DIR, filename))
print(f"Uploaded: {filename}")
else:
shutil.move(filepath, os.path.join(FAILED_DIR, filename))
print(f"Failed: {filename}")

if __name__ == "__main__":
process_all()

Error Handling

StatusErrorAction
401Invalid API keyCheck/rotate key
403ForbiddenCheck org_id, permissions
413File too largeSplit file
500Server errorRetry with backoff

Verification

After upload:

  1. Go to Sable → Admin → File Bucket
  2. Check for new files with status "uploaded"
  3. Watch for processing to complete

Or via API:

curl "https://sable.aicholdings.com/api/storage/files?org_id=$ORG_ID" \
-H "x-api-key: $SABLE_API_KEY"