Upload, Process, Deliver: The Complete Asset Lifecycle
The end-to-end journey of an asset from upload to CDN delivery -- multipart upload, URL ingest, status polling, auto-processing, webhooks, and serving via CDN.
FileSpin is an AI-native digital asset management platform used by eCommerce retailers, event producers, attractions operators, and media companies to manage, transform, and deliver assets autonomously. Whether you're syncing product photos from a photoshoot to multiple marketplaces, processing thousands of event images for sponsor delivery, capturing guest photos at attractions, or delivering media to global audiences—understanding the asset lifecycle is essential for building integrations that scale.
Every integration with FileSpin follows the same fundamental pattern: get content in, let FileSpin process it, then serve it to your users. This guide walks through the entire pipeline so you can build a reliable, production-ready integration from day one.
How the pipeline works
When you upload a file to FileSpin, it moves through a series of stages before it's ready to serve. Understanding this pipeline is essential for building integrations that handle timing correctly and don't surprise your users with missing thumbnails or incomplete metadata.
- Upload -- You send the file (or a URL to fetch it from). FileSpin returns an asset ID immediately.
- Storage -- The original file is saved to cloud storage (S3 or R2). A
file-savedwebhook fires. - Auto-processing -- Based on your account settings, FileSpin generates image conversions, video transcodes, and runs any enabled addons (auto-tags, face recognition, etc.). A
file-processedwebhook fires when complete. - Delivery -- The asset and its derivatives are available via CDN URLs for fast, global delivery.
Step 1: Upload an asset
FileSpin supports two upload methods: direct multipart upload and URL ingest. Choose based on where your files originate.
For uploads from websites, use the File Picker Web Widget.
Multipart upload (files you have)
Use this when your application has the file -- a user-uploaded photo, a generated document, or a file from your server's filesystem.
curl -X POST "https://app.filespin.io/api/v1/assets/new/content/original/upload" \
-H "X-FileSpin-Api-Key: YOUR_API_KEY" \
-F "file=@product-photo.jpg"
Response:
{
"assets": [
{
"id": "a1b2c3d4e5f6789012345678abcdef90",
"status": "NOT_READY",
"name": "product-photo.jpg",
"size": 2456789,
"checksum": "d41d8cd98f00b204e9800998ecf8427e",
"content_type": "image/jpeg"
}
]
}
You can upload multiple files in a single request by using file1, file2, etc. as form field names.
Attaching metadata at upload time
You can include custom metadata in the same upload request. This is useful when your application has context about the file (e.g. which product it belongs to, who approved it, what campaign it's for):
curl -X POST "https://app.filespin.io/api/v1/assets/new/content/original/upload" \
-H "X-FileSpin-Api-Key: YOUR_API_KEY" \
-F "file=@product-photo.jpg" \
-F 'custom_metadata={"data": {"project": "Summer Campaign", "status": "draft"}, "data_schema_id=1"}'
data_schema_id is the optional ID of asset schema that powers custom searches and other powerful automations. See the post on Asset Schemas for more.*
URL ingest (files hosted elsewhere)
Use this when the file already lives at a URL -- an image on a partner's CDN, a video on a content server, or an object in an S3 bucket.
curl -X POST "https://app.filespin.io/api/v1/assets/new/content/original/external" \
-H "X-FileSpin-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "interview.mp4",
"key": "https://example.com/videos/interview.mp4"
}'
For S3 objects, use the s3:// protocol:
curl -X POST "https://app.filespin.io/api/v1/assets/new/content/original/external" \
-H "X-FileSpin-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "interview.mp4",
"key": "s3://my-bucket/path/to/file.mp4"
}'
URL ingests are asynchronous -- FileSpin queues the download and returns a QUEUED status. The file will be fetched in the background.
The URL provided should allow direct downloads without any authorization. If S3 URL is provided, make sure the bucket is accessible for FileSpin (See Custom S3 Storage Setup in the docs).
Step 2: Check asset status
After upload, the asset status is NOT_READY while the file is being saved to storage. You need to wait for it to become OK before performing further operations.
Polling for readiness
curl "https://app.filespin.io/api/v1/assets/a1b2c3d4e5f6789012345678abcdef90/data" \
-H "X-FileSpin-Api-Key: YOUR_API_KEY"
Response when ready:
status will be OK
{
"id": "a1b2c3d4e5f6789012345678abcdef90",
"status": "OK",
"name": "product-photo.jpg",
"size": 2456789,
"content_type": "image/jpeg",
"metadata": {
"width": 4000,
"height": 3000
},
"conversions": {},
"addons_info": {
"ON_DEMAND_IMAGE": {
"available": true
}
}
}
Timing guidelines:
| File size | Typical wait |
|---|---|
| Small files (< 50 MB) | A few hundred milliseconds |
| Large files (50 MB -- 1 GB) | A few seconds |
| Very large files (1 GB+) | Several seconds |
Always check status is OK before attempting to access the asset or trigger processing. Attempting to process a NOT_READY asset will fail.
Using webhooks instead of polling
Polling works for simple integrations, but webhooks are more efficient at scale. Configure a webhook URL in your account settings to receive file-saved notifications automatically. See the Webhooks in Integrations docs for the complete setup.
Step 3: Understand auto-processing
Once the file is saved, FileSpin automatically processes it based on your account settings. This includes:
- Image conversions -- Smart imaging for on-demand transformations (ODI)
- Video transcodes -- Multiple resolutions (360p, 480p, 720p, 1080p) and HLS adaptive streaming
- Addons -- Auto-tags, face recognition, etc
Triggering processing manually
If you need specific processing that isn't enabled by default, or you want to reprocess an asset:
curl -X POST "https://app.filespin.io/api/v1/assets/a1b2c3d4e5f6789012345678abcdef90/process" \
-H "X-FileSpin-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"keys": ["smart_imaging", "720p-video", "1080p-video", "hls-video"]
}'
Refer to the Asset Processing docs for all the valid processing keys that can be used.
For video processing, the response includes a job_id that you can use to track progress. Processing completion is also notified via webhooks.
Step 4: Serve assets via CDN
Once processing is complete, your assets are ready for delivery through FileSpin's global CDN.
Serving images with on-demand transformations
Once ON_DEMAND_IMAGE processing is complete (usually within a second or two), you can serve images with real-time transformations via URL parameters:
https://cdn.filespin.io/api/v1/assets/ASSET_ID/conversions?resize=800,600&quality=85
This resizes to 800x600 and compresses to quality 85 -- all on the fly, cached at the CDN edge.
See the Image Transformations Docs for the full transformation reference.
Serving video transcodes
Video transcodes are available through the get_link API:
curl "https://app.filespin.io/api/v1/assets/ASSET_ID/get_link?key=720p-video&link_type=cdn&delivery=display" \
-H "X-FileSpin-Api-Key: YOUR_API_KEY"
The response includes a signed CDN URL you can use directly in a video player or embed tag:
{
"url": "https://cdn.filespin.io/api/v1/assets/ASSET_ID/transcodes/720p-video.mp4?expiry=..."
}
For public videos, you can also construct the URL directly: https://cdn.filespin.io/api/v1/assets/ASSET_ID/transcodes/720p-video.mp4
Public vs. private assets
By default, assets are private except for on-demand images. Private files require authentication to access. For public-facing content, you can make individual assets public using the set_public_access API:
curl -X POST "https://app.filespin.io/api/v1/assets/ASSET_ID/content/set_public_access" \
-H "X-FileSpin-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"keys": ["original", "720p-video"]
}'
For private assets that need temporary access (e.g. serving to authenticated users on your website), use the get_link API with signed URLs:
curl "https://app.filespin.io/api/v1/assets/ASSET_ID/get_link?key=original&expiry=3600" \
-H "X-FileSpin-Api-Key: YOUR_API_KEY"
This returns a signed URL valid for 3600 seconds (1 hour).
Replacing asset content
Sometimes you need to update the file while keeping the same asset ID -- for example, when a designer revises a photo but you want to preserve all the metadata and the reference in your application.
curl -X POST "https://app.filespin.io/api/v1/assets/ASSET_ID/content/original/replace" \
-H "X-FileSpin-Api-Key: YOUR_API_KEY" \
-F "file=@updated-product-photo.jpg"
The asset ID stays the same, but the content is replaced. All conversions and transcodes will be regenerated based on accoount settings.
Error handling
Common status values
| Status | Meaning | Action |
|---|---|---|
OK | Asset saved and ready | Proceed normally |
NOT_READY | File is being saved | Wait and retry |
QUEUED | URL ingest is queued | Wait for webhook or poll |
ERROR | Processing failed | Check errors field in asset data |
ARCHIVED | Asset is archived (read-only) | Cannot modify, only read |
Handling errors in the asset data
When something goes wrong, the errors field in the asset data provides details:
{
"id": "a1b2c3d4e5f6789012345678abcdef90",
"status": "ERROR",
"errors": {
"original": "Original file appears to be invalid!"
}
}
Warnings (non-fatal issues) are also reported:
{
"errors": {
"warning": "This may be a PNG file uploaded as JPG!"
}
}
Putting it all together
Here's a complete Python example that uploads an image, waits for it to be ready, and builds a CDN URL for serving:
import requests
import time
API_KEY = "YOUR_API_KEY"
API_BASE = "https://app.filespin.io/api/v1"
CDN_BASE = "https://cdn.filespin.io/api/v1"
HEADERS = {"X-FileSpin-Api-Key": API_KEY}
# 1. Upload the file
with open("product-photo.jpg", "rb") as f:
resp = requests.post(
f"{API_BASE}/assets/new/content/original/upload",
headers=HEADERS,
files={"file": f}
)
asset_id = resp.json()["assets"][0]["id"]
print(f"Uploaded: {asset_id}")
# 2. Wait for asset to be ready
for _ in range(30):
resp = requests.get(
f"{API_BASE}/assets/{asset_id}/data",
headers=HEADERS
)
data = resp.json()
if data["status"] == "OK":
break
time.sleep(1)
else:
raise TimeoutError("Asset did not become ready in time")
# 3. Build a CDN URL with transformations
thumbnail_url = (
f"{CDN_BASE}/assets/{asset_id}/conversions"
f"?resize=400,300&quality=80"
)
print(f"Thumbnail URL: {thumbnail_url}")
Best practices
-
Store the asset ID in your application database right after upload. This is your permanent reference to the file in FileSpin.
-
Use webhooks over polling for production systems. Polling is fine for development, but webhooks scale better and react faster.
-
Check status before operating on an asset. Never assume an upload is instantly available.
-
Use on-demand transformations for images instead of pre-generating every size. This saves storage and processing time.
-
Enable auto-processing for videos in your account settings for the transcodes you regularly need, so every video upload is processed for transcodes automatically.
Next steps
- Organizing assets with custom metadata schemas -- Add structured, searchable metadata
- Real-time notifications with webhooks -- React to asset events automatically
- On-demand image transformations -- Serve optimized images
- Video transcoding and HLS streaming -- Process and stream video