openapi: 3.0.1 info: title: Shotstack API description: >- Shotstack is a cloud video-editing platform that renders video, image, and audio assets from a JSON edit specification. This document covers the Edit API (render and templates), the Ingest API (source assets), the Serve API (asset hosting and delivery), and the Create API (AI-generated assets). All endpoints authenticate with an `x-api-key` header. Each API is available in a `v1` (production) and `stage` (sandbox) environment. termsOfService: https://shotstack.io/terms/ contact: name: Shotstack Support url: https://shotstack.io/contact/ version: '1.0' servers: - url: https://api.shotstack.io description: Shotstack production and sandbox host (use /edit/v1 or /edit/stage, etc.) security: - apiKey: [] tags: - name: Edit description: Render videos, images, and audio from a JSON edit specification. - name: Templates description: Manage and render reusable edit templates with merge fields. - name: Ingest description: Upload, store, and transform source assets. - name: Serve description: Inspect, manage, and deliver hosted assets. - name: Create description: Generate AI assets such as text-to-speech and text-to-image. paths: /edit/v1/render: post: operationId: postRender tags: - Edit summary: Queue a render description: >- Queue a video, image, or audio for rendering from a JSON edit specification consisting of a timeline and an output. Returns a render ID used to poll status. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Edit' responses: '201': description: Render queued. content: application/json: schema: $ref: '#/components/schemas/QueuedResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' /edit/v1/render/{id}: get: operationId: getRender tags: - Edit summary: Get render status description: >- Retrieve the status, progress, and output URL of a render by its ID. Status values progress through queued, fetching, rendering, saving, done, and failed. parameters: - name: id in: path required: true description: The render ID returned when the render was queued. schema: type: string format: uuid - name: data in: query required: false description: Include the original edit JSON in the response. schema: type: boolean default: false responses: '200': description: Render status. content: application/json: schema: $ref: '#/components/schemas/RenderResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /edit/v1/probe/{url}: get: operationId: probeAsset tags: - Edit summary: Probe a media asset description: >- Inspect the metadata of a media asset (duration, dimensions, codecs) using FFprobe. The asset URL must be URL-encoded. parameters: - name: url in: path required: true description: URL-encoded URL of the media asset to inspect. schema: type: string responses: '200': description: Asset metadata. content: application/json: schema: $ref: '#/components/schemas/ProbeResponse' '401': $ref: '#/components/responses/Unauthorized' /edit/v1/templates: post: operationId: createTemplate tags: - Templates summary: Create a template description: Save an edit as a reusable template with optional merge fields. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Template' responses: '201': description: Template created. content: application/json: schema: $ref: '#/components/schemas/TemplateResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' get: operationId: listTemplates tags: - Templates summary: List templates description: List all templates for the authenticated account. responses: '200': description: A list of templates. content: application/json: schema: $ref: '#/components/schemas/TemplateListResponse' '401': $ref: '#/components/responses/Unauthorized' /edit/v1/templates/{id}: get: operationId: getTemplate tags: - Templates summary: Get a template parameters: - $ref: '#/components/parameters/TemplateId' responses: '200': description: A template. content: application/json: schema: $ref: '#/components/schemas/TemplateResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' put: operationId: updateTemplate tags: - Templates summary: Update a template parameters: - $ref: '#/components/parameters/TemplateId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Template' responses: '200': description: Template updated. content: application/json: schema: $ref: '#/components/schemas/TemplateResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' delete: operationId: deleteTemplate tags: - Templates summary: Delete a template parameters: - $ref: '#/components/parameters/TemplateId' responses: '200': description: Template deleted. '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /edit/v1/templates/render: post: operationId: renderTemplate tags: - Templates summary: Render a template description: >- Render an asset from a saved template, supplying optional merge fields to substitute variables in the template. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TemplateRenderRequest' responses: '201': description: Render queued. content: application/json: schema: $ref: '#/components/schemas/QueuedResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' /ingest/v1/sources: post: operationId: fetchSource tags: - Ingest summary: Ingest a source from a URL description: >- Queue a source file (video, image, audio, or font) to be fetched from a URL, stored, and optionally transformed into renditions or transcribed. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SourceRequest' responses: '201': description: Source queued. content: application/json: schema: $ref: '#/components/schemas/SourceResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' get: operationId: listSources tags: - Ingest summary: List sources responses: '200': description: A list of ingested sources. content: application/json: schema: $ref: '#/components/schemas/SourceListResponse' '401': $ref: '#/components/responses/Unauthorized' /ingest/v1/sources/{id}: get: operationId: getSource tags: - Ingest summary: Get a source parameters: - $ref: '#/components/parameters/SourceId' responses: '200': description: A source. content: application/json: schema: $ref: '#/components/schemas/SourceResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' delete: operationId: deleteSource tags: - Ingest summary: Delete a source parameters: - $ref: '#/components/parameters/SourceId' responses: '200': description: Source deleted. '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /ingest/v1/upload: post: operationId: requestUpload tags: - Ingest summary: Request a direct upload description: >- Request a signed URL to upload a source file directly to Shotstack storage. responses: '201': description: Signed upload URL issued. content: application/json: schema: $ref: '#/components/schemas/UploadResponse' '401': $ref: '#/components/responses/Unauthorized' /serve/v1/assets/{id}: get: operationId: getAsset tags: - Serve summary: Get an asset description: Retrieve the details and CDN URL of a hosted asset by asset ID. parameters: - $ref: '#/components/parameters/AssetId' responses: '200': description: An asset. content: application/json: schema: $ref: '#/components/schemas/AssetResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' delete: operationId: deleteAsset tags: - Serve summary: Delete an asset parameters: - $ref: '#/components/parameters/AssetId' responses: '200': description: Asset deleted. '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /serve/v1/assets/render/{id}: get: operationId: getAssetsByRender tags: - Serve summary: Get assets by render ID description: >- Retrieve all assets (video, thumbnail, poster) associated with a render ID. parameters: - name: id in: path required: true description: The render ID. schema: type: string format: uuid responses: '200': description: A list of assets for the render. content: application/json: schema: $ref: '#/components/schemas/AssetListResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /serve/v1/assets: post: operationId: transferAsset tags: - Serve summary: Transfer an asset description: Transfer a file from a URL to one or more hosting destinations. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TransferRequest' responses: '201': description: Transfer queued. content: application/json: schema: $ref: '#/components/schemas/AssetResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' /create/v1/assets: post: operationId: generateAsset tags: - Create summary: Generate an AI asset description: >- Generate an AI asset (text-to-speech, text-to-image, image-to-video, or text generation) using a built-in or third-party provider. Returns an asset ID to poll for the generated, hosted asset. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/GenerateAssetRequest' responses: '201': description: Generation queued. content: application/json: schema: $ref: '#/components/schemas/GenerateAssetResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' /create/v1/assets/{id}: get: operationId: getGeneratedAsset tags: - Create summary: Get a generated asset description: Retrieve the status and URL of a generated AI asset by ID. parameters: - $ref: '#/components/parameters/AssetId' responses: '200': description: A generated asset. content: application/json: schema: $ref: '#/components/schemas/GenerateAssetResponse' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' components: securitySchemes: apiKey: type: apiKey in: header name: x-api-key description: Developer API key. The same key set is used by all Shotstack APIs. parameters: TemplateId: name: id in: path required: true description: The template ID. schema: type: string format: uuid SourceId: name: id in: path required: true description: The source ID. schema: type: string format: uuid AssetId: name: id in: path required: true description: The asset ID. schema: type: string format: uuid responses: BadRequest: description: The request was malformed or failed validation. content: application/json: schema: $ref: '#/components/schemas/Error' Unauthorized: description: Missing or invalid x-api-key. content: application/json: schema: $ref: '#/components/schemas/Error' NotFound: description: The requested resource was not found. content: application/json: schema: $ref: '#/components/schemas/Error' schemas: Edit: type: object required: - timeline - output properties: timeline: $ref: '#/components/schemas/Timeline' output: $ref: '#/components/schemas/Output' merge: type: array description: Find-and-replace merge fields applied before rendering. items: $ref: '#/components/schemas/MergeField' callback: type: string format: uri description: HTTPS webhook URL called when the render status changes. Timeline: type: object required: - tracks properties: soundtrack: $ref: '#/components/schemas/Soundtrack' background: type: string description: Hex color of the background canvas. example: '#000000' fonts: type: array items: type: object properties: src: type: string format: uri tracks: type: array description: Layers of clips composited from bottom to top. items: $ref: '#/components/schemas/Track' Track: type: object required: - clips properties: clips: type: array items: $ref: '#/components/schemas/Clip' Clip: type: object required: - asset - start - length properties: asset: $ref: '#/components/schemas/Asset' start: type: number description: Start time on the timeline in seconds. length: oneOf: - type: number - type: string description: Duration of the clip in seconds, or "auto"/"end". fit: type: string enum: [crop, cover, contain, none] scale: type: number position: type: string enum: [top, topRight, right, bottomRight, bottom, bottomLeft, left, topLeft, center] opacity: type: number transition: type: object properties: in: type: string out: type: string effect: type: string Asset: type: object description: >- A clip asset. The "type" discriminates between video, image, audio, title, html, luma, caption, and the AI generative asset types (text-to-speech, text-to-image, image-to-video). required: - type properties: type: type: string enum: - video - image - audio - title - html - luma - caption - text-to-speech - text-to-image - image-to-video src: type: string format: uri description: Source URL for video, image, audio, and luma assets. text: type: string description: Text content for title, caption, and AI text-based assets. trim: type: number volume: type: number Soundtrack: type: object properties: src: type: string format: uri effect: type: string enum: [fadeIn, fadeOut, fadeInFadeOut] volume: type: number Output: type: object required: - format properties: format: type: string enum: [mp4, gif, jpg, png, bmp, mp3, webm] resolution: type: string enum: [preview, mobile, sd, hd, '1080'] aspectRatio: type: string enum: ['16:9', '9:16', '1:1', '4:5', '4:3'] fps: type: number enum: [12, 15, 24, 25, 30, 60] quality: type: string enum: [low, medium, high] destinations: type: array description: Where to deliver the rendered output. items: type: object properties: provider: type: string enum: [shotstack, s3, googlecloudstorage, googledrive, mux, vimeo] MergeField: type: object properties: find: type: string replace: type: string QueuedResponse: type: object properties: success: type: boolean message: type: string response: type: object properties: message: type: string id: type: string format: uuid RenderResponse: type: object properties: success: type: boolean message: type: string response: type: object properties: id: type: string format: uuid owner: type: string status: type: string enum: [queued, fetching, rendering, saving, done, failed] url: type: string format: uri poster: type: string format: uri thumbnail: type: string format: uri duration: type: number renderTime: type: number created: type: string format: date-time updated: type: string format: date-time ProbeResponse: type: object properties: success: type: boolean response: type: object properties: metadata: type: object Template: type: object required: - name - template properties: name: type: string template: $ref: '#/components/schemas/Edit' TemplateResponse: type: object properties: success: type: boolean message: type: string response: type: object properties: id: type: string format: uuid name: type: string template: $ref: '#/components/schemas/Edit' TemplateListResponse: type: object properties: success: type: boolean response: type: object properties: templates: type: array items: type: object properties: id: type: string format: uuid name: type: string TemplateRenderRequest: type: object required: - id properties: id: type: string format: uuid description: The template ID to render. merge: type: array items: $ref: '#/components/schemas/MergeField' SourceRequest: type: object required: - url properties: url: type: string format: uri description: URL of the source file to fetch and store. outputs: type: object description: Optional renditions and/or transcription to generate. properties: renditions: type: array items: type: object properties: format: type: string resolution: type: string transcription: type: object properties: format: type: string SourceResponse: type: object properties: data: type: object properties: type: type: string example: source id: type: string format: uuid attributes: type: object properties: id: type: string format: uuid owner: type: string source: type: string format: uri status: type: string enum: [queued, importing, ready, failed, deleted] created: type: string format: date-time updated: type: string format: date-time SourceListResponse: type: object properties: data: type: array items: $ref: '#/components/schemas/SourceResponse' UploadResponse: type: object properties: data: type: object properties: type: type: string example: upload id: type: string format: uuid attributes: type: object properties: id: type: string format: uuid url: type: string format: uri description: Signed URL to PUT the file to. AssetResponse: type: object properties: data: type: object properties: type: type: string example: asset id: type: string format: uuid attributes: type: object properties: id: type: string format: uuid owner: type: string region: type: string renderId: type: string format: uuid filename: type: string url: type: string format: uri status: type: string enum: [queued, transferring, ready, failed, deleted] created: type: string format: date-time updated: type: string format: date-time AssetListResponse: type: object properties: data: type: array items: $ref: '#/components/schemas/AssetResponse' TransferRequest: type: object required: - url properties: url: type: string format: uri description: URL of the file to transfer. destinations: type: array items: type: object properties: provider: type: string enum: [shotstack, s3, googlecloudstorage, googledrive, mux, vimeo] GenerateAssetRequest: type: object required: - provider - options properties: provider: type: string description: The generation provider. enum: [shotstack, elevenlabs, stability-ai, openai] options: type: object required: - type properties: type: type: string enum: [text-to-speech, text-to-image, image-to-video, text-generation] text: type: string description: Prompt or text input for the generation. prompt: type: string voice: type: string language: type: string GenerateAssetResponse: type: object properties: data: type: object properties: type: type: string example: asset id: type: string format: uuid attributes: type: object properties: id: type: string format: uuid owner: type: string provider: type: string type: type: string status: type: string enum: [queued, processing, done, failed] url: type: string format: uri created: type: string format: date-time updated: type: string format: date-time Error: type: object properties: success: type: boolean example: false message: type: string response: type: object properties: error: type: string code: type: string