Skip to content

Content Bank Assets API#

The Content Bank Assets endpoints allow you to retrieve media assets from your Storyteller content bank. The content bank stores processed media files with metadata, thumbnails, and processing status information.

Endpoints#

Get All Content Bank Assets#

GET https://integrations.usestoryteller.com/api/content-bank-assets

Get Content Bank Asset by External ID#

GET https://integrations.usestoryteller.com/api/content-bank-assets/{externalId}

Headers#

Header Required Description
x-storyteller-api-key Yes Your API key for authentication

Get All Assets#

Query Parameters#

Parameter Type Required Default Description
searchText string No - Filter assets by title
currentPage integer No 1 Page number for pagination
pageSize integer No 10 Number of items per page (max 500)
sort string No - Sort order: AlphabeticalAsc, LastModifiedDesc, CreatedDesc

Response (200 OK)#

{
  "contentBankAssets": [
    {
      "id": "3e9444d1-1a21-4d3e-cbdc-3a0986ec9838",
      "externalId": "video-001",
      "title": "Product Demo Video",
      "type": "Video",
      "assetType": "UserGenerated",
      "width": 1920,
      "height": 1080,
      "mimeType": "video/mp4",
      "duration": 45.5,
      "assetUrl": "https://media.usestoryteller.com/assets/video-001.mp4",
      "playcardUrl": "https://media.usestoryteller.com/assets/video-001-thumbnail.jpg",
      "processing": false,
      "hidden": false,
      "hasError": false,
      "createdAt": "2024-03-01T10:30:00Z",
      "updatedAt": "2024-03-01T10:35:00Z",
      "cmsUrl": "https://yourtenant.usestoryteller.com/content-bank/video-001/form",
      "categories": [
        {
          "title": "Products",
          "externalId": "products"
        }
      ]
    }
  ],
  "pageSize": 10,
  "currentPage": 1,
  "totalPages": 1
}

Get Asset by External ID#

Path Parameters#

Parameter Type Required Description
externalId string Yes The external ID of the content bank asset

Response (200 OK)#

Returns a single content bank asset object with the same structure as shown above.

Response (404 Not Found)#

{
  "status": 404,
  "type": "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4",
  "title": "Not Found",
  "detail": "Content bank asset with externalId video-001 not found",
  "instance": ""
}

Response Fields#

Content Bank Asset Object#

Field Type Description
id string Unique asset identifier
externalId string External identifier for the asset
title string Display title of the asset
type string Asset resource type: Image, Video, Audio
assetType string Studio asset type: UserGenerated, Stock, Template
width integer Asset width in pixels (for images/videos)
height integer Asset height in pixels (for images/videos)
mimeType string MIME type of the asset
duration number Duration in seconds (for video/audio assets)
assetUrl string Direct URL to the processed asset file
playcardUrl string URL to the thumbnail/preview image
processing boolean Whether the asset is currently being processed
hidden boolean Whether the asset is hidden from public access
hasError boolean Whether the asset encountered processing errors
createdAt string ISO timestamp when asset was created
updatedAt string ISO timestamp when asset was last updated
cmsUrl string URL to edit the asset in Storyteller CMS
categories array Array of category objects assigned to the asset

Category Object#

Field Type Description
title string Category display name
externalId string External identifier for the category

Pagination Object (for list endpoint)#

Field Type Description
pageSize integer Number of items per page
currentPage integer Current page number
totalPages integer Total number of pages available

Code Examples#

Get All Content Bank Assets#

const fetch = require('node-fetch');

async function getContentBankAssets(searchText = '', currentPage = 1, pageSize = 10, sort = '') {
  const params = new URLSearchParams({
    ...(searchText && { searchText }),
    currentPage: currentPage.toString(),
    pageSize: pageSize.toString(),
    ...(sort && { sort })
  });

  try {
    const response = await fetch(`https://integrations.usestoryteller.com/api/content-bank-assets?${params}`, {
      method: 'GET',
      headers: {
        'x-storyteller-api-key': process.env.STORYTELLER_API_KEY
      }
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(`HTTP ${response.status}: ${errorData.detail}`);
    }

    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Error fetching content bank assets:', error);
    throw error;
  }
}

async function getContentBankAssetByExternalId(externalId) {
  try {
    const response = await fetch(`https://integrations.usestoryteller.com/api/content-bank-assets/${externalId}`, {
      method: 'GET',
      headers: {
        'x-storyteller-api-key': process.env.STORYTELLER_API_KEY
      }
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(`HTTP ${response.status}: ${errorData.detail}`);
    }

    const asset = await response.json();
    return asset;
  } catch (error) {
    console.error('Error fetching content bank asset:', error);
    throw error;
  }
}

// Usage examples
async function examples() {
  // Get all assets
  const allAssets = await getContentBankAssets();
  console.log(`Found ${allAssets.contentBankAssets.length} assets`);

  // Search for video assets
  const videoAssets = await getContentBankAssets('video', 1, 20);
  console.log(`Found ${videoAssets.contentBankAssets.length} video assets`);

  // Get a specific asset by external ID
  const specificAsset = await getContentBankAssetByExternalId('video-001');
  console.log(`Asset: ${specificAsset.title} (${specificAsset.type})`);

  // Filter by asset type
  const userGeneratedAssets = allAssets.contentBankAssets.filter(asset =>
    asset.assetType === 'UserGenerated'
  );
  console.log(`Found ${userGeneratedAssets.length} user-generated assets`);
}
import requests
import os
from urllib.parse import urlencode

def get_content_bank_assets(search_text='', current_page=1, page_size=10, sort=''):
    url = 'https://integrations.usestoryteller.com/api/content-bank-assets'
    headers = {
        'x-storyteller-api-key': os.environ.get('STORYTELLER_API_KEY')
    }

    params = {
        'currentPage': current_page,
        'pageSize': page_size
    }

    if search_text:
        params['searchText'] = search_text
    if sort:
        params['sort'] = sort

    try:
        response = requests.get(url, headers=headers, params=params)
        response.raise_for_status()

        data = response.json()
        return data
    except requests.exceptions.RequestException as e:
        print(f'Error fetching content bank assets: {e}')
        if hasattr(e.response, 'json'):
            print(f'Error details: {e.response.json()}')
        raise

def get_content_bank_asset_by_external_id(external_id):
    url = f'https://integrations.usestoryteller.com/api/content-bank-assets/{external_id}'
    headers = {
        'x-storyteller-api-key': os.environ.get('STORYTELLER_API_KEY')
    }

    try:
        response = requests.get(url, headers=headers)
        response.raise_for_status()

        asset = response.json()
        return asset
    except requests.exceptions.RequestException as e:
        print(f'Error fetching content bank asset: {e}')
        if hasattr(e.response, 'json'):
            print(f'Error details: {e.response.json()}')
        raise

# Usage examples
try:
    # Get all assets
    all_assets = get_content_bank_assets()
    print(f'Found {len(all_assets["contentBankAssets"])} assets')

    # Search for video assets
    video_assets = get_content_bank_assets(search_text='video', page_size=20)
    print(f'Found {len(video_assets["contentBankAssets"])} video assets')

    # Get a specific asset by external ID
    specific_asset = get_content_bank_asset_by_external_id('video-001')
    print(f'Asset: {specific_asset["title"]} ({specific_asset["type"]})')

    # Filter by asset type
    user_generated_assets = [asset for asset in all_assets['contentBankAssets']
                           if asset['assetType'] == 'UserGenerated']
    print(f'Found {len(user_generated_assets)} user-generated assets')

except Exception as e:
    print(f'Failed to fetch content bank assets: {e}')
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Collections.Generic;
using Newtonsoft.Json;

public class ContentBankAssetsClient
{
    private readonly HttpClient _httpClient;
    private readonly string _baseUrl = "https://integrations.usestoryteller.com";

    public ContentBankAssetsClient(string apiKey)
    {
        _httpClient = new HttpClient();
        _httpClient.DefaultRequestHeaders.Add("x-storyteller-api-key", apiKey);
    }

    public async Task<ContentBankAssetsResponse> GetContentBankAssetsAsync(string searchText = "", int currentPage = 1, int pageSize = 10, string sort = "")
    {
        try
        {
            var queryParams = new List<string>
            {
                $"currentPage={currentPage}",
                $"pageSize={pageSize}"
            };

            if (!string.IsNullOrEmpty(searchText))
            {
                queryParams.Add($"searchText={Uri.EscapeDataString(searchText)}");
            }

            if (!string.IsNullOrEmpty(sort))
            {
                queryParams.Add($"sort={sort}");
            }

            var queryString = string.Join("&", queryParams);
            var response = await _httpClient.GetAsync($"{_baseUrl}/api/content-bank-assets?{queryString}");
            response.EnsureSuccessStatusCode();

            var responseContent = await response.Content.ReadAsStringAsync();
            var assets = JsonConvert.DeserializeObject<ContentBankAssetsResponse>(responseContent);

            return assets;
        }
        catch (HttpRequestException ex)
        {
            throw new Exception($"Error fetching content bank assets: {ex.Message}", ex);
        }
    }

    public async Task<ContentBankAsset> GetContentBankAssetByExternalIdAsync(string externalId)
    {
        try
        {
            var response = await _httpClient.GetAsync($"{_baseUrl}/api/content-bank-assets/{externalId}");
            response.EnsureSuccessStatusCode();

            var responseContent = await response.Content.ReadAsStringAsync();
            var asset = JsonConvert.DeserializeObject<ContentBankAsset>(responseContent);

            return asset;
        }
        catch (HttpRequestException ex)
        {
            throw new Exception($"Error fetching content bank asset: {ex.Message}", ex);
        }
    }
}

public class ContentBankAssetsResponse
{
    public ContentBankAsset[] ContentBankAssets { get; set; }
    public int PageSize { get; set; }
    public int CurrentPage { get; set; }
    public int TotalPages { get; set; }
}

public class ContentBankAsset
{
    public Guid Id { get; set; }
    public string ExternalId { get; set; }
    public string Title { get; set; }
    public string Type { get; set; }
    public string AssetType { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
    public string MimeType { get; set; }
    public double Duration { get; set; }
    public string AssetUrl { get; set; }
    public string PlaycardUrl { get; set; }
    public bool Processing { get; set; }
    public bool Hidden { get; set; }
    public bool HasError { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime UpdatedAt { get; set; }
    public string CmsUrl { get; set; }
    public Category[] Categories { get; set; }
}

public class Category
{
    public string Title { get; set; }
    public string ExternalId { get; set; }
}

// Usage
var client = new ContentBankAssetsClient(Environment.GetEnvironmentVariable("STORYTELLER_API_KEY"));

try
{
    // Get all assets
    var allAssets = await client.GetContentBankAssetsAsync();
    Console.WriteLine($"Found {allAssets.ContentBankAssets.Length} assets");

    // Search for video assets
    var videoAssets = await client.GetContentBankAssetsAsync("video", 1, 20);
    Console.WriteLine($"Found {videoAssets.ContentBankAssets.Length} video assets");

    // Get a specific asset by external ID
    var specificAsset = await client.GetContentBankAssetByExternalIdAsync("video-001");
    Console.WriteLine($"Asset: {specificAsset.Title} ({specificAsset.Type})");

    // Filter by asset type
    var userGeneratedAssets = allAssets.ContentBankAssets
        .Where(a => a.AssetType == "UserGenerated")
        .ToArray();
    Console.WriteLine($"Found {userGeneratedAssets.Length} user-generated assets");
}
catch (Exception ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}
# Get all content bank assets (first page)
curl -X GET "https://integrations.usestoryteller.com/api/content-bank-assets" \
  -H "x-storyteller-api-key: your-api-key-here"

# Search for video assets
curl -X GET "https://integrations.usestoryteller.com/api/content-bank-assets?searchText=video&pageSize=20" \
  -H "x-storyteller-api-key: your-api-key-here"

# Get a specific asset by external ID
curl -X GET "https://integrations.usestoryteller.com/api/content-bank-assets/video-001" \
  -H "x-storyteller-api-key: your-api-key-here"

# Get assets sorted by creation date
curl -X GET "https://integrations.usestoryteller.com/api/content-bank-assets?sort=CreatedDesc&pageSize=50" \
  -H "x-storyteller-api-key: your-api-key-here"

Usage with Workflows#

Content bank assets can be referenced in workflow metadata:

// 1. Get available assets
const assetsData = await getContentBankAssets();
const videoAssets = assetsData.contentBankAssets.filter(asset => asset.type === 'Video');

// 2. Use asset information in workflow metadata
const workflowMetadata = {
  'https://example.com/new-video.mp4': {
    'Title': 'New Product Video',
    'baseVideoId': videoAssets[0].externalId, // Reference existing asset
    'templateAssetUrl': videoAssets[0].assetUrl
  }
};

// 3. Execute workflow with asset references
await executeWorkflow(['create-video-variation'], ['https://example.com/new-video.mp4'], workflowMetadata);

Asset Status Monitoring#

async function checkProcessingStatus(externalId) {
  const asset = await getContentBankAssetByExternalId(externalId);

  if (asset.processing) {
    console.log(`Asset ${externalId} is still processing...`);
    return 'processing';
  } else if (asset.hasError) {
    console.log(`Asset ${externalId} encountered an error during processing`);
    return 'error';
  } else {
    console.log(`Asset ${externalId} is ready: ${asset.assetUrl}`);
    return 'ready';
  }
}

// Poll for processing completion
async function waitForProcessing(externalId, maxAttempts = 30) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const status = await checkProcessingStatus(externalId);

    if (status === 'ready') {
      return await getContentBankAssetByExternalId(externalId);
    } else if (status === 'error') {
      throw new Error(`Asset processing failed: ${externalId}`);
    }

    // Wait before next check
    await new Promise(resolve => setTimeout(resolve, 5000));
  }

  throw new Error(`Asset processing timeout: ${externalId}`);
}

Filtering Assets#

async function getAssetsByType(assetType) {
  const allAssets = await getAllContentBankAssets();
  return allAssets.filter(asset => asset.type === assetType);
}

async function getAssetsByCategory(categoryExternalId) {
  const allAssets = await getAllContentBankAssets();
  return allAssets.filter(asset =>
    asset.categories.some(cat => cat.externalId === categoryExternalId)
  );
}

// Usage
const videoAssets = await getAssetsByType('Video');
const productAssets = await getAssetsByCategory('products');

Error Handling#

Common Error Responses#

{
  "status": 401,
  "type": "https://datatracker.ietf.org/doc/html/rfc7235#section-3.1",
  "title": "Unauthorized",
  "detail": "No valid API key provided",
  "instance": ""
}
{
  "status": 404,
  "type": "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4",
  "title": "Not Found",
  "detail": "Content bank asset with externalId video-001 not found",
  "instance": ""
}

Best Practices#

  1. Check Processing Status - Always verify that processing is false before using assets
  2. Handle Errors - Check the hasError flag and provide appropriate fallbacks
  3. Use External IDs - External IDs are more stable than internal IDs for referencing assets
  4. Cache Asset URLs - Asset URLs are stable and can be cached for performance
  5. Monitor Hidden Assets - Hidden assets won't appear in public content
  6. Pagination for Large Sets - Use appropriate page sizes for large asset libraries
  7. Filter Efficiently - Use search and filtering to find relevant assets quickly