Downloading Files - SuperAI Flows
Documentation Index
Fetch the complete documentation index at: /llms.txt
Use this file to discover all available pages before exploring further.
When SuperAI Flows processes documents, task outputs often include file references as gs:// URLs. These point to files stored in Google Cloud Storage, but you don’t need to understand GCS internals — the File API handles everything.
Example gs:// URL in a task output:
{
"document_url": "gs://superai-file-upload-prod-eu/flows/255a17d0-5c21-47d9-8e0b-a08b48436f0a/documents/f8230da2-4136-4ffb-acfe-db9318970ea2"
}
Prerequisites
- curl — for making HTTP requests
- jq — for parsing JSON in shell scripts (optional, but recommended)
- A SuperAI Flows API key — get one from the dashboard under Settings → API Keys
Quick start
Download a file in one command:
curl -f -L -H "X-API-Key: saf_your_api_key" \
"https://flows.super.ai/api/files/download?uri=gs://superai-file-upload-prod-eu/flows/255a17d0-5c21-47d9-8e0b-a08b48436f0a/documents/f8230da2-4136-4ffb-acfe-db9318970ea2" \
-o downloaded_file.pdf
- The
-Lflag tells curl to follow the redirect to the actual download URL. - The
-fflag makes curl fail with an error instead of saving error responses as your file.
Authentication
Both file endpoints require authentication. You can use either method:
| Method | Header | Example |
|---|---|---|
| API Key (recommended) | X-API-Key |
X-API-Key: saf_abc123... |
| JWT Token | Authorization |
Authorization: Bearer eyJhbGci... |
About API keys:
- API keys start with the
saf_prefix (e.g.,saf_org_550e8400_abc123...). - Get your API key from the dashboard under Settings → API Keys.
- Store keys in environment variables — never hardcode them in scripts.
About JWT tokens:
Obtained by authenticating with your email and password. See the API Quickstart. Tokens expire after 1 hour and must be refreshed.
Two ways to download
Option 1: Direct download (GET)
Use GET /api/files/download for the simplest approach. This endpoint redirects you to a temporary signed URL.
curl -f -L -H "X-API-Key: $SAF_API_KEY" \
"https://flows.super.ai/api/files/download?uri=gs://bucket/path/to/file" \
-o output_file.pdf
If your URI contains special characters, URL-encode it first:
ENCODED_URI=$(printf '%s' "$GS_URL" | jq -sRr @uri)
curl -f -L -H "X-API-Key: $SAF_API_KEY" \
"https://flows.super.ai/api/files/download?uri=$ENCODED_URI" -o file.pdf
| Parameter | Required | Description |
|---|---|---|
uri |
Yes | The gs:// URL from your task output (URL-encoded) |
redirect |
No | Set to false to get JSON instead of a redirect (default: true) |
Response: 302 redirect to a pre-signed download URL (valid for 1 hour).
Option 2: Resolve URL first (POST)
Use POST /api/files/resolve when you need the download URL for further processing or want to keep URIs out of server logs.
curl -X POST "https://flows.super.ai/api/files/resolve" \
-H "X-API-Key: $SAF_API_KEY" \
-H "Content-Type: application/json" \
-d '{"uri": "gs://bucket/path/to/file"}'
{
"download_url": "https://storage.googleapis.com/bucket/path/to/file?X-Goog-Algorithm=...",
"expires_at": "2025-01-15T15:00:00+00:00",
"expires_in_seconds": 3600
}
Then download using the returned URL:
curl -o output_file.pdf "https://storage.googleapis.com/bucket/path/to/file?X-Goog-Algorithm=..."
Complete example: download after flow completion
This script executes a flow, waits for completion, and downloads any output files:
#!/bin/bash
set -e
# Configuration — use environment variables for API key
API_KEY="${SAF_API_KEY:-saf_your_api_key}"
FLOW_ID="your-flow-id"
BASE_URL="https://flows.super.ai"
MAX_ATTEMPTS=60 # 5 minutes timeout (60 * 5 seconds)
# 1. Create flow execution
echo "Starting flow execution..."
EXEC_RESPONSE=$(curl -s -X POST "$BASE_URL/api/flow-executions" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "{\n \"flow_id\": \"$FLOW_ID\",\n \"input\": {\n \"filename\": \"invoice.pdf\",\n \"mime_type\": \"application/pdf\",\n \"document_url\": \"https://cdn.super.ai/invoice-example.pdf\"\n }\n }")
EXEC_ID=$(echo "$EXEC_RESPONSE" | jq -r .id)
if [ "$EXEC_ID" = "null" ] || [ -z "$EXEC_ID" ]; then
echo "Failed to create execution. Response: $EXEC_RESPONSE"
exit 1
fi
echo "Execution started: $EXEC_ID"
# 2. Wait for completion
ATTEMPT=0
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
STATUS=$(curl -s "$BASE_URL/api/flow-executions/$EXEC_ID" \
-H "X-API-Key: $API_KEY" | jq -r .status)
echo "Status: $STATUS (attempt $((ATTEMPT + 1))/$MAX_ATTEMPTS)"
if [ "$STATUS" = "completed" ]; then break
elif [ "$STATUS" = "failed" ]; then echo "Execution failed!"; exit 1; fi
ATTEMPT=$((ATTEMPT + 1))
sleep 5
done
# 3. Get task outputs
RESULTS=$(curl -s "$BASE_URL/api/task-executions?flow_execution_id=$EXEC_ID" \
-H "X-API-Key: $API_KEY")
# 4. Download any gs:// URLs from the output (requires jq)
echo "$RESULTS" | jq -r '.. | select(type == "string" and startswith("gs://"))' 2>/dev/null | while read -r GS_URL; do
if [ -n "$GS_URL" ]; then
FILENAME=$(basename "$GS_URL")
ENCODED_URI=$(printf '%s' "$GS_URL" | jq -sRr @uri)
if curl -f -L -H "X-API-Key: $API_KEY" \
"$BASE_URL/api/files/download?uri=$ENCODED_URI" -o "$FILENAME"; then
echo "Downloaded: $FILENAME"
else
echo "Failed to download: $FILENAME"
fi
fi
done
echo "Done!"
Error handling
| Status | Description | Common causes |
|---|---|---|
| 400 | Bad Request | URI doesn’t start with gs://, malformed URI, path traversal attempt |
| 401 | Unauthorized | Missing or invalid API key / token |
| 403 | Forbidden | File belongs to a different organization, invalid bucket |
| 404 | Not Found | Flow doesn’t exist, you lack access, or the file was deleted from storage |
| 500 | Server Error | Internal error generating download URL |
Example error response:
{
"error": {
"message": "Access denied: you do not have access to this file",
"code": "forbidden"
},
"request_id": "01K8KABR6S16YETA2SZPVBS9SP"
}
Include the request_id when contacting support for faster resolution.
Always use -f -L with curl on the GET endpoint: -L follows the redirect to the actual download URL, and -f makes curl return a non-zero exit code on HTTP 4xx/5xx errors instead of silently saving an error response as your output file.
Security
- Organization-scoped access — You can only download files from flows your organization owns.
- Temporary URLs — Pre-signed download URLs expire after 1 hour.
- Path validation — The API rejects path traversal attempts.
- Bucket validation — Only files from the authorized storage bucket can be accessed.
For sensitive files, prefer POST /api/files/resolve to keep URIs out of server access logs.
FAQ
What URI formats are supported?
Currently only gs:// URIs (Google Cloud Storage) are supported.
How long are download URLs valid?
Pre-signed URLs are valid for 1 hour. Request a new URL if your download fails after this time.
Can I download files from any flow?
No. You can only download files from flows that belong to your organization.
Do I need to parse the gs:// URL?
No — pass the full URI exactly as received from the task output.
Which endpoint should I use?
Use GET /api/files/download for simple downloads with curl. Use POST /api/files/resolve when you need the URL for programmatic use or want to keep URIs out of logs.
Need help? Email support@super.ai and include your request_id and flow ID.