Skip to main content

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

Asset Lifecycle

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.

  1. Upload -- You send the file (or a URL to fetch it from). FileSpin returns an asset ID immediately.
  2. Storage -- The original file is saved to cloud storage (S3 or R2). A file-saved webhook fires.
  3. 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-processed webhook fires when complete.
  4. 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.

info

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 sizeTypical 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
warning

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

StatusMeaningAction
OKAsset saved and readyProceed normally
NOT_READYFile is being savedWait and retry
QUEUEDURL ingest is queuedWait for webhook or poll
ERRORProcessing failedCheck errors field in asset data
ARCHIVEDAsset 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

  1. Store the asset ID in your application database right after upload. This is your permanent reference to the file in FileSpin.

  2. Use webhooks over polling for production systems. Polling is fine for development, but webhooks scale better and react faster.

  3. Check status before operating on an asset. Never assume an upload is instantly available.

  4. Use on-demand transformations for images instead of pre-generating every size. This saves storage and processing time.

  5. 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