ottoport 1.13.1 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -0
- package/cli/ottoport.mjs +31 -6
- package/commands/speech.md +4 -2
- package/commands/video.md +5 -0
- package/mcp/server.mjs +13 -11
- package/package.json +1 -1
- package/skills/ottoport/SKILL.md +4 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ottoport",
|
|
3
3
|
"description": "One API for every model. Call chat, image, video, speech and music models through the OttoPort gateway — as MCP tools, slash commands, or the bundled CLI.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.14.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "LITBOX LLC",
|
|
7
7
|
"email": "support@ottoport.ai"
|
package/README.md
CHANGED
|
@@ -30,6 +30,7 @@ ottoport video "<prompt>" [--model kling-3.0] [--duration 5] [--resolution 1080p
|
|
|
30
30
|
ottoport webhook status|retry <job-id> # delivery attempts / redeliver now
|
|
31
31
|
ottoport speech "<text>" [--model gpt-4o-mini-tts] [--voice alloy] [--out speech.mp3]
|
|
32
32
|
ottoport music "<prompt>" [--model suno-v5] [--duration 15] [--out song.mp3]
|
|
33
|
+
ottoport music --model mirelo-sfx-2.0 --video <url> [--duration 8] # soundtrack for a video
|
|
33
34
|
|
|
34
35
|
ottoport install <host> # wire the MCP server into an agent
|
|
35
36
|
ottoport mcp # run the MCP server on stdio
|
package/cli/ottoport.mjs
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
// ottoport video "prompt" [--model kling-3.0] [--duration 5] [--out clip.mp4]
|
|
11
11
|
// ottoport speech "text" [--model gpt-4o-mini-tts] [--voice alloy] [--out speech.mp3]
|
|
12
12
|
// ottoport music "prompt" [--model suno-v5] [--duration 15] [--out song.mp3]
|
|
13
|
+
// ottoport music --model mirelo-sfx-2.0 --video <url> [--duration 8]
|
|
13
14
|
// ottoport collections [list | create "name"]
|
|
14
15
|
// ottoport mcp
|
|
15
16
|
// ottoport install <codex|claude|hermes|cursor|windsurf|claude-desktop>
|
|
@@ -24,6 +25,9 @@ import { readFile, stat, writeFile } from "node:fs/promises";
|
|
|
24
25
|
const BASE = "https://ottoport.ai";
|
|
25
26
|
|
|
26
27
|
// ── arg parsing ──────────────────────────────────────────────────────
|
|
28
|
+
// Switches that never take a value, so `--draft "a boat"` keeps its prompt.
|
|
29
|
+
const BOOLEAN_FLAGS = new Set(["draft"]);
|
|
30
|
+
|
|
27
31
|
function parseArgs(argv) {
|
|
28
32
|
const positional = [];
|
|
29
33
|
const flags = {};
|
|
@@ -33,7 +37,7 @@ function parseArgs(argv) {
|
|
|
33
37
|
const key = a.slice(2);
|
|
34
38
|
if (key.startsWith("no-")) {
|
|
35
39
|
flags[key.slice(3)] = false;
|
|
36
|
-
} else if (i + 1 < argv.length && !argv[i + 1].startsWith("--")) {
|
|
40
|
+
} else if (!BOOLEAN_FLAGS.has(key) && i + 1 < argv.length && !argv[i + 1].startsWith("--")) {
|
|
37
41
|
const value = argv[++i];
|
|
38
42
|
// Repeats accumulate rather than overwrite, so `--ref a --ref b` keeps
|
|
39
43
|
// both. Everything downstream reads the last value of a scalar flag,
|
|
@@ -297,10 +301,14 @@ async function cmdImage(prompt, flags) {
|
|
|
297
301
|
|
|
298
302
|
async function cmdVideo(prompt, flags) {
|
|
299
303
|
// A depth model needs only --video; the gateway refuses a prompt there.
|
|
300
|
-
|
|
304
|
+
// A draft's 1080p render takes everything from the draft, the prompt included.
|
|
305
|
+
const draftId = last(flags["draft-id"]);
|
|
306
|
+
if (!prompt && !last(flags.video) && !draftId) die("video requires a prompt: ottoport video \"a drone shot\" (or --video <url> on a depth model)");
|
|
301
307
|
const { baseUrl, apiKey } = config(flags);
|
|
308
|
+
// Drafts are Seedance 2.5's, so a draft with no model named is one of its.
|
|
309
|
+
const model = last(flags.model) || (flags.draft === true || draftId ? "seedance-2.5" : "kling-3.0");
|
|
302
310
|
const body = {
|
|
303
|
-
model
|
|
311
|
+
model,
|
|
304
312
|
...(prompt ? { prompt } : {}),
|
|
305
313
|
...(last(flags.video) ? { video_url: last(flags.video) } : {}),
|
|
306
314
|
...(last(flags.duration) ? { duration: Number(last(flags.duration)) } : {}),
|
|
@@ -312,6 +320,8 @@ async function cmdVideo(prompt, flags) {
|
|
|
312
320
|
...(references(flags) ? { reference_image_urls: references(flags) } : {}),
|
|
313
321
|
...(references(flags, "ref-video") ? { reference_video_urls: references(flags, "ref-video") } : {}),
|
|
314
322
|
...(references(flags, "ref-audio") ? { reference_audio_urls: references(flags, "ref-audio") } : {}),
|
|
323
|
+
...(flags.draft === true ? { draft: true } : {}),
|
|
324
|
+
...(draftId ? { draft_id: draftId } : {}),
|
|
315
325
|
...webhook(flags),
|
|
316
326
|
...collection(flags),
|
|
317
327
|
};
|
|
@@ -338,6 +348,10 @@ async function cmdVideo(prompt, flags) {
|
|
|
338
348
|
const url = job.data?.[0]?.url;
|
|
339
349
|
if (url) {
|
|
340
350
|
console.log(outputLine(job.data[0]));
|
|
351
|
+
// The draft's job id is what renders it in 1080p, so say it.
|
|
352
|
+
if (!draftId && (body.draft || model.endsWith("-draft"))) {
|
|
353
|
+
process.stderr.write(`draft ${job.id} — render it in 1080p within seven days: ottoport video --model ${model} --draft-id ${job.id}\n`);
|
|
354
|
+
}
|
|
341
355
|
if (flags.out) await download(url, last(flags.out));
|
|
342
356
|
} else {
|
|
343
357
|
console.log(JSON.stringify(job, null, 2));
|
|
@@ -381,11 +395,14 @@ async function cmdWebhook(action, jobId, flags) {
|
|
|
381
395
|
}
|
|
382
396
|
|
|
383
397
|
async function cmdAudio(kind, prompt, flags) {
|
|
384
|
-
|
|
398
|
+
// A sound-effects model scores a video, so the prompt is optional with one.
|
|
399
|
+
const video = kind === "music" ? last(flags.video) : undefined;
|
|
400
|
+
if (!prompt && !video) die(`${kind} requires a prompt: ottoport ${kind} "hello"`);
|
|
385
401
|
const { baseUrl, apiKey } = config(flags);
|
|
386
402
|
const body = {
|
|
387
403
|
model: last(flags.model) || (kind === "speech" ? "gpt-4o-mini-tts" : "suno-v5"),
|
|
388
|
-
prompt,
|
|
404
|
+
...(prompt ? { prompt } : {}),
|
|
405
|
+
...(video ? { video_url: video } : {}),
|
|
389
406
|
...(last(flags.voice) ? { voice: last(flags.voice) } : {}),
|
|
390
407
|
...(last(flags.duration) ? { duration: Number(last(flags.duration)) } : {}),
|
|
391
408
|
...(last(flags.format) ? { format: last(flags.format) } : {}),
|
|
@@ -475,14 +492,20 @@ Usage:
|
|
|
475
492
|
[--aspect-ratio 16:9] [--seed 7] [--image <url>]
|
|
476
493
|
[--last-frame <url>] [--ref <url>[,<url>…]]
|
|
477
494
|
[--ref-video <url>[,<url>…]] [--ref-audio <url>[,<url>…]]
|
|
478
|
-
[--webhook-url https://…] [--webhook-secret <s>]
|
|
495
|
+
[--draft] [--webhook-url https://…] [--webhook-secret <s>]
|
|
479
496
|
[--no-wait] [--out clip.mp4]
|
|
497
|
+
ottoport video --draft-id <job-id> [--model seedance-2.5] [--out clip.mp4]
|
|
498
|
+
render a Seedance 2.5 draft (--draft, or the
|
|
499
|
+
seedance-2.5-draft model) in 1080p, within 7 days
|
|
480
500
|
ottoport video --model video-depth-anything --video <url> [--out depth.mp4]
|
|
481
501
|
turn a video (≤60s) into a grayscale depth video
|
|
482
502
|
ottoport webhook status <job-id> [--json] delivery attempts and responses
|
|
483
503
|
ottoport webhook retry <job-id> [--json] redeliver a finished job's webhook now
|
|
484
504
|
ottoport speech "<text>" [--model gpt-4o-mini-tts] [--voice alloy] [--format mp3] [--out speech.mp3]
|
|
485
505
|
ottoport music "<prompt>" [--model suno-v5] [--duration 15] [--format mp3] [--out song.mp3]
|
|
506
|
+
ottoport music ["<prompt>"] --model mirelo-sfx-2.0 --video <url> [--duration 8] [--out sfx.wav]
|
|
507
|
+
a soundtrack synced to the video, dialogue kept;
|
|
508
|
+
set --duration to the clip's length (it bills)
|
|
486
509
|
ottoport collections [list] [--json] collections in the key's project
|
|
487
510
|
ottoport collections create "<name>" [--description "..."] [--external-id <id>]
|
|
488
511
|
ottoport mcp
|
|
@@ -512,6 +535,8 @@ Examples:
|
|
|
512
535
|
ottoport image --model seedream-5.0-layers --image https://…/poster.png
|
|
513
536
|
ottoport speech "Welcome to OttoPort" --voice alloy --out welcome.mp3
|
|
514
537
|
ottoport music "lo-fi focus beat" --duration 20 --out focus.mp3
|
|
538
|
+
ottoport music "rain on a tin roof" --model mirelo-sfx-2.0 --duration 10 --format mp3 --out rain.mp3
|
|
539
|
+
ottoport music --model mirelo-sfx-2.0 --video https://example.com/chase.mp4 --duration 8 --out chase.wav
|
|
515
540
|
ottoport collections create "Spring campaign"
|
|
516
541
|
ottoport image "spring hero banner" --collection <collection-id>
|
|
517
542
|
ottoport mcp
|
package/commands/speech.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Turn text into speech, or a prompt into music, through the OttoPort gateway
|
|
2
|
+
description: Turn text into speech, or a prompt into music or sound effects, through the OttoPort gateway
|
|
3
3
|
argument-hint: "<text> [--voice alloy] [--music]"
|
|
4
4
|
allowed-tools: mcp__ottoport__ottoport_generate_speech, mcp__ottoport__ottoport_generate_music, Bash(curl:*)
|
|
5
5
|
---
|
|
@@ -7,7 +7,9 @@ allowed-tools: mcp__ottoport__ottoport_generate_speech, mcp__ottoport__ottoport_
|
|
|
7
7
|
Request: $ARGUMENTS
|
|
8
8
|
|
|
9
9
|
Use `ottoport_generate_music` when the request is for music, a song, or a
|
|
10
|
-
backing track
|
|
10
|
+
backing track — or for sound effects, ambience or a soundtrack for a video, with
|
|
11
|
+
`model` `mirelo-sfx-2.0` (pass the video as `video_url`, and `duration` as its
|
|
12
|
+
length); otherwise use `ottoport_generate_speech` to read the text aloud.
|
|
11
13
|
Pass `voice` and `format` only when named — speech defaults to `gpt-4o-mini-tts`
|
|
12
14
|
with the `alloy` voice, music to `suno-v5`.
|
|
13
15
|
|
package/commands/video.md
CHANGED
|
@@ -22,6 +22,11 @@ Request: $ARGUMENTS
|
|
|
22
22
|
discovering it from a failed call.
|
|
23
23
|
- `resolution` is billed: a 1080p or 4k clip costs more per second than the
|
|
24
24
|
model's base tier. Send one only when the request asks for it.
|
|
25
|
+
- When the user wants to preview before paying for the full clip, draft it:
|
|
26
|
+
`model: "seedance-2.5-draft"` (or `seedance-2.5` with `draft: true`) renders
|
|
27
|
+
a cheap 480p take. To keep it, call again with the same model and
|
|
28
|
+
`draft_id` set to the draft's job id — nothing else; it renders that shot in
|
|
29
|
+
1080p, within seven days.
|
|
25
30
|
- Video generation takes a minute or more and the call blocks until the job is
|
|
26
31
|
terminal. Say so before you start, and do not retry a call that is merely slow
|
|
27
32
|
— a retry is a second billable generation.
|
package/mcp/server.mjs
CHANGED
|
@@ -358,7 +358,8 @@ async function generateVideo({ prompt, model, webhook_url, webhook_secret, colle
|
|
|
358
358
|
const output = job.data?.[0];
|
|
359
359
|
const url = output?.url ? outputLine(output) : undefined;
|
|
360
360
|
// The draft's job id is what completes it, so it is worth saying.
|
|
361
|
-
|
|
361
|
+
// `seedance-2.5-draft` drafts without being told to.
|
|
362
|
+
if (url && !rest.draft_id && (rest.draft || /-draft$/.test(model ?? ""))) return `${url}\nDraft ${job.id} — complete it at 1080p with draft_id "${job.id}" within seven days.`;
|
|
362
363
|
return url || JSON.stringify(job);
|
|
363
364
|
}
|
|
364
365
|
|
|
@@ -374,15 +375,16 @@ async function videoWebhook({ job_id, action = "status" }) {
|
|
|
374
375
|
return JSON.stringify({ id: body.id, status: body.status, webhook: body.webhook ?? null }, null, 2);
|
|
375
376
|
}
|
|
376
377
|
|
|
377
|
-
async function generateAudio(kind, { prompt, model, voice, duration, format, collection }) {
|
|
378
|
-
if (!prompt) throw new Error("`prompt` is required");
|
|
378
|
+
async function generateAudio(kind, { prompt, model, voice, duration, format, video_url, collection }) {
|
|
379
|
+
if (!prompt && !video_url) throw new Error("`prompt` is required");
|
|
379
380
|
const res = await fetch(`${BASE}/api/v1/audio/${kind === "tts" ? "speech" : "music"}`, {
|
|
380
381
|
method: "POST",
|
|
381
382
|
headers: headers(),
|
|
382
383
|
body: JSON.stringify({
|
|
383
384
|
model: model || (kind === "tts" ? "gpt-4o-mini-tts" : "suno-v5"),
|
|
384
|
-
prompt,
|
|
385
|
+
...(prompt ? { prompt } : {}),
|
|
385
386
|
...(voice ? { voice } : {}),
|
|
387
|
+
...(video_url ? { video_url } : {}),
|
|
386
388
|
...(duration ? { duration } : {}),
|
|
387
389
|
...(format ? { format } : {}),
|
|
388
390
|
...withCollection(await collectionId(collection)),
|
|
@@ -458,7 +460,7 @@ const TOOLS = [
|
|
|
458
460
|
},
|
|
459
461
|
{
|
|
460
462
|
name: "ottoport_generate_video",
|
|
461
|
-
description: "Generate a video through an OttoPort video model (Veo, Kling, Seedance, …). Modes: text-to-video, image-to-video (`image_url`), first-and-last-frame (plus `last_frame_url`), reference-to-video (`reference_image_urls`, plus `reference_video_urls` / `reference_audio_urls` on models whose capabilities list `referenceMedia`), and on some models video edit/extend (`video_url`). Seedance 2.5 also drafts: `draft: true` renders a cheap 480p preview, and `draft_id` set to that job's id renders the same shot at 1080p. video-depth-anything instead turns `video_url` into a grayscale depth video and takes no prompt. Kling motion control (`kling-2.6-motion-control`, `kling-3.0-motion-control` and their `-pro` variants) makes the character in `image_url` perform the movement in `video_url`; the prompt is optional and the output runs as long as the clip. Which a model accepts is in its capabilities — call ottoport_list_models. Blocks on the queue and returns a video URL, unless `webhook_url` is given.",
|
|
463
|
+
description: "Generate a video through an OttoPort video model (Veo, Kling, Seedance, …). Modes: text-to-video, image-to-video (`image_url`), first-and-last-frame (plus `last_frame_url`), reference-to-video (`reference_image_urls`, plus `reference_video_urls` / `reference_audio_urls` on models whose capabilities list `referenceMedia`), and on some models video edit/extend (`video_url`). Seedance 2.5 also drafts: `draft: true` (or the model `seedance-2.5-draft`, where every request is a draft) renders a cheap 480p preview, and `draft_id` set to that job's id renders the same shot at 1080p. video-depth-anything instead turns `video_url` into a grayscale depth video and takes no prompt. Kling motion control (`kling-2.6-motion-control`, `kling-3.0-motion-control` and their `-pro` variants) makes the character in `image_url` perform the movement in `video_url`; the prompt is optional and the output runs as long as the clip. Which a model accepts is in its capabilities — call ottoport_list_models. Blocks on the queue and returns a video URL, unless `webhook_url` is given.",
|
|
462
464
|
inputSchema: {
|
|
463
465
|
type: "object",
|
|
464
466
|
properties: {
|
|
@@ -480,8 +482,8 @@ const TOOLS = [
|
|
|
480
482
|
character_orientation: { type: "string", enum: ["video", "image"], description: "Motion-control models only: whether the character faces the way the person in `video_url` does (\"video\", the default) or keeps the pose of `image_url` (\"image\")." },
|
|
481
483
|
keep_original_sound: { type: "boolean", description: "Motion-control models only: keep the audio of `video_url` in the result." },
|
|
482
484
|
video_task: { type: "string", enum: ["edit", "extend"], description: "edit (default) restyles video_url; extend continues it for `duration` more seconds." },
|
|
483
|
-
draft: { type: "boolean", description: "
|
|
484
|
-
draft_id: { type: "string", description: "
|
|
485
|
+
draft: { type: "boolean", description: "seedance-2.5 only (implied on seedance-2.5-draft): render a 480p preview at about a quarter of the 1080p price, to check the shot before paying for it. Text, image and reference-image requests; no `resolution`." },
|
|
486
|
+
draft_id: { type: "string", description: "seedance-2.5 or seedance-2.5-draft: the job id of a finished draft, to render that same shot at 1080p — either id completes a draft made with the other. Send `model` and this alone — prompt, inputs and duration come from the draft. Within seven days of the draft." },
|
|
485
487
|
webhook_url: { type: "string", description: "Public HTTPS endpoint to POST the finished job to (events video.completed / video.failed, signed with HMAC-SHA256). With it the tool returns the job id at once instead of waiting." },
|
|
486
488
|
webhook_secret: { type: "string", description: "Signing secret for webhook_url. Omit to use the server's OTTOPORT_WEBHOOK_SECRET." },
|
|
487
489
|
collection: { type: "string", description: "Save the result for good into this collection — its id or exact name (see ottoport_list_collections). Without it the file expires after a few days. Needs collections unlocked on the account. Defaults to OTTOPORT_COLLECTION when set." },
|
|
@@ -521,17 +523,17 @@ const TOOLS = [
|
|
|
521
523
|
},
|
|
522
524
|
{
|
|
523
525
|
name: "ottoport_generate_music",
|
|
524
|
-
description: "Generate music from a prompt through an OttoPort music model. Returns an audio URL or data URL.",
|
|
526
|
+
description: "Generate music or sound effects from a prompt through an OttoPort music model — or, with mirelo-sfx-2.0 and a video_url, a soundtrack synced to that video. Returns an audio URL or data URL.",
|
|
525
527
|
inputSchema: {
|
|
526
528
|
type: "object",
|
|
527
529
|
properties: {
|
|
528
|
-
prompt: { type: "string", description: "Music-generation prompt." },
|
|
529
|
-
model: { type: "string", description: "Music model id. Default suno-v5." },
|
|
530
|
+
prompt: { type: "string", description: "Music-generation prompt, or the sounds to make. Optional with video_url." },
|
|
531
|
+
model: { type: "string", description: "Music model id. Default suno-v5; mirelo-sfx-2.0 for sound effects." },
|
|
530
532
|
duration: { type: "number", description: "Requested duration in seconds." },
|
|
533
|
+
video_url: { type: "string", description: "mirelo-sfx-2.0 only: an http(s) video to score. Set duration to its length — duration is what bills." },
|
|
531
534
|
format: { type: "string", description: 'e.g. "mp3" or "wav".' },
|
|
532
535
|
collection: { type: "string", description: "Save the result for good into this collection — its id or exact name (see ottoport_list_collections). Without it the file expires after a few days. Needs collections unlocked on the account. Defaults to OTTOPORT_COLLECTION when set." },
|
|
533
536
|
},
|
|
534
|
-
required: ["prompt"],
|
|
535
537
|
},
|
|
536
538
|
handler: (args) => generateAudio("music", args),
|
|
537
539
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ottoport",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "Claude Code plugin, CLI and MCP server for OttoPort — one OpenAI-compatible API for every LLM, image, video, and speech model.",
|
|
5
5
|
"homepage": "https://ottoport.ai",
|
|
6
6
|
"repository": {
|
package/skills/ottoport/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ottoport
|
|
3
|
-
description: Generate text, images, video, speech, and music through OttoPort — one gateway for every model (GPT, Claude, Gemini, GPT Image, Nano Banana, Veo, Kling, Seedance, Suno). Use when the user wants to call an LLM or generate an image, video, or
|
|
3
|
+
description: Generate text, images, video, speech, and music through OttoPort — one gateway for every model (GPT, Claude, Gemini, GPT Image, Nano Banana, Veo, Kling, Seedance, Suno, Mirelo). Use when the user wants to call an LLM or generate an image, video, audio or sound effects and has OttoPort configured, or asks to "use OttoPort".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# OttoPort
|
|
@@ -17,10 +17,10 @@ and do not call the HTTP API, when a tool covers the job:
|
|
|
17
17
|
| `ottoport_list_models` | The catalog: what each model is for, and its rate in credits and USD. Filter with `modality`, or pass `model` for ONE model in full — its modes, its resolution tiers with prices, and every parameter it reads. |
|
|
18
18
|
| `ottoport_chat` | `prompt`, plus optional `model`, `system`, `temperature`, `max_tokens`. |
|
|
19
19
|
| `ottoport_generate_image` | `prompt`, plus optional `model`, `size` or `resolution`, `quality` (GPT Image and Ideogram), `aspect_ratio`, `n`, `seed`, `image_url` (one reference), `reference_image_urls` (several). Layer decomposition too: `model` `qwen-image-layered` or `seedream-5.0-layers` with `image_url` alone (prompt optional, `num_layers` on Qwen) returns one URL per RGBA layer. |
|
|
20
|
-
| `ottoport_generate_video` | `prompt`, plus optional `model`, `duration`, `resolution`, `aspect_ratio`, `seed`, `image_url` (first frame), `last_frame_url`, `reference_image_urls`, `reference_video_urls` / `reference_audio_urls` (models listing `referenceMedia`), `video_url` (edit / extend, or the movement for motion control), `character_orientation` / `keep_original_sound` (motion control), `draft` / `draft_id` (Seedance 2.5: a 480p preview, then the same shot at 1080p from the preview's job id), `webhook_url` (returns the job id at once and POSTs the result there; the secret comes from `webhook_secret` or the server's `OTTOPORT_WEBHOOK_SECRET`). |
|
|
20
|
+
| `ottoport_generate_video` | `prompt`, plus optional `model`, `duration`, `resolution`, `aspect_ratio`, `seed`, `image_url` (first frame), `last_frame_url`, `reference_image_urls`, `reference_video_urls` / `reference_audio_urls` (models listing `referenceMedia`), `video_url` (edit / extend, or the movement for motion control), `character_orientation` / `keep_original_sound` (motion control), `draft` / `draft_id` (Seedance 2.5: a 480p preview, then the same shot at 1080p from the preview's job id; the model `seedance-2.5-draft` drafts on every request without `draft`), `webhook_url` (returns the job id at once and POSTs the result there; the secret comes from `webhook_secret` or the server's `OTTOPORT_WEBHOOK_SECRET`). |
|
|
21
21
|
| `ottoport_video_webhook` | `job_id`, plus `action` `status` (every delivery attempt and the endpoint's response) or `retry` (redeliver a finished job's webhook now). |
|
|
22
22
|
| `ottoport_generate_speech` | `prompt` (the text), plus optional `model`, `voice`, `format`. |
|
|
23
|
-
| `ottoport_generate_music` | `prompt`, plus optional `model`, `duration`, `format`. |
|
|
23
|
+
| `ottoport_generate_music` | `prompt`, plus optional `model`, `duration`, `format`. Sound effects too: `model` `mirelo-sfx-2.0` makes them from the prompt, or with `video_url` a soundtrack synced to that video, dialogue kept (prompt then optional). It bills per requested second, so set `duration` to the clip's length. |
|
|
24
24
|
| `ottoport_list_collections` | The project's collections (ids, asset counts) and whether this account may save. Read it to find the collection the user means. |
|
|
25
25
|
| `ottoport_create_collection` | `name`, plus optional `description`, `external_id`. |
|
|
26
26
|
| `ottoport_list_assets` | Saved files, optionally by `collection` and `kind`. |
|
|
@@ -90,7 +90,7 @@ sensible default.
|
|
|
90
90
|
| image | `gpt-image-2` | `nano-banana-2.1` (fast generation and edits), `nano-banana-pro` (high fidelity) |
|
|
91
91
|
| video | `kling-3.0` | `seedance-2.0-fast` (cheap), `veo-3.1` (with audio) |
|
|
92
92
|
| speech | `gpt-4o-mini-tts` | `eleven-v3` |
|
|
93
|
-
| music | `suno-v5` | `lyria-2` |
|
|
93
|
+
| music | `suno-v5` | `lyria-2`, `mirelo-sfx-2.0` (sound effects, or a soundtrack for a video) |
|
|
94
94
|
|
|
95
95
|
Never invent a model id. Call `ottoport_list_models` when unsure — the catalog
|
|
96
96
|
changes, and a wrong id is a failed billable call. Rates come back in credits (the unit the ledger
|