The Templates endpoint allows you to retrieve workflow templates from your Storyteller tenant. Workflow templates define reusable configurations for content processing with customizable properties and parameters.
{"templates":[{"code":"video-to-story","title":"Video to Story Template","previewImageUrl":"https://media.usestoryteller.com/templates/video-story-preview.jpg","properties":[{"key":"title","remarks":"The title for the story","type":"string","isOptional":false},{"key":"storyId","remarks":"ID of the story to add content to","type":"string","isOptional":false},{"key":"category","remarks":"Category to assign to the content","type":"string","isOptional":true},{"key":"autoPublish","remarks":"Whether to automatically publish the content","type":"boolean","isOptional":true}]},{"code":"image-slideshow","title":"Image Slideshow Template","previewImageUrl":"https://media.usestoryteller.com/templates/slideshow-preview.jpg","properties":[{"key":"title","remarks":"The title for the slideshow","type":"string","isOptional":false},{"key":"duration","remarks":"Duration per slide in seconds","type":"number","isOptional":true},{"key":"transition","remarks":"Transition effect between slides","type":"string","isOptional":true}]}],"pageSize":10,"currentPage":1,"totalPages":1}
constfetch=require('node-fetch');asyncfunctiongetTemplates(searchText='',currentPage=1,pageSize=10,sort=''){constparams=newURLSearchParams({...(searchText&&{searchText}),currentPage:currentPage.toString(),pageSize:pageSize.toString(),...(sort&&{sort})});try{constresponse=awaitfetch(`https://integrations.usestoryteller.com/api/templates?${params}`,{method:'GET',headers:{'x-storyteller-api-key':process.env.STORYTELLER_API_KEY}});if(!response.ok){consterrorData=awaitresponse.json();thrownewError(`HTTP ${response.status}: ${errorData.detail}`);}constdata=awaitresponse.json();returndata;}catch(error){console.error('Error fetching templates:',error);throwerror;}}// Usage examplesasyncfunctionexamples(){// Get all templatesconstallTemplates=awaitgetTemplates();console.log(`Found ${allTemplates.templates.length} templates`);// Search for video templatesconstvideoTemplates=awaitgetTemplates('video',1,20);console.log(`Found ${videoTemplates.templates.length} video templates`);// Get templates sorted alphabeticallyconstsortedTemplates=awaitgetTemplates('',1,50,'AlphabeticalAsc');console.log(`Retrieved ${sortedTemplates.templates.length} templates sorted alphabetically`);// Analyze template propertiesallTemplates.templates.forEach(template=>{console.log(`Template: ${template.title} (${template.code})`);console.log('Required properties:',template.properties.filter(p=>!p.isOptional).map(p=>p.key));console.log('Optional properties:',template.properties.filter(p=>p.isOptional).map(p=>p.key));});}
importrequestsimportosfromurllib.parseimporturlencodedefget_templates(search_text='',current_page=1,page_size=10,sort=''):url='https://integrations.usestoryteller.com/api/templates'headers={'x-storyteller-api-key':os.environ.get('STORYTELLER_API_KEY')}params={'currentPage':current_page,'pageSize':page_size}ifsearch_text:params['searchText']=search_textifsort:params['sort']=sorttry:response=requests.get(url,headers=headers,params=params)response.raise_for_status()data=response.json()returndataexceptrequests.exceptions.RequestExceptionase:print(f'Error fetching templates: {e}')ifhasattr(e.response,'json'):print(f'Error details: {e.response.json()}')raise# Usage examplestry:# Get all templatesall_templates=get_templates()print(f'Found {len(all_templates["templates"])} templates')# Search for video templatesvideo_templates=get_templates(search_text='video',page_size=20)print(f'Found {len(video_templates["templates"])} video templates')# Get templates sorted alphabeticallysorted_templates=get_templates(page_size=50,sort='AlphabeticalAsc')print(f'Retrieved {len(sorted_templates["templates"])} templates sorted alphabetically')# Analyze template propertiesfortemplateinall_templates['templates']:print(f'Template: {template["title"]} ({template["code"]})')required_props=[p['key']forpintemplate['properties']ifnotp['isOptional']]optional_props=[p['key']forpintemplate['properties']ifp['isOptional']]print(f'Required properties: {required_props}')print(f'Optional properties: {optional_props}')exceptExceptionase:print(f'Failed to fetch templates: {e}')
usingSystem;usingSystem.Net.Http;usingSystem.Threading.Tasks;usingSystem.Collections.Generic;usingNewtonsoft.Json;publicclassTemplatesClient{privatereadonlyHttpClient_httpClient;privatereadonlystring_baseUrl="https://integrations.usestoryteller.com";publicTemplatesClient(stringapiKey){_httpClient=newHttpClient();_httpClient.DefaultRequestHeaders.Add("x-storyteller-api-key",apiKey);}publicasyncTask<TemplatesResponse>GetTemplatesAsync(stringsearchText="",intcurrentPage=1,intpageSize=10,stringsort=""){try{varqueryParams=newList<string>{$"currentPage={currentPage}",$"pageSize={pageSize}"};if(!string.IsNullOrEmpty(searchText)){queryParams.Add($"searchText={Uri.EscapeDataString(searchText)}");}if(!string.IsNullOrEmpty(sort)){queryParams.Add($"sort={sort}");}varqueryString=string.Join("&",queryParams);varresponse=await_httpClient.GetAsync($"{_baseUrl}/api/templates?{queryString}");response.EnsureSuccessStatusCode();varresponseContent=awaitresponse.Content.ReadAsStringAsync();vartemplates=JsonConvert.DeserializeObject<TemplatesResponse>(responseContent);returntemplates;}catch(HttpRequestExceptionex){thrownewException($"Error fetching templates: {ex.Message}",ex);}}}publicclassTemplatesResponse{publicWorkflowTemplate[]Templates{get;set;}publicintPageSize{get;set;}publicintCurrentPage{get;set;}publicintTotalPages{get;set;}}publicclassWorkflowTemplate{publicstringCode{get;set;}publicstringTitle{get;set;}publicstringPreviewImageUrl{get;set;}publicTemplateProperty[]Properties{get;set;}}publicclassTemplateProperty{publicstringKey{get;set;}publicstringRemarks{get;set;}publicstringType{get;set;}publicboolIsOptional{get;set;}}// Usagevarclient=newTemplatesClient(Environment.GetEnvironmentVariable("STORYTELLER_API_KEY"));try{// Get all templatesvarallTemplates=awaitclient.GetTemplatesAsync();Console.WriteLine($"Found {allTemplates.Templates.Length} templates");// Search for video templatesvarvideoTemplates=awaitclient.GetTemplatesAsync("video",1,20);Console.WriteLine($"Found {videoTemplates.Templates.Length} video templates");// Get templates sorted alphabeticallyvarsortedTemplates=awaitclient.GetTemplatesAsync("",1,50,"AlphabeticalAsc");Console.WriteLine($"Retrieved {sortedTemplates.Templates.Length} templates sorted alphabetically");// Analyze template propertiesforeach(vartemplateinallTemplates.Templates){Console.WriteLine($"Template: {template.Title} ({template.Code})");varrequiredProps=template.Properties.Where(p=>!p.IsOptional).Select(p=>p.Key);varoptionalProps=template.Properties.Where(p=>p.IsOptional).Select(p=>p.Key);Console.WriteLine($"Required properties: {string.Join(",", requiredProps)}");Console.WriteLine($"Optional properties: {string.Join(",", optionalProps)}");}}catch(Exceptionex){Console.WriteLine($"Error: {ex.Message}");}
# Get all templates (first page)curl-XGET"https://integrations.usestoryteller.com/api/templates"\-H"x-storyteller-api-key: your-api-key-here"# Search for video templatescurl-XGET"https://integrations.usestoryteller.com/api/templates?searchText=video&pageSize=20"\-H"x-storyteller-api-key: your-api-key-here"# Get templates sorted alphabeticallycurl-XGET"https://integrations.usestoryteller.com/api/templates?sort=AlphabeticalAsc&pageSize=50"\-H"x-storyteller-api-key: your-api-key-here"# Get second page of templatescurl-XGET"https://integrations.usestoryteller.com/api/templates?currentPage=2&pageSize=10"\-H"x-storyteller-api-key: your-api-key-here"
Templates provide the structure for workflow execution. Use template information to build proper metadata:
// 1. Get template informationconsttemplatesData=awaitgetTemplates();constvideoTemplate=templatesData.templates.find(t=>t.code==='video-to-story');// 2. Build metadata based on template propertiesfunctionbuildMetadataFromTemplate(template,userValues){constmetadata={};template.properties.forEach(property=>{if(userValues[property.key]!==undefined){// Convert value based on property typeswitch(property.type){case'boolean':metadata[property.key]=Boolean(userValues[property.key]);break;case'number':metadata[property.key]=Number(userValues[property.key]);break;default:metadata[property.key]=String(userValues[property.key]);}}elseif(!property.isOptional){thrownewError(`Required property '${property.key}' is missing`);}});returnmetadata;}// 3. Create metadata from templateconstuserValues={title:'My Product Demo',storyId:'story-123',category:'products',autoPublish:true};constmetadata={'https://example.com/video.mp4':buildMetadataFromTemplate(videoTemplate,userValues)};// 4. Execute workflow with template-based metadataawaitexecuteWorkflow([videoTemplate.code],['https://example.com/video.mp4'],metadata);
functionvalidateTemplateMetadata(template,metadata){consterrors=[];constprovidedKeys=Object.keys(metadata);// Check required propertiestemplate.properties.forEach(property=>{if(!property.isOptional&&!providedKeys.includes(property.key)){errors.push(`Missing required property: ${property.key}`);}// Type validationif(metadata[property.key]!==undefined){constvalue=metadata[property.key];constexpectedType=property.type;switch(expectedType){case'boolean':if(typeofvalue!=='boolean'){errors.push(`Property '${property.key}' must be a boolean`);}break;case'number':if(typeofvalue!=='number'||isNaN(value)){errors.push(`Property '${property.key}' must be a number`);}break;case'string':if(typeofvalue!=='string'){errors.push(`Property '${property.key}' must be a string`);}break;}}});returnerrors;}// Usageconsterrors=validateTemplateMetadata(videoTemplate,userValues);if(errors.length>0){console.error('Validation errors:',errors);}else{console.log('Metadata is valid for template');}
functiongenerateFormFromTemplate(template){console.log(`Template: ${template.title}`);console.log('Required fields:');template.properties.forEach(property=>{constrequired=property.isOptional?' (optional)':' (required)';console.log(`- ${property.key} (${property.type})${required}: ${property.remarks}`);});}// Generate form structure for all templatesasyncfunctiongenerateForms(){consttemplatesData=awaitgetTemplates();templatesData.templates.forEach(template=>{generateFormFromTemplate(template);console.log('---');});}
asyncfunctiongetAllTemplates(){letallTemplates=[];letcurrentPage=1;lettotalPages=1;do{constresponse=awaitgetTemplates('',currentPage,50);allTemplates.push(...response.templates);totalPages=response.totalPages;currentPage++;}while(currentPage<=totalPages);returnallTemplates;}// UsageconstallTemplates=awaitgetAllTemplates();console.log(`Retrieved ${allTemplates.length} total templates`);
{"status":401,"type":"https://datatracker.ietf.org/doc/html/rfc7235#section-3.1","title":"Unauthorized","detail":"No valid API key provided","instance":""}
{"status":400,"type":"https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1","title":"Bad Request","detail":"Invalid page size. Must be between 1 and 100","instance":""}
For a complete working example that demonstrates how to build a form interface for handling template metadata and properties, see the Storyteller Sample Integration repository.
This Next.js application shows:
Template Properties Handling: Dynamically generating form fields based on template properties
Metadata Collection: Building metadata objects from user input
Form Validation: Handling required vs optional template properties
Workflow Execution: Submitting templates with metadata to the Integration API
Key files to examine:
src/api/requests.ts - API integration methods for templates and workflows
src/components/PublishToStoryteller/ - Complete form implementation