studio / N8N_ENDPOINTS.md
Ava2lon's picture
Upload 213 files
99d5f49 verified
|
Raw
History Blame Contribute Delete
25.2 kB
# Unified Media Studio API for n8n
This reference describes every business API endpoint exposed by the unified
Space and how to call it with n8n's **HTTP Request** node.
## Base URL
Store the deployed Space URL in an n8n variable:
```text
STUDIO_BASE_URL=https://<space-subdomain>.hf.space
```
Use this expression in HTTP Request nodes:
```text
{{ $vars.STUDIO_BASE_URL }}/health
```
Do not add a trailing slash to `STUDIO_BASE_URL`.
## Standard HTTP Request Node Settings
### JSON request
- **Method:** Use the method in the endpoint tables.
- **URL:** `{{ $vars.STUDIO_BASE_URL }}<path>`
- **Send Body:** On
- **Body Content Type:** JSON
- **Specify Body:** Using JSON
- **Response Format:** JSON
For routes marked **API key**, add a Header Auth credential or enable
**Send Headers**:
```text
X-API-Key: <AVA2LON_API_KEY value>
```
The header is only enforced when `AVA2LON_API_KEY` or `BASYX_API_KEY` is set in
the Space environment.
### Query parameters
- Enable **Send Query Parameters**.
- Add each query parameter shown in the endpoint table.
- Do not place simple query parameters in the JSON body.
### Multipart file upload
- **Send Body:** On
- **Body Content Type:** Form-Data
- For text fields, select **Parameter Type: Form Data**.
- For files, select **Parameter Type: n8n Binary File**.
- Set **Name** to the API field name, usually `file` or `files`.
- Set **Input Data Field Name** to the incoming n8n binary field, commonly
`data`.
Add another `files` parameter for every additional binary file.
### File download response
For endpoints marked **File response**:
- Set **Response Format** to File.
- Set **Put Output in Field** to `data`.
- The following n8n node can read the output from `$binary.data`.
### Asynchronous job workflow
Most renderer operations return:
```json
{
"job_id": "job_123",
"status_url": "/status/job_123",
"download_url": "/download/job_123?token=..."
}
```
Recommended n8n flow:
1. HTTP Request submits the job.
2. Wait node pauses for several seconds.
3. HTTP Request calls
`{{ $vars.STUDIO_BASE_URL }}{{ $json.status_url }}`.
4. IF node checks whether `state` equals `COMPLETED`, `FAILED`, or `CANCELLED`.
5. Loop through Wait while the state is `PENDING` or `RUNNING`.
6. Download using the original submission node's `download_url`.
For payloads with `callback_url`, use an n8n Webhook node's production URL to
avoid polling.
Render callbacks use `render.completed`, `render.failed`, and
`render.cancelled`; toolkit and analysis callbacks use `task.*`. The event is
available in both the JSON `event` property and `X-Ava2lon-Event` header.
## Root and Discovery
| Method | Path | n8n input | Response |
| --- | --- | --- | --- |
| GET | `/` | None | Redirects to `/dashboard`; use only for browser access. |
| GET | `/apps` | None | JSON map of mounted applications and MCP tool count. |
## Renderer Discovery and Monitoring
These routes use the root base URL.
| Method | Path | n8n input | Response |
| --- | --- | --- | --- |
| GET | `/health` | None | Renderer health. |
| GET | `/healthz` | None | Health-check alias for hosting probes. |
| GET | `/monitor` | None | Runtime, queue, storage, and capability summary. |
| GET | `/queue` | None | Job queue summary. |
| GET | `/workers` | None | Worker and runtime settings. |
| GET | `/presets` | None | Presets, templates, styles, transitions, and task IDs. |
| GET | `/platforms` | None | Platform profile metadata. |
| GET | `/toolkit/tasks` | None | Renderer toolkit task names. |
| GET | `/capabilities` | None | Complete capability catalog. |
| GET | `/effects` | None | Effects catalog. |
| GET | `/filters` | None | Filter catalog. |
| GET | `/transitions` | None | Transition catalog. |
| GET | `/templates/catalog` | None | Templates, presets, and styles. |
| GET | `/projects` | None | List saved projects. |
## Projects and Timeline
| Method | Path | n8n input | Auth | Response |
| --- | --- | --- | --- | --- |
| POST | `/projects` | JSON `ProjectPayload` | API key | Created project. |
| POST | `/project/create` | JSON `ProjectPayload` | API key | Alias of `/projects`. |
| GET | `/project/{project_id}` | Replace `{project_id}` | None | Project JSON. |
| POST | `/project/save` | JSON `ProjectSavePayload` | API key | Saved project. |
| POST | `/project/assets/add` | JSON `ProjectAssetPayload` | API key | Updated project. |
| POST | `/timeline/add` | JSON `TimelineAddPayload` | API key | Updated project. |
| POST | `/timeline/operation` | JSON `TimelineOperationPayload` | API key | Updated project. |
| POST | `/timeline/split` | JSON `TimelineOperationPayload` | API key | Runs `split`. |
| POST | `/timeline/trim` | JSON `TimelineOperationPayload` | API key | Runs `trim`. |
| POST | `/timeline/ripple-delete` | JSON `TimelineOperationPayload` | API key | Runs `ripple_delete`. |
| POST | `/timeline/insert` | JSON `TimelineOperationPayload` | API key | Runs `insert`. |
| POST | `/timeline/replace` | JSON `TimelineOperationPayload` | API key | Runs `replace`. |
| POST | `/timeline/group` | JSON `TimelineOperationPayload` | API key | Runs `group`. |
| POST | `/timeline/lock` | JSON `TimelineOperationPayload` | API key | Runs `lock`. |
| POST | `/timeline/hide` | JSON `TimelineOperationPayload` | API key | Runs `hide`. |
| POST | `/timeline/duplicate` | JSON `TimelineOperationPayload` | API key | Runs `duplicate`. |
| POST | `/effect/apply` | JSON `EffectApplyPayload` | API key | Updated project or asynchronous job. |
| POST | `/filter/apply` | JSON `FilterApplyPayload` | API key | Updated project or asynchronous job. |
| POST | `/transition/add` | JSON `TransitionAddPayload` | API key | Updated project or asynchronous job. |
| POST | `/keyframe/add` | JSON `KeyframePayload` | API key | Updated project. |
Example project creation:
```json
{
"name": "Campaign 01",
"metadata": {
"platform": "tiktok",
"creative_style": "high_energy"
},
"export_settings": {
"platform": "tiktok"
}
}
```
## AI and Generation
All routes in this table return asynchronous job information.
| Method | Path | n8n input | Auth |
| --- | --- | --- | --- |
| POST | `/caption/generate` | JSON `CaptionGeneratePayload` | API key |
| POST | `/music/generate` | JSON `GenerationPayload` | API key |
| POST | `/voice/generate` | JSON `GenerationPayload` | API key |
| POST | `/image/generate` | JSON `GenerationPayload` | API key |
| POST | `/video/generate` | JSON `GenerationPayload` | API key |
| POST | `/ai/{tool}` | Replace `{tool}`; JSON `AIToolPayload` | API key |
| POST | `/assistant/{tool}` | Replace `{tool}`; JSON `AIToolPayload` | API key |
Example:
```json
{
"prompt": "Upbeat cinematic background music",
"provider": "local",
"callback_url": "https://n8n.example/webhook/studio-complete",
"params": {
"duration": 20
}
}
```
## Rendering and Uploads
| Method | Path | n8n input | Auth | Response |
| --- | --- | --- | --- | --- |
| POST | `/render` | JSON `RenderPayload` or `AIReelsPayload` | None | Async job. |
| POST | `/render/variants` | JSON `RenderVariantsPayload` | None | Render group plus child jobs. |
| POST | `/render/template` | JSON `TemplateRenderPayload` | None | Async job. |
| POST | `/render/ai-reels` | JSON `AIReelsPayload` | None | Async job. |
| POST | `/render/batch` | JSON `BatchPayload` | None | Array of job IDs. |
| POST | `/automation/batch` | JSON `BatchPayload` | API key | Array of job IDs. |
| POST | `/project/{project_id}/render` | Replace `{project_id}`; JSON `ProjectRenderPayload` | API key | Async job. |
| POST | `/render/upload` | Multipart `request_json` plus zero or more `files` | None | Async job. |
| POST | `/render/ai-reels/upload` | Multipart `request_json` plus zero or more `files` | None | Async job. |
| POST | `/assets/upload` | Multipart; one or more `files` | None | Uploaded asset references. |
| POST | `/upload` | Multipart `files`; optional `expand_zip` | None | Uploaded or expanded assets. |
| GET | `/render/groups/{group_id}` | Replace `{group_id}` | None | Aggregate state and child jobs. |
| GET | `/templates/automation` | None | None | Data-driven render templates. |
Basic render body:
```json
{
"scenes": [
{
"start": 0,
"duration": 5,
"media": "https://example.com/video.mp4",
"caption": "Opening hook",
"transition": "fade",
"background": "blur",
"layout": "fill"
}
],
"output_name": "campaign.mp4",
"template": "tiktok_classic",
"auto_subtitles": true,
"subtitle_language": "en"
}
```
For `/render/upload`, configure n8n Form-Data as:
| Parameter Type | Name | Value |
| --- | --- | --- |
| Form Data | `request_json` | JSON string shown below |
| n8n Binary File | `files` | Input Data Field Name such as `data` |
```json
{
"scenes": [
{
"start": 0,
"duration": 5,
"media": "upload://clip.mp4",
"caption": "Uploaded clip"
}
],
"output_name": "render.mp4"
}
```
The filename in `upload://clip.mp4` must match the uploaded binary filename.
Render several platform outputs from one timeline with `/render/variants`:
```json
{
"scenes": [{"start": 0, "duration": 12, "media": "https://example.com/input.mp4"}],
"callback_url": "https://n8n.example/webhook/render-events",
"variants": [
{"name": "shorts", "platform": "youtube_shorts", "output_name": "shorts.mp4"},
{"name": "reels", "platform": "instagram_reels", "output_name": "reels.mp4"},
{"name": "youtube", "platform": "youtube_1080p", "output_name": "youtube.mp4"}
]
}
```
Use `/render/template` for spreadsheet, CRM, and database-driven renders. An
exact placeholder preserves arrays, objects, numbers, and booleans instead of
converting them to strings.
```json
{
"template": "vertical-captioned-clip",
"variables": {
"output_name": "customer-42.mp4",
"scenes": [{"start": 0, "duration": 8, "media": "https://example.com/42.mp4"}],
"voiceover": null,
"background_music": null
}
}
```
## Platform Processing and Toolkit
All routes in this table require `X-API-Key` and return asynchronous job
information.
| Method | Path | n8n input |
| --- | --- | --- |
| POST | `/ingest` | JSON `IngestPayload` |
| POST | `/analyze` | JSON `AnalyzePayload` |
| POST | `/clips` | JSON `ClipsPayload` |
| POST | `/thumbnail` | JSON `ThumbnailPayload` |
| POST | `/thumbnail/create` | JSON `ThumbnailPayload` |
| POST | `/metadata` | JSON `MetadataPayload` |
| POST | `/publish` | JSON `PublishPayload` |
| POST | `/toolkit` | JSON `ToolkitPayload` |
| POST | `/edit` | JSON `ToolkitPayload`; alias of `/toolkit` |
Toolkit example:
```json
{
"task": "compress",
"media": "https://example.com/input.mp4",
"output_name": "compressed.mp4",
"params": {
"crf": 28,
"resolution": "720p"
}
}
```
FFmpeg automation tasks added for n8n:
| Task | Important `params` | Download artifact |
| --- | --- | --- |
| `inspect` | None | FFprobe metadata JSON |
| `loudness_analyze` | `target_lufs` | LUFS/LRA/true-peak JSON |
| `silence_detect` | `noise_db`, `duration_seconds` | Timed silence events JSON |
| `black_detect` | `pixel_threshold`, `duration_seconds` | Timed black-frame events JSON |
| `scene_detect` | `threshold` | Scene-change timestamps JSON |
| `contact_sheet` | `columns`, `rows`, `interval_seconds`, `thumbnail_width` | JPEG/PNG |
| `hls` | `segment_seconds`, `playlist_type`, `crf` | ZIP with M3U8 and TS segments |
All use the normal `POST /toolkit` body with `task`, `media`, optional `params`,
and optional `callback_url`.
## Transcription, Subtitles, Jobs, and Downloads
| Method | Path | n8n input | Response |
| --- | --- | --- | --- |
| POST | `/transcribe` | JSON `TranscribePayload` | Transcription JSON. |
| POST | `/subtitles` | JSON `SubtitlePayload` | File response (`.srt` or `.ass`). |
| POST | `/scene-builder` | JSON `SceneBuildPayload` | Generated scene array. |
| POST | `/transcribe/upload` | Multipart `file` plus optional transcription fields | Transcription JSON. |
| GET | `/status` | Optional query `job_id` | Service status without `job_id`; job record with it. |
| GET | `/status/{job_id}` | Replace `{job_id}` | Job record. |
| POST | `/cancel/{job_id}` | Replace `{job_id}` | Updated job record. |
| POST | `/admin/cleanup` | Optional query `older_than_seconds` | Cleanup counts. |
| GET | `/download` | Query `job_id`; optional `token` | File response. |
| GET | `/download/{job_id}` | Replace `{job_id}`; optional query `token` | File response. |
| POST | `/inspect` | Query `path` | Media metadata JSON. |
| POST | `/media/inspect` | JSON `{ "media": "...", "callback_url": "..." }` | Async remote-safe inspection. |
Transcription body:
```json
{
"audio": "https://example.com/audio.mp3",
"model_size": "tiny",
"language": "en",
"task": "transcribe",
"beam_size": 5,
"vad_filter": true,
"word_timestamps": true
}
```
Subtitle body:
```json
{
"events": [
{
"start": 0,
"end": 2.5,
"text": "Opening caption"
}
],
"format": "srt",
"template": "tiktok_classic"
}
```
## Kokoro TTS
| Method | Path | n8n input | Response |
| --- | --- | --- | --- |
| POST | `/tts/v1/audio/speech` | JSON shown below | WAV file response. |
Set the HTTP Request node's response format to **File**.
```json
{
"input": "This is generated speech.",
"voice": "af_bella.pt",
"model": "kokoro-v0_19.onnx",
"speed": 1.0
}
```
`voice` and `model` are optional; the server uses its first configured voice and
model when omitted.
## MusicGen
| Method | Path | n8n input | Response |
| --- | --- | --- | --- |
| GET | `/music/health` | None | Health JSON. |
| POST | `/music/generate` | Query `prompt`; optional query `duration` | WAV file response. |
For generation:
- **Method:** POST
- **URL:** `{{ $vars.STUDIO_BASE_URL }}/music/generate`
- **Send Query Parameters:** On
- `prompt`: `Soft cinematic instrumental`
- `duration`: `10`
- **Response Format:** File
## Whisper Operator
| Method | Path | n8n input | Response |
| --- | --- | --- | --- |
| POST | `/whisper/execute/{task_name}` | Multipart file or URL fields | JSON or file response. |
| GET | `/whisper/api/health` | None | Health JSON. |
| GET | `/whisper/api/status/{job_id}` | Replace `{job_id}` | Whisper queue status. |
Use one of these multipart inputs for `/whisper/execute/{task_name}`:
- `file`: n8n Binary File.
- `url_input`: downloadable media URL.
- `source`: alternative media URL.
- `webhook`: optional callback URL.
Supported task names:
```text
autonomous
auto-publish
publish
bulk-publish
generate-metadata
generate-thumbnail
schedule-post
transcribe
subtitles
render
highlights
clips
viral-score
strategy
batch
```
## FFmpeg Editor
| Method | Path | n8n input | Response |
| --- | --- | --- | --- |
| GET | `/editor/healthz` | None | Health and dependency checks. |
| GET | `/editor/readyz` | None | Readiness; returns 503 when dependencies fail. |
| GET | `/editor/tasks` | None | Editor task registry. |
| POST | `/editor/n8n/execute/{task_id}` | JSON, multipart, or raw binary | Synchronous file response. |
| POST | `/editor/n8n/jobs/{task_id}` | JSON, multipart, or raw binary | Background job JSON. |
| POST | `/editor/execute/{task_id}` | Multipart fields | Synchronous file response. |
| POST | `/editor/jobs/{task_id}` | Multipart fields | Background job JSON. |
| GET | `/editor/status/{job_id}` | Replace `{job_id}` | Background job status. |
| GET | `/editor/download/{job_id}` | Replace `{job_id}` | File response. |
| GET | `/editor/history` | None | Recent output metadata. |
| GET | `/editor/history/{history_id}/download` | Replace `{history_id}` | File response. |
### Recommended editor request for n8n
Use `/editor/n8n/jobs/{task_id}` for long-running jobs.
Multipart request:
- Add one or more **n8n Binary File** parameters. The field name may be
`files`.
- Add text options as **Form Data**.
- A URL may use `url`, `urls`, `file_url`, `source_url`, or `download_url`.
JSON request:
```json
{
"url": "https://example.com/input.mp4",
"options": {
"resolution": "720p",
"crf": "28",
"preset": "medium",
"text": "Caption text"
}
}
```
Raw binary request:
- **Body Content Type:** n8n Binary File
- **Input Data Field Name:** `data`
- Add header `X-Filename: input.mp4`
- Put editor options in query parameters.
Available editor option fields:
```text
text
start_time
end_time
duration
aspect_ratio
resolution
crf
preset
audio_bitrate
volume
position
opacity
fps
width
speed
timestamp
image_duration
frame_rate
font_size
wave_color
```
### Editor task IDs
Use one value below as `{task_id}`:
| Task ID | Purpose | Files |
| --- | --- | --- |
| `normalize` | Convert to H.264/AAC MP4 | 1 video |
| `extract_audio` | Export MP3 audio | 1 video/audio |
| `resize_916` | Crop to vertical 9:16 | 1 video |
| `add_subtitles` | Burn SRT/ASS subtitles | video + subtitle |
| `burn_lyrics` | Burn styled lyrics | video + subtitle |
| `text_overlay` | Add caption text | 1 video |
| `merge_music` | Add background music | video + audio |
| `thumbnail` | Export JPG frame | 1 video |
| `watermark` | Overlay logo/image | video + image |
| `compress` | Reduce video size | 1 video |
| `batch_compress` | Compress videos into ZIP | 1+ videos |
| `make_gif` | Create GIF | 1 video |
| `tiktok_lyrics` | Vertical lyric clip | 1 video |
| `tiktok_pro_reframer` | Vertical reframe and style | 1 video |
| `reels_blur_fit` | Blurred 9:16 fit | 1 video |
| `reels_safe_caption` | Mobile-safe caption | 1 video |
| `reels_hook_title` | Top hook/title | 1 video |
| `reels_progress_bar` | Progress bar and trim | 1 video |
| `reels_loop` | Loop to target duration | 1 video |
| `reels_subtitle_safe` | Mobile-safe subtitles | video + subtitle |
| `reels_reaction_stack` | Stack reaction videos | 2 videos |
| `reels_audio_duck` | Duck music below video | video + audio |
| `faceless_quote_card` | Text-only quote short | no file |
| `faceless_story_pages` | Timed text story slides | no file |
| `faceless_image_narration` | Image with narration | image + audio |
| `faceless_video_narration` | B-roll with narration | video + audio |
| `faceless_broll_montage` | Silent b-roll montage | 2+ videos |
| `series_split_pack` | Split long video into series ZIP | 1 video |
| `series_episode_badge` | Add episode badge | 1 video |
| `series_batch_pack` | Package clips as numbered series | 2+ videos |
| `series_recap_card` | Text-only recap card | no file |
| `concat` | Join clips | 2+ videos |
| `slideshow` | Build video from images | 2+ images |
| `trim` | Cut by start/end | 1 video/audio |
| `crop_aspect` | Crop to target aspect ratio | 1 video |
| `waveform` | Create waveform video | 1 audio/video |
| `extract_frames` | Export frames as ZIP | 1 video |
| `add_intro_outro` | Join intro/main/outro | 2-3 videos |
| `speed` | Change playback speed | 1 video |
| `remove_audio` | Remove video audio | 1 video |
| `replace_audio` | Replace video audio | video + audio |
## JSON Payload Reference
Fields marked `*` are required.
### Rendering
`ScenePayload`
```text
start*: number >= 0
duration*: number > 0
media*: string path or URL
caption: string
transition: string = "fade"
background: string = "blur"
layout: string = "fill"
effect: string | null
```
`RenderPayload`
```text
scenes*: ScenePayload[]
template: string = "tiktok_classic"
preset, creative_style, platform: string | null
output_name: string = "render.mp4"
voiceover, background_music: string | null
music_volume: number = 0.316
music_fade_in, music_fade_out, music_start: number = 0
music_loop, music_ducking: boolean = true
voice_volume: number = 1
subtitle_format: string = "ass"
auto_subtitles: boolean = false
subtitle_language, whisper_model_size: string | null
preview, audio_normalize: boolean = false
watermark, intro, outro: string | null
watermark_position: string = "bottom-right"
callback_url, export_target: string | null
priority: integer = 0
scheduled_at: number | null
normalize: boolean = true
metadata: object = {}
```
`AIReelsPayload`
```text
script*: string
voiceover*: string
assets*: string[]
template: string = "tiktok_classic"
creative_style, platform: string | null
output_name: string = "ai_reel.mp4"
background_music: string | null
music_volume: number = 0.316
music_fade_in, music_fade_out, music_start: number = 0
music_loop, music_ducking: boolean = true
voice_volume: number = 1
callback_url, export_target: string | null
```
`BatchPayload`
```text
jobs*: RenderPayload[]
```
`ProjectRenderPayload`
```text
output_name: string = "project_render.mp4"
template, preset, creative_style, platform: string | null
callback_url, export_target: string | null
preview: boolean = false
normalize: boolean = true
metadata: object = {}
```
### Projects and Editing
`ProjectPayload`
```text
name*: string
metadata: object = {}
export_settings: object = {}
template: object | null
```
`ProjectSavePayload`
```text
project_id: string | null
project*: object
```
`ProjectAssetPayload`
```text
project_id*: string
asset*: object
```
`TimelineAddPayload`
```text
project_id*: string
track_type: string = "video"
track_id: string | null
item: object = {}
```
`TimelineOperationPayload`
```text
project_id*: string
operation: string = "drag"
item_id: string | null
params: object = {}
```
`EffectApplyPayload`
```text
project_id, target_id, item_id: string | null
effect*: string
params: object = {}
callback_url: string | null
```
`FilterApplyPayload`
```text
project_id, target_id, item_id: string | null
filter*: string
params: object = {}
lut: string | null
callback_url: string | null
```
`TransitionAddPayload`
```text
project_id, from_item_id, to_item_id, target_id: string | null
transition*: string
duration: number = 0.45
params: object = {}
callback_url: string | null
```
`KeyframePayload`
```text
project_id*: string
target_id*: string
property*: string
time*: number >= 0
value*: any JSON value
easing: string = "linear"
```
### Generation and Platform Tools
`GenerationPayload`
```text
prompt, text, media, provider: string | null
callback_url, export_target: string | null
params: object = {}
additional JSON fields are accepted
```
`CaptionGeneratePayload`
```text
media, audio, text, transcript: string | null
events: object[] | null
template: string = "capcut"
language: string | null
engine: string = "whisper"
word_timestamps: boolean = true
emoji_insertion, speaker_detection: boolean = false
karaoke, animated: boolean = true
callback_url: string | null
additional JSON fields are accepted
```
`AIToolPayload`
```text
project_id, media, transcript, text, platform: string | null
callback_url: string | null
params: object = {}
additional JSON fields are accepted
```
`IngestPayload`
```text
sources*: [{ "url": string, "type": string|null, "name": string|null }]
callback_url: string | null
```
`AnalyzePayload`
```text
media*: string
transcript: string = ""
platform, callback_url: string | null
```
`ClipsPayload`
```text
media*: string
clips: object[] | null
callback_url: string | null
```
`ThumbnailPayload`
```text
media*: string
text: string = ""
timestamp: number | null
template: string = "bold"
callback_url: string | null
```
`MetadataPayload`
```text
topic, transcript: string = ""
platform, callback_url: string | null
```
`PublishPayload`
```text
media, asset, title, description: string | null
platforms: string[] = []
platform, scheduled_at: string | null
draft: boolean = true
callback_url: string | null
```
`ToolkitPayload`
```text
task*: string
input, media, output_name: string | null
params: object = {}
callback_url, export_target: string | null
additional JSON fields are accepted
```
### Transcription and Subtitles
`TranscribePayload`
```text
audio*: string path or URL
model_size, language: string | null
task: string = "transcribe"
beam_size: integer = 5
vad_filter, word_timestamps: boolean = true
```
`SubtitlePayload`
```text
events*: [{ "start": number, "end": number, "text": string }]
format: string = "srt"
template: string = "tiktok_classic"
```
`SceneBuildPayload`
```text
script*: string
assets*: string[]
duration: number | null
transition: string = "fade"
creative_style: string | null
```
## Framework and UI Endpoints
These are not business API operations:
| Path | Purpose |
| --- | --- |
| `/dashboard` | Renderer Gradio interface. |
| `/tts/` | Kokoro TTS Gradio interface. |
| `/music/` | MusicGen Gradio interface. |
| `/whisper/` | Whisper Gradio interface. |
| `/editor/` | FFmpeg editor Gradio interface. |
| `/mcp/` | MCP Streamable HTTP transport; use an MCP client rather than a normal REST request. |
| `/dashboard/gradio_api/mcp/` | Gradio-native MCP transport for documented dashboard actions. |
| `/mcp-health` | MCP transport discovery and custom tool count. |
| `/docs` | Root FastAPI Swagger UI when `ENABLE_API_DOCS=true`. |
| `/redoc` | Root FastAPI ReDoc UI when `ENABLE_API_DOCS=true`. |
| `/openapi.json` | Root renderer OpenAPI schema when `ENABLE_API_DOCS=true`. |
| `/<service>/docs` | Mounted service Swagger UI when `ENABLE_API_DOCS=true`. |
| `/<service>/openapi.json` | Mounted service OpenAPI schema when `ENABLE_API_DOCS=true`. |