Add Clip#
Creates Clips from source media. Use when you want Storyteller to ingest a media URL and create a Clip with optional publish status, categories, collections, thumbnail, and action links.
Clips are created as Published by default. Set the optional per-media PublishStatus metadata to Draft when a Clip needs editorial review, or to Scheduled when it should only be viewer-facing during a defined availability window.
- Workflow ID:
add-clip
Basic Usage#
Minimal Example Request#
{
"workflows": [
"add-clip"
],
"mediaUrls": [
"https://cdn.example.com/videos/highlight-001.mp4"
],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight"
}
}
}
Because PublishStatus is omitted, this request creates a Published Clip.
Required Metadata#
| Key | Type | Required | Remarks |
|---|---|---|---|
Title |
string | Yes | Per-media. Clip title used internally. |
Minimal Example Request with Optional Metadata#
{
"workflows": [
"add-clip"
],
"mediaUrls": [
"https://cdn.example.com/videos/highlight-001.mp4"
],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"DisplayTitle": "Highlight",
"CreationTime": "2025-10-26T11:41:15+00:00",
"PublishStatus": "Draft"
}
}
}
Optional Basic Metadata#
| Key | Type | Required | Remarks |
|---|---|---|---|
DisplayTitle |
string | No | Per-media. Display title shown for the clip. If not provided, defaults to Title. |
CreationTime |
DateTime | No | Per-media. ISO 8601 creation time; defaults to current time if omitted. |
PublishStatus |
string | No | Per-media. Exact supported values are Draft, Published, and Scheduled. Defaults to Published when omitted or blank. |
AvailableFrom |
DateTimeOffset | No | Per-media. Inclusive start of the availability window as an ISO 8601 date/time with an offset. Required when PublishStatus is Scheduled. |
AvailableUntil |
DateTimeOffset or null | No | Per-media. Optional exclusive end of the availability window as an ISO 8601 date/time with an offset. Must be later than AvailableFrom. |
Creating a Draft Clip#
Use Draft when the Clip should be fully ingested and available to authorized CMS editors without appearing in published Clip feeds or viewer search. It becomes viewer-facing only after it is published.
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"PublishStatus": "Draft"
}
}
}
Values are case-sensitive. Values other than Draft, Published, and Scheduled are rejected.
Scheduling a Clip#
Availability scheduling must be enabled for the tenant. Use Scheduled with an AvailableFrom value and, optionally, an AvailableUntil value:
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"PublishStatus": "Scheduled",
"AvailableFrom": "2026-08-04T18:00:00+01:00",
"AvailableUntil": "2026-08-05T00:00:00+01:00"
}
}
}
The window is half-open: the Clip is available at exactly AvailableFrom and unavailable at exactly AvailableUntil. AvailableUntil can be omitted for a schedule with no automatic expiry. Supplied offsets describe an instant and are normalized by Storyteller.
The scheduling feature is checked during tenant-aware workflow processing. If it is not enabled, metadata validation can succeed but the workflow step fails before the Clip is created or updated; use the workflow status endpoint to observe that failure.
Availability fields are only accepted with an explicit PublishStatus of Scheduled. When updating an existing Clip:
- omitting or leaving
PublishStatusblank preserves its editorial status and availability dates; ScheduledreplacesAvailableFrom; omittingAvailableUntilpreserves the existing end date, while setting it tonullclears the end date;Publishedpublishes immediately and clears both availability dates; andDraftremoves the Clip from viewer-facing results but retains its availability dates for a later explicit reschedule.
cURL Example (Basic)#
curl -X POST "https://integrations.usestoryteller.com/api/workflows/execute" \
-H "x-storyteller-api-key: $ST_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<'JSON'
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"DisplayTitle": "Derby Day: 90s Highlight"
}
}
}
JSON
Advanced Usage#
Clips can be created with additional metadata to set up more properties to work with optional categories, collections, thumbnail, and action links.
External Identifiers#
Track clips using your own external identifier system:
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"ExternalId": "ext-clip-001"
}
}
}
Metadata:
| Key | Type | Remarks |
|---|---|---|
ExternalId |
string | External identifier for the clip asset that can be used for future reference. |
Action Links#
Associate primary and secondary action links with clips:
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"PrimaryActionLinkId": "987ce210-0f79-404b-bd0a-5d6e67b58d3c",
"SecondaryActionLinkIds": [
"6df128ea-8aaa-4160-ae6e-382c1bf9727f",
"d78234c3-16f7-4883-b499-14eeaacd87b8"
]
}
}
}
Metadata:
| Key | Type | Remarks |
|---|---|---|
PrimaryActionLinkId |
Guid | Primary action link associated with the clip. Must be a valid GUID of an existing action link. |
SecondaryActionLinkIds |
ArrayOf(Guid) | Additional action links. Each must be a valid GUID of an existing action link. |
Categories#
Using Existing Categories (by External ID)#
Both CategoryIds and Categories can be used to specify categories by their External IDs.
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"CategoryIds": ["premier-league", "featured"]
}
}
}
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"Categories": [
{
"ExternalId": "premier-league"
},
{
"ExternalId": "featured"
}
]
}
}
}
Creating New Categories#
To create a new category all of it's properties must be specified in Categories:
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"Categories": [
{
"ExternalId": "premier-league",
"DisplayTitle": "Premier League",
"InternalTitle": "PL",
"AvailableForNavigation": true,
"ShowInClips": false,
"Type": "Other"
}
]
}
}
}
When creating a new category the following must be true:
ExternalIdis required and must be uniqueInternalTitlewill default toExternalIdif not provided, but must be unique in the systemDisplayTitleis optional (defaults toInternalTitleif not provided)ShowInClipsmust be set tofalse
Metadata:
| Key | Type | Remarks |
|---|---|---|
CategoryIds |
ArrayOf(string) | Category external IDs to associate with the clip. Categories must already exist. |
Categories |
ArrayOf(object) | Rich category objects for creating or referencing categories. |
Category Object Properties:
| Property | Type | Required | Remarks |
|---|---|---|---|
ExternalId |
string | Yes | Unique external identifier for the category. |
DisplayTitle |
string | No | Display title shown to users. |
InternalTitle |
string | No | Internal title for CMS use. Defaults to ExternalId if not provided. |
AvailableForNavigation |
bool | No | Whether category appears in navigation. Defaults to false. |
ShowInClips |
bool | No | Whether category is shown in clips list. Defaults to false. Currently only false is supported. |
Type |
string | No | Category type (e.g., "Other", "Player"). |
Collections#
Using Existing Collections (by Internal ID)#
Existing Collections can be referenced by their Internal ID specified in the Collections array:
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"Collections": [
{
"InternalId": "coll-100"
}
]
}
}
}
Creating New Collections#
Editorial collections can be created by specifying the type accordingly:
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"Collections": [
{
"InternalId": "coll-100",
"InternalTitle": "Season 2025 Highlights",
"DisplayTitle": "Season '25 Highlights",
"Type": "Editorial"
}
]
}
}
}
CategoryBased collections require the CategoryExternalId to be pointing to an existing Category by its External ID. In the following example the existing Category is also added to the Clip so it'll be included in the Collection from the Category.
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"Categories": [
{
"ExternalId": "premier-league"
}
],
"Collections": [
{
"InternalId": "coll-100",
"InternalTitle": "Season 2025 Highlights",
"DisplayTitle": "Season '25 Highlights",
"Type": "CategoryBased",
"CategoryExternalId": "premier-league"
}
]
}
}
}
Metadata:
| Key | Type | Remarks |
|---|---|---|
Collections |
ArrayOf(object) | Collections to associate the clip with. |
Collection Object Properties:
| Property | Type | Required | Remarks |
|---|---|---|---|
InternalId |
string | Yes* | Unique internal identifier. |
InternalTitle |
string | No | Internal title for CMS use. Defaults to InternalId. |
DisplayTitle |
string | No | Display title shown to users. Truncated to max length if needed. |
Type |
string | Yes | Collection type: "Editorial" or "CategoryBased". Editorial collections associate clips directly while Category Based collections include Clips when added to the category. |
CategoryExternalId |
string | No | Links collection to a category. Required when creating a category-based collection. |
Item Metadata#
Add arbitrary key-value metadata to clips:
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"ItemMetadata": {
"editor": "jdoe",
"series": "Derby Day",
"publisher_name": "CNN",
"production_date": "2025-10-01"
}
}
}
}
Metadata:
| Key | Type | Remarks |
|---|---|---|
ItemMetadata |
object | Arbitrary key-value pairs stored as clip metadata. Useful for tracking custom fields. |
Special Metadata Keys:
publisher_name: "CNN"- When set to "CNN", uses frame 2 for thumbnail generation to avoid text overlays.
Custom Thumbnails#
Static Thumbnail URL#
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"ThumbnailUrl": "https://cdn.example.com/images/highlight-001-thumb.jpg"
}
}
}
Template-Based Thumbnail#
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"ThumbnailTemplate": "thumb-template-01",
"TemplateMetadata": {
"style": "bold",
"watermark": "on"
}
}
}
}
Template with Custom Thumbnail#
{
"workflows": ["add-clip"],
"mediaUrls": ["https://cdn.example.com/videos/highlight-001.mp4"],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"ThumbnailUrl": "https://cdn.example.com/images/highlight-001-thumb.jpg",
"ThumbnailTemplate": "thumb-template-01",
"TemplateMetadata": {
"overlay": "team-logo"
}
}
}
}
Metadata:
| Key | Type | Remarks |
|---|---|---|
ThumbnailUrl |
string | Must be an absolute URL. Used as custom thumbnail or as base image for template. |
ThumbnailTemplate |
string | Thumbnail Template ID to apply. Can be used alone (uses auto-generated thumbnail) or with ThumbnailUrl. |
TemplateMetadata |
object | Template-specific key-value pairs passed to the template processor. |
Thumbnail Processing Behavior:
ThumbnailUrlonly: Sets custom thumbnail directlyThumbnailTemplateonly: Applies template to auto-generated thumbnail from video- Both: Applies template to provided custom thumbnail URL
Complete Advanced Example#
{
"workflows": ["add-clip"],
"mediaUrls": [
"https://cdn.example.com/videos/highlight-001.mp4"
],
"metadata": {
"https://cdn.example.com/videos/highlight-001.mp4": {
"Title": "Derby Day Highlight",
"DisplayTitle": "Derby Day: 90s Highlight",
"PublishStatus": "Draft",
"ExternalId": "ext-clip-001",
"ItemMetadata": {
"editor": "jdoe",
"series": "Derby Day",
"publisher_name": "CNN"
},
"PrimaryActionLinkId": "987ce210-0f79-404b-bd0a-5d6e67b58d3c",
"SecondaryActionLinkIds": [
"6df128ea-8aaa-4160-ae6e-382c1bf9727f",
"d78234c3-16f7-4883-b499-14eeaacd87b8"
],
"CategoryIds": ["premier-league", "featured"],
"Categories": [
{
"ExternalId": "premier-league",
"DisplayTitle": "Premier League",
"InternalTitle": "PL",
"AvailableForNavigation": true,
"ShowInClips": false,
"Type": "Other"
}
],
"Collections": [
{
"InternalId": "coll-100",
"InternalTitle": "Season 2025 Highlights",
"DisplayTitle": "Season '25 Highlights",
"Type": "Editorial",
"CategoryExternalId": "featured"
}
],
"ThumbnailUrl": "https://cdn.example.com/images/highlight-001-thumb.jpg",
"ThumbnailTemplate": "thumb-template-01",
"CreationTime": "2025-10-01T10:00:00Z",
"TemplateMetadata": {
"style": "bold",
"watermark": "on"
}
}
},
"workflowProcessedWebhookUrl": "https://partner.example.com/webhooks/processed",
"workflowFailedWebhookUrl": "https://partner.example.com/webhooks/failed"
}
Webhooks#
Both workflow completion and failure webhooks are optional but recommended for tracking workflow execution status:
| Key | Type | Required | Remarks |
|---|---|---|---|
workflowProcessedWebhookUrl |
string | No | URL called when workflow completes successfully. |
workflowFailedWebhookUrl |
string | No | URL called when workflow fails. |