This repository was archived by the owner on Oct 25, 2026. It is now read-only.
Repository navigation
Expand file tree
/
Copy pathsite-data.json
More file actions
2497 lines (2497 loc) · 111 KB
/
Copy pathsite-data.json
File metadata and controls
2497 lines (2497 loc) · 111 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
{
"pack_version": "2.4.2",
"source": "https://github.com/gitroomhq/agent-media",
"connector": {
"url": "https://api.agent-media.ai/mcp",
"transport": "streamable-http",
"auth": "OAuth 2.1 with dynamic client registration (browser sign-in); `Authorization: Bearer ma_...` API keys also accepted.",
"clients": [
{
"id": "claude",
"label": "Claude.ai / Claude Desktop / Cowork",
"how": "Customize > Connectors > + > Add custom connector > paste the URL > Connect and sign in. Enable Agent Media in the conversation connector menu."
},
{
"id": "claude-code",
"label": "Claude Code",
"command": "claude mcp add --transport http --scope user agent-media https://api.agent-media.ai/mcp",
"note": "Available in all your projects. In Claude Code, run /mcp, select agent-media, and complete browser sign-in. If already connected, do not add a second copy."
},
{
"id": "chatgpt",
"label": "ChatGPT (web)",
"how": "Enable Developer mode where your account or workspace permits it. Create a custom MCP app with the connector URL and OAuth, complete sign-in, then select Agent Media in the conversation. Refresh the app tools when the catalog changes.",
"note": "Settings labels and availability vary by account and workspace policy. See the linked official ChatGPT setup guide below."
},
{
"id": "codex",
"label": "Codex",
"command": "codex mcp add agent-media --url https://api.agent-media.ai/mcp",
"note": "Then run codex mcp login agent-media to complete browser sign-in. Keep your normal approval settings; review requested tool actions."
},
{
"id": "grok",
"label": "Grok CLI",
"command": "grok mcp add --transport http agent-media https://api.agent-media.ai/mcp"
},
{
"id": "cursor",
"label": "Cursor",
"config": "{ \"mcpServers\": { \"agent-media\": { \"url\": \"https://api.agent-media.ai/mcp\" } } }",
"note": "~/.cursor/mcp.json"
},
{
"id": "local",
"label": "Any stdio client",
"command": "npx -y -p @agentmedia/mcp-server@latest agent-media-mcp",
"note": "A stdio proxy to the same hosted server; set AGENT_MEDIA_API_KEY. Do not register both the connector and the proxy in one client, or every tool appears twice."
}
],
"prompt": "Set up agent-media so I can generate videos, images and voice from here.\n1. Add the MCP server: https://api.agent-media.ai/mcp (Streamable HTTP).\n2. Authenticate: complete the sign-in in the browser it opens.\n3. Call get_account and tell me whether the account is ready.\n4. Explain that you can freely combine the direct generators or use make_ugc as an optional composed shortcut.\n5. Open the existing image upload panel using open_upload_panel, or upload_image with {} if only the older tools are available. Do not generate anything yet.",
"polling": "Every generate tool returns a job id. Call get_run_status with wait:true; each call blocks up to about 45 seconds, a video usually needs several calls (seedance-2.0: about 3 minutes for a 5 s clip at 720p; seedance-2.5: 12 to 25 minutes per clip; plan the wait). Never report a result before get_run_status returned its URL."
},
"tools": [
{
"name": "make_ugc",
"title": "Make UGC Video",
"read_only": false,
"spends_credits": true,
"description": "Optional convenience workflow for one finished vertical UGC video from a script. Use it when the user wants the server to choose takes and timing, join a long monologue, and optionally burn captions. Use the direct generate_image, generate_video and generate_audio tools instead when the agent needs custom models, modes, shot structure, intermediate assets, or a different composition. Use `image` for a person photo, `product_image` for a product photo, or `character` for a saved character. Call `quote_ugc` with the exact same input first; it costs no credits. Ask before setting captions:true. After submission, keep calling get_run_status until it returns the finished video URL.\n\nWhen the user wants to provide a product photo, portrait, screenshot, or image reference, check tools/list. If open_upload_panel is available, offer it first: call open_upload_panel with {}, show its inline panel or returned browser link, and wait for the user to finish. Then call get_uploads with the returned session_id and use the exact ready image_url in refs, first_frame, last_frame, or the matching skill image field. Do not start a reference-dependent generation until the required images are ready. The panel accepts still PNG, JPEG, and WebP, up to 10 images and 25 MB each. Images expire 24 hours after the panel is created; show the returned expiry, request a new upload if expired, and never make a permanent copy. Uploading uses no generation credits. Do not ask the user for base64, shell commands, or a public hosting service; do not continuously poll while waiting for them. Only call these tool names when discovered. If they are missing from the connected tool catalog, call upload_image with {} to open the same panel; use the returned panel: upload_key with upload_image to retrieve images after the user finishes. If that reports the panel is unavailable, use upload_image only for an already accessible file or URL. Do not build an upload page or request a local folder as a substitute for the existing panel. Never invent access to a chat attachment: if you cannot read it, explain that and offer the panel when available. Browser fallback works without inline UI support; do not promise an inline panel in every client.\nInspect the native image previews returned with retrieved uploads before describing them or writing image-specific prompts. Never infer what the image shows from an email domain, account metadata, or filename. Use the original URLs for generation, not preview bytes. If the session ID was lost, call get_uploads with {} to list recent sessions, or upload_image with {\"upload_key\":\"panel:recent\"} for cached catalogs; retrieve the matching session before asking for re-upload. Account-wide recent uploads may belong to other conversations, so clarify ambiguous selection. Uploading stores an image; it does not attach it to a generation automatically. If the user already requested a generation with these images, continue that request using the returned URLs; do not stop at \"upload complete\" or ask again whether to use them. If make_ugc fits the requested outcome, pass a person photo as image or a product photo as product_image, then call quote_ugc before spending. Otherwise compose the direct generators: for generate_image, put the relevant image_url values in refs; for generate_video, use refs for product/person/appearance references, or first_frame for animating a still (last_frame only for an explicitly requested ending frame), and never combine refs with frame fields. Preserve the user's intended image roles and model limits; ask only if the role or selection is unclear. Include the URL in the tool arguments, not only in the prompt. Do not substitute a newly generated image for the uploaded reference. If the request was upload-only, report readiness and wait for a generation request; uploading alone does not authorize spending credits. After submitting, poll get_run_status and return the result.\n\nIMAGES: pass an https URL. If you only have raw bytes or a data: URL, call `upload_image` FIRST and pass the URL it returns. Never paste base64 into these arguments, the client prints tool arguments in the conversation, so a base64 image becomes a wall of text for the user and is re-sent on every retry.",
"input_schema": {
"type": "object",
"properties": {
"script": {
"type": "string",
"minLength": 1,
"maxLength": 1200,
"description": "What the person SAYS (lip-synced), any length. A one-liner makes one clip; a full monologue makes the full multi-take video automatically, never trimmed. Usually the only field you set. EXCEPTION: when you also pass product_image the video is a SINGLE take of at most 15s, so the script must be ~33 words or fewer."
},
"scene_action": {
"type": "string",
"minLength": 3,
"maxLength": 400,
"description": "A silent action clip (dancing, b-roll, vibes), no dialogue. Use instead of script; needs a `character`."
},
"person": {
"type": "string",
"minLength": 8,
"maxLength": 400,
"description": "Describe the person in words. Omit if you pass image or character."
},
"image": {
"type": "string",
"description": "A photo of the person, an https URL. The face is locked to it. If you only hold bytes, call `upload_image` first and pass the URL it returns; base64 is still accepted here but it is printed into the user’s chat and re-sent on every retry."
},
"character": {
"type": "string",
"description": "Reuse a saved character: its character_id (char_…) OR its character_sheet_url from list_characters."
},
"product_image": {
"type": "string",
"description": "A photo of a PRODUCT to show/hold/wear, an https URL. If you only hold bytes, call `upload_image` first and pass the URL it returns: base64 travels inside this tool call, is printed into the user’s chat, and is re-sent on every retry. Turns the video into a product ad; needs a `character` to hold it, and limits `script` to ONE take of at most 15s (~33 words)."
},
"name": {
"type": "string",
"maxLength": 80,
"description": "Name/age/vibe hint, e.g. 'Sophia, 28'."
},
"broll_url": {
"type": "string",
"format": "uri",
"pattern": "^https:\\/\\/",
"description": "A b-roll / gameplay / product video overlaid on the lower half while the person narrates."
},
"duration": {
"type": "number",
"enum": [
5,
10,
15,
20,
25,
30
],
"description": "IGNORED when `script` is set, length is derived from the word count (≤11 words → 5s, ≤22 → 10s, else 15s) because the renderer requires the script to fit the take. To get a shorter clip, write a shorter script. Only used for a silent `scene_action` clip, which has no words to measure."
},
"captions": {
"type": "boolean",
"description": "Burn in TikTok/Hormozi captions. OFF unless set true, ASK the user whether they want captions (and which caption_style) before generating; never add captions unprompted."
},
"caption_style": {
"type": "string",
"enum": [
"hormozi",
"tiktok",
"minimal"
],
"default": "hormozi"
},
"look": {
"type": "string",
"enum": [
"natural",
"commercial",
"raw_iphone"
],
"default": "natural"
},
"aspect_ratio": {
"type": "string",
"enum": [
"9:16",
"1:1"
],
"default": "9:16"
},
"music": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "string",
"maxLength": 120
}
]
}
},
"additionalProperties": false
}
},
{
"name": "quote_ugc",
"title": "Quote UGC Video",
"read_only": true,
"spends_credits": false,
"description": "Price an optional make_ugc workflow and check the spendable balance without rendering or using credits. Pass the exact input intended for make_ugc. Show the returned price to the user and only call make_ugc after the user has authorized that spend.",
"input_schema": {
"type": "object",
"properties": {
"script": {
"type": "string",
"minLength": 1,
"maxLength": 1200,
"description": "What the person SAYS (lip-synced), any length. A one-liner makes one clip; a full monologue makes the full multi-take video automatically, never trimmed. Usually the only field you set. EXCEPTION: when you also pass product_image the video is a SINGLE take of at most 15s, so the script must be ~33 words or fewer."
},
"scene_action": {
"type": "string",
"minLength": 3,
"maxLength": 400,
"description": "A silent action clip (dancing, b-roll, vibes), no dialogue. Use instead of script; needs a `character`."
},
"person": {
"type": "string",
"minLength": 8,
"maxLength": 400,
"description": "Describe the person in words. Omit if you pass image or character."
},
"image": {
"type": "string",
"description": "A photo of the person, an https URL. The face is locked to it. If you only hold bytes, call `upload_image` first and pass the URL it returns; base64 is still accepted here but it is printed into the user’s chat and re-sent on every retry."
},
"character": {
"type": "string",
"description": "Reuse a saved character: its character_id (char_…) OR its character_sheet_url from list_characters."
},
"product_image": {
"type": "string",
"description": "A photo of a PRODUCT to show/hold/wear, an https URL. If you only hold bytes, call `upload_image` first and pass the URL it returns: base64 travels inside this tool call, is printed into the user’s chat, and is re-sent on every retry. Turns the video into a product ad; needs a `character` to hold it, and limits `script` to ONE take of at most 15s (~33 words)."
},
"name": {
"type": "string",
"maxLength": 80,
"description": "Name/age/vibe hint, e.g. 'Sophia, 28'."
},
"broll_url": {
"type": "string",
"format": "uri",
"pattern": "^https:\\/\\/",
"description": "A b-roll / gameplay / product video overlaid on the lower half while the person narrates."
},
"duration": {
"type": "number",
"enum": [
5,
10,
15,
20,
25,
30
],
"description": "IGNORED when `script` is set, length is derived from the word count (≤11 words → 5s, ≤22 → 10s, else 15s) because the renderer requires the script to fit the take. To get a shorter clip, write a shorter script. Only used for a silent `scene_action` clip, which has no words to measure."
},
"captions": {
"type": "boolean",
"description": "Burn in TikTok/Hormozi captions. OFF unless set true, ASK the user whether they want captions (and which caption_style) before generating; never add captions unprompted."
},
"caption_style": {
"type": "string",
"enum": [
"hormozi",
"tiktok",
"minimal"
],
"default": "hormozi"
},
"look": {
"type": "string",
"enum": [
"natural",
"commercial",
"raw_iphone"
],
"default": "natural"
},
"aspect_ratio": {
"type": "string",
"enum": [
"9:16",
"1:1"
],
"default": "9:16"
},
"music": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "string",
"maxLength": 120
}
]
}
},
"additionalProperties": false
}
},
{
"name": "generate_video",
"title": "Generate Video",
"read_only": false,
"spends_credits": true,
"description": "Render a video clip from YOUR prompt on the model YOU choose, in one of three MODES that follow from the fields you pass: TEXT (prompt only), IMAGE-TO-VIDEO (`first_frame`: an https still that becomes frame one, optionally `last_frame` to end on; the clip animates the still) or REFERENCE (`refs`: https images such as a portrait, a character sheet from list_characters or a product photo whose identity/look is kept; `video_refs`: clips whose motion or framing is followed; `audio_refs`: a voice or sound to carry; address them in the prompt as @image1, @video1, @audio1). Frames and refs cannot be mixed. Write the shot like a director: who is in frame, where, what happens, camera, and the exact spoken words in quotes if anyone talks. Models: seedance-2.0, seedance-2.5 (default seedance-2.0; call list_models for each model's modes, limits, prices and recent results; or pass model:\"auto\"). Aspect: 9:16 default, also 16:9, 1:1, 4:3, 3:4, 21:9, adaptive. Quality: 480p, 720p (default), 1080p; the price per second follows the quality (seedance-2.0: 30 credits/s at 480p, 60 credits/s at 720p, 150 credits/s at 1080p). Reference clip seconds are billed like output seconds. Call `quote` first if the user cares about cost. Returns a job id, then call get_run_status until it is done and hand the user the URL.\n\nWhen the user wants to provide a product photo, portrait, screenshot, or image reference, check tools/list. If open_upload_panel is available, offer it first: call open_upload_panel with {}, show its inline panel or returned browser link, and wait for the user to finish. Then call get_uploads with the returned session_id and use the exact ready image_url in refs, first_frame, last_frame, or the matching skill image field. Do not start a reference-dependent generation until the required images are ready. The panel accepts still PNG, JPEG, and WebP, up to 10 images and 25 MB each. Images expire 24 hours after the panel is created; show the returned expiry, request a new upload if expired, and never make a permanent copy. Uploading uses no generation credits. Do not ask the user for base64, shell commands, or a public hosting service; do not continuously poll while waiting for them. Only call these tool names when discovered. If they are missing from the connected tool catalog, call upload_image with {} to open the same panel; use the returned panel: upload_key with upload_image to retrieve images after the user finishes. If that reports the panel is unavailable, use upload_image only for an already accessible file or URL. Do not build an upload page or request a local folder as a substitute for the existing panel. Never invent access to a chat attachment: if you cannot read it, explain that and offer the panel when available. Browser fallback works without inline UI support; do not promise an inline panel in every client.\nInspect the native image previews returned with retrieved uploads before describing them or writing image-specific prompts. Never infer what the image shows from an email domain, account metadata, or filename. Use the original URLs for generation, not preview bytes. If the session ID was lost, call get_uploads with {} to list recent sessions, or upload_image with {\"upload_key\":\"panel:recent\"} for cached catalogs; retrieve the matching session before asking for re-upload. Account-wide recent uploads may belong to other conversations, so clarify ambiguous selection. Uploading stores an image; it does not attach it to a generation automatically. If the user already requested a generation with these images, continue that request using the returned URLs; do not stop at \"upload complete\" or ask again whether to use them. If make_ugc fits the requested outcome, pass a person photo as image or a product photo as product_image, then call quote_ugc before spending. Otherwise compose the direct generators: for generate_image, put the relevant image_url values in refs; for generate_video, use refs for product/person/appearance references, or first_frame for animating a still (last_frame only for an explicitly requested ending frame), and never combine refs with frame fields. Preserve the user's intended image roles and model limits; ask only if the role or selection is unclear. Include the URL in the tool arguments, not only in the prompt. Do not substitute a newly generated image for the uploaded reference. If the request was upload-only, report readiness and wait for a generation request; uploading alone does not authorize spending credits. After submitting, poll get_run_status and return the result.\n\nIMAGES: pass an https URL. If you only have raw bytes or a data: URL, call `upload_image` FIRST and pass the URL it returns. Never paste base64 into these arguments, the client prints tool arguments in the conversation, so a base64 image becomes a wall of text for the user and is re-sent on every retry.\n\nRETRY SAFETY: set request_id to a fresh UUID for a new generation. Reuse the exact same request_id and inputs only to recover a lost response; that returns the original job without another charge. A deliberately new generation needs a new request_id. Keep the returned job_id and poll get_run_status. Never invent a refund.",
"input_schema": {
"type": "object",
"properties": {
"prompt": {
"type": "string",
"minLength": 3,
"maxLength": 4000,
"description": "The shot, as a director would say it: who (age, look), where (setting, light), what happens, camera (phone framing), and, if anyone speaks, the exact words in quotes. About 2.3 words per second. With references, address them as @image1, @video1, @audio1."
},
"model": {
"type": "string",
"description": "A live video model id from list_models, or \"auto\" to let agent-media pick from recent results. Omit for the default. Call list_models for what each model is good for, its modes, limits and price."
},
"first_frame": {
"type": "string",
"format": "uri",
"description": "IMAGE-TO-VIDEO: an https image that becomes frame one of the clip (a still you want animated, a product shot, a portrait). Cannot be combined with refs, video_refs or audio_refs on Seedance."
},
"last_frame": {
"type": "string",
"format": "uri",
"description": "Optional with first_frame: the image the clip ends on; the model animates from first to last."
},
"refs": {
"type": "array",
"items": {
"type": "string",
"format": "uri"
},
"maxItems": 30,
"description": "REFERENCE-TO-VIDEO: image references (https URLs): a portrait, a character sheet from list_characters, a product photo. The model keeps that identity/look. Address them in the prompt as @image1, @image2..."
},
"video_refs": {
"type": "array",
"items": {
"type": "string",
"format": "uri"
},
"maxItems": 10,
"description": "Reference clips (https mp4/mov) whose motion, framing or look the model should follow; @video1... in the prompt. Their seconds are billed like output seconds."
},
"audio_refs": {
"type": "array",
"items": {
"type": "string",
"format": "uri"
},
"maxItems": 10,
"description": "Reference audio (https wav/mp3): a voice or a sound the clip should carry; @audio1... in the prompt."
},
"seconds": {
"type": "integer",
"minimum": 1,
"maximum": 60,
"default": 5,
"description": "Clip length in seconds (the model sets the range; seedance 2.0: 4 to 15, seedance 2.5: 4 to 30). Credits = seconds x the per-second rate at the chosen quality."
},
"aspect": {
"type": "string",
"enum": [
"9:16",
"16:9",
"1:1",
"4:3",
"3:4",
"21:9",
"adaptive"
],
"description": "9:16 (default for text and reference), 16:9, 1:1, 4:3, 3:4, 21:9, or adaptive (follows the first frame or reference; the default and the only option in image mode on seedance-2.5)."
},
"quality": {
"type": "string",
"enum": [
"480p",
"720p",
"1080p"
],
"description": "480p (cheapest), 720p, 1080p (dearest). Omit for the model default: 480p on seedance-2.5, 720p on seedance-2.0. Price per second differs; see list_models."
},
"audio": {
"type": "boolean",
"default": true,
"description": "Render native audio (speech from the quoted words, ambience). false = silent clip."
},
"seed": {
"type": "integer",
"minimum": 0,
"maximum": 2147483647,
"description": "Only for models whose mode lists seed support (none of the live Seedance modes). Refused elsewhere."
},
"request_id": {
"type": "string",
"pattern": "^[A-Za-z0-9._:-]{1,128}$",
"description": "Unique request identity (prefer a UUID). Reuse with identical inputs to recover the same job after a lost response; choose a new identity only for an intentionally new generation."
}
},
"required": [
"prompt"
],
"additionalProperties": false
}
},
{
"name": "generate_image",
"title": "Generate Image",
"read_only": false,
"spends_credits": true,
"description": "Render one image from YOUR prompt. Without refs it paints from the prompt; with refs (https URLs) it edits/composes from them, a portrait to re-light, a product to place in a hand, a character sheet to pose. Use it to build the reference a video needs (portrait first, then generate_video with that URL in refs). Models: gpt-image-2.5, gpt-image-2.5-flare, gpt-image-2 (default gpt-image-2.5). Spends credits per image (see list_models). Returns a job id, poll get_run_status for the image URL.\n\nWhen the user wants to provide a product photo, portrait, screenshot, or image reference, check tools/list. If open_upload_panel is available, offer it first: call open_upload_panel with {}, show its inline panel or returned browser link, and wait for the user to finish. Then call get_uploads with the returned session_id and use the exact ready image_url in refs, first_frame, last_frame, or the matching skill image field. Do not start a reference-dependent generation until the required images are ready. The panel accepts still PNG, JPEG, and WebP, up to 10 images and 25 MB each. Images expire 24 hours after the panel is created; show the returned expiry, request a new upload if expired, and never make a permanent copy. Uploading uses no generation credits. Do not ask the user for base64, shell commands, or a public hosting service; do not continuously poll while waiting for them. Only call these tool names when discovered. If they are missing from the connected tool catalog, call upload_image with {} to open the same panel; use the returned panel: upload_key with upload_image to retrieve images after the user finishes. If that reports the panel is unavailable, use upload_image only for an already accessible file or URL. Do not build an upload page or request a local folder as a substitute for the existing panel. Never invent access to a chat attachment: if you cannot read it, explain that and offer the panel when available. Browser fallback works without inline UI support; do not promise an inline panel in every client.\nInspect the native image previews returned with retrieved uploads before describing them or writing image-specific prompts. Never infer what the image shows from an email domain, account metadata, or filename. Use the original URLs for generation, not preview bytes. If the session ID was lost, call get_uploads with {} to list recent sessions, or upload_image with {\"upload_key\":\"panel:recent\"} for cached catalogs; retrieve the matching session before asking for re-upload. Account-wide recent uploads may belong to other conversations, so clarify ambiguous selection. Uploading stores an image; it does not attach it to a generation automatically. If the user already requested a generation with these images, continue that request using the returned URLs; do not stop at \"upload complete\" or ask again whether to use them. If make_ugc fits the requested outcome, pass a person photo as image or a product photo as product_image, then call quote_ugc before spending. Otherwise compose the direct generators: for generate_image, put the relevant image_url values in refs; for generate_video, use refs for product/person/appearance references, or first_frame for animating a still (last_frame only for an explicitly requested ending frame), and never combine refs with frame fields. Preserve the user's intended image roles and model limits; ask only if the role or selection is unclear. Include the URL in the tool arguments, not only in the prompt. Do not substitute a newly generated image for the uploaded reference. If the request was upload-only, report readiness and wait for a generation request; uploading alone does not authorize spending credits. After submitting, poll get_run_status and return the result.\n\nIMAGES: pass an https URL. If you only have raw bytes or a data: URL, call `upload_image` FIRST and pass the URL it returns. Never paste base64 into these arguments, the client prints tool arguments in the conversation, so a base64 image becomes a wall of text for the user and is re-sent on every retry.\n\nRETRY SAFETY: set request_id to a fresh UUID for a new generation. Reuse the exact same request_id and inputs only to recover a lost response; that returns the original job without another charge. A deliberately new generation needs a new request_id. Keep the returned job_id and poll get_run_status. Never invent a refund.",
"input_schema": {
"type": "object",
"properties": {
"prompt": {
"type": "string",
"minLength": 3,
"maxLength": 4000,
"description": "What to paint. Be concrete: subject, age, framing, light, lens, mood, what the hands do."
},
"model": {
"type": "string",
"description": "A live image model id from list_models, or \"auto\" to let agent-media pick from recent results. Omit for the default (gpt-image-2)."
},
"refs": {
"type": "array",
"items": {
"type": "string",
"format": "uri"
},
"maxItems": 4,
"description": "Reference images (https URLs, up to 4). With refs the model EDITS/composes from them (a product into a hand, a portrait re-lit); without, it paints from the prompt alone."
},
"size": {
"type": "string",
"enum": [
"1024x1024",
"1024x1536",
"1536x1024"
],
"default": "1024x1536",
"description": "1024x1536 portrait (default, for 9:16 video), 1024x1024 square, 1536x1024 landscape."
},
"request_id": {
"type": "string",
"pattern": "^[A-Za-z0-9._:-]{1,128}$",
"description": "Unique request identity (prefer a UUID). Reuse with identical inputs to recover the same job after a lost response; choose a new identity only for an intentionally new generation."
}
},
"required": [
"prompt"
],
"additionalProperties": false
}
},
{
"name": "generate_audio",
"title": "Generate Audio",
"read_only": false,
"spends_credits": true,
"description": "Speak text in a named voice (jessica, sarah, liam, chris, lily, bill, matilda, or a raw ElevenLabs voice id). Emotion tags like [excited] or [whispers] are honoured. For a talking-head clip you usually do NOT need this: generate_video renders native speech when the words are in the prompt. Use it for voiceover over b-roll or a standalone audio file. Models: elevenlabs-tts. Spends 1 credit per 100 characters, rounded up. Returns a job id, poll get_run_status for the mp3 URL. The mp3 URL can be passed as an audio_ref to generate_video.\n\nRETRY SAFETY: set request_id to a fresh UUID for a new generation. Reuse the exact same request_id and inputs only to recover a lost response; that returns the original job without another charge. A deliberately new generation needs a new request_id. Keep the returned job_id and poll get_run_status. Never invent a refund.",
"input_schema": {
"type": "object",
"properties": {
"text": {
"type": "string",
"minLength": 1,
"maxLength": 4000,
"description": "The words to speak. Emotion tags like [excited] or [whispers] are honoured. Priced per character; see list_models."
},
"model": {
"type": "string",
"description": "A live audio model id from list_models, or \"auto\". Omit for the default (elevenlabs-tts)."
},
"voice": {
"type": "string",
"minLength": 1,
"default": "sarah",
"description": "A voice name: jessica (young female), sarah (female), liam (young male), chris (male), lily (elder female), bill (elder male), matilda (warm), or a raw ElevenLabs voice id."
},
"tone": {
"type": "string",
"enum": [
"energetic",
"calm",
"confident",
"dramatic"
],
"description": "energetic | calm | confident | dramatic."
},
"request_id": {
"type": "string",
"pattern": "^[A-Za-z0-9._:-]{1,128}$",
"description": "Unique request identity (prefer a UUID). Reuse with identical inputs to recover the same job after a lost response; choose a new identity only for an intentionally new generation."
}
},
"required": [
"text"
],
"additionalProperties": false
}
},
{
"name": "quote",
"title": "Quote",
"read_only": true,
"spends_credits": false,
"description": "Price a generate_image / generate_video / generate_audio call WITHOUT running it. Pass the same `input` you would pass to the tool. Returns credits (1 credit = $0.01), the model that would run, and the breakdown. Costs nothing. Use it before spending when the user asked about cost, when choosing between models, or before a clip longer than a few seconds.",
"input_schema": {
"type": "object",
"properties": {
"kind": {
"type": "string",
"enum": [
"image",
"video",
"audio"
]
},
"input": {
"type": "object",
"description": "The exact arguments you would pass to generate_<kind>."
}
},
"required": [
"kind",
"input"
],
"additionalProperties": false
}
},
{
"name": "list_characters",
"title": "List Characters",
"read_only": true,
"spends_credits": false,
"description": "List the authenticated user's saved, reusable characters. Each has a character_id (char_…) and a character_sheet_url. Pass either one as make_ugc's `character`, or pass the sheet/portrait URL in `refs` of the advanced generate_video / generate_image tools. Plus a portrait/thumbnail URL for display.",
"input_schema": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"description": "Max characters to return (default 50)."
}
},
"additionalProperties": false
}
},
{
"name": "get_run_status",
"title": "Get Run Status",
"read_only": true,
"spends_credits": false,
"description": "Check a generation you already submitted, and get its output URL (video, image or audio) when it is done. Pass the id ANY agent-media tool returned (run id, skill run id, or job id), this resolves all of them. Set wait:true to block until the job reaches a terminal state (up to ~45 seconds per call; if it is still running, just call again: seedance-2.0 needs about 3 minutes for a 5 s clip, seedance-2.5 12 to 25 minutes, so keep calling until it is done). ALWAYS call this after submitting: without it you cannot tell whether the video succeeded, and cannot give the user a link.",
"input_schema": {
"type": "object",
"properties": {
"run_id": {
"type": "string",
"description": "The run_id / skill_run_id / job_id returned when you submitted."
},
"wait": {
"type": "boolean",
"description": "Block until the run finishes or ~45 seconds elapse (default false). A video needs several such calls; just call again."
}
},
"required": [
"run_id"
],
"additionalProperties": false
}
},
{
"name": "upload_image",
"title": "Upload Image",
"read_only": false,
"spends_credits": false,
"description": "When the user wants to provide a product photo, portrait, screenshot, or image reference, check tools/list. If open_upload_panel is available, offer it first: call open_upload_panel with {}, show its inline panel or returned browser link, and wait for the user to finish. Then call get_uploads with the returned session_id and use the exact ready image_url in refs, first_frame, last_frame, or the matching skill image field. Do not start a reference-dependent generation until the required images are ready. The panel accepts still PNG, JPEG, and WebP, up to 10 images and 25 MB each. Images expire 24 hours after the panel is created; show the returned expiry, request a new upload if expired, and never make a permanent copy. Uploading uses no generation credits. Do not ask the user for base64, shell commands, or a public hosting service; do not continuously poll while waiting for them. Only call these tool names when discovered. If they are missing from the connected tool catalog, call upload_image with {} to open the same panel; use the returned panel: upload_key with upload_image to retrieve images after the user finishes. If that reports the panel is unavailable, use upload_image only for an already accessible file or URL. Do not build an upload page or request a local folder as a substitute for the existing panel. Never invent access to a chat attachment: if you cannot read it, explain that and offer the panel when available. Browser fallback works without inline UI support; do not promise an inline panel in every client.\nInspect the native image previews returned with retrieved uploads before describing them or writing image-specific prompts. Never infer what the image shows from an email domain, account metadata, or filename. Use the original URLs for generation, not preview bytes. If the session ID was lost, call get_uploads with {} to list recent sessions, or upload_image with {\"upload_key\":\"panel:recent\"} for cached catalogs; retrieve the matching session before asking for re-upload. Account-wide recent uploads may belong to other conversations, so clarify ambiguous selection. Uploading stores an image; it does not attach it to a generation automatically. If the user already requested a generation with these images, continue that request using the returned URLs; do not stop at \"upload complete\" or ask again whether to use them. If make_ugc fits the requested outcome, pass a person photo as image or a product photo as product_image, then call quote_ugc before spending. Otherwise compose the direct generators: for generate_image, put the relevant image_url values in refs; for generate_video, use refs for product/person/appearance references, or first_frame for animating a still (last_frame only for an explicitly requested ending frame), and never combine refs with frame fields. Preserve the user's intended image roles and model limits; ask only if the role or selection is unclear. Include the URL in the tool arguments, not only in the prompt. Do not substitute a newly generated image for the uploaded reference. If the request was upload-only, report readiness and wait for a generation request; uploading alone does not authorize spending credits. After submitting, poll get_run_status and return the result.\n\nFor an image already accessible to you: Store an image and get back a stable https URL you can pass to any agent-media tool. Costs NO credits. THREE ways in, in this order:\n1. FILE ON DISK (when the file is already accessible to your shell): call upload_image with `file_bytes` set to the exact byte size of the file (`wc -c < photo.png`) and `file_name`. You get back a `put_url`; run the printed curl to stream the file straight to storage, then call upload_image again with the `upload_key` you were given to get the URL. The bytes never pass through this conversation, so there is NO reason to resize, crop or re-encode the user’s photo first. Do not: a downscaled product photo is what the video model will show. Up to 25 MB.\n2. A URL you already have: pass `image_url` to re-host it.\n3. Raw bytes with no shell available: pass `image_base64` (PNG or JPEG, 10 MB max after decoding). Only when 1 and 2 are impossible, and even then upload the original, never a shrunken copy.\nThen pass the returned URL everywhere. Do NOT paste base64 into other tool arguments or into the conversation: the client displays tool arguments to the user, so a base64 image becomes a wall of unreadable text, and every retry re-sends it.",
"input_schema": {
"type": "object",
"properties": {
"file_bytes": {
"type": "integer",
"description": "Step 1 of the file path: the exact size of the file in bytes (`wc -c < photo.png`). Returns a put_url and an upload_key. Full resolution, up to 25 MB."
},
"file_name": {
"type": "string",
"description": "Optional with file_bytes: the file name, so the content type is right (.png or .jpg)."
},
"upload_key": {
"type": "string",
"description": "Reuse the exact upload_key returned earlier: a panel: key retrieves all ready temporary images; a file upload key confirms the completed PUT and returns its image_url."
},
"image_base64": {
"type": "string",
"description": "The image bytes, base64-encoded. A `data:image/png;base64,...` prefix is accepted and stripped. Last resort: use file_bytes when you can run a shell."
},
"image_url": {
"type": "string",
"description": "An https URL to fetch and re-host instead."
}
},
"additionalProperties": false
}
},
{
"name": "list_models",
"title": "List Models",
"read_only": true,
"spends_credits": false,
"description": "List the generation models agent-media can use: for each, its MODES (video: text, image-to-video via first_frame, reference via refs / video_refs / audio_refs) with the exact inputs, limits, aspects, qualities and credits per second of every mode, a \"pick when\" line, prompting tips, expected latency, how to select it, plus `recent`: the last 30 days of real runs per model (fail rate, auto-judge score, user ratings, median render time). Read this BEFORE choosing a model or a mode for generate_video / generate_image / generate_audio: the default seedance-2.0 is right for most jobs. Pass the id as `model`, or `model:\"auto\"` and the printed policy picks from the stats. Costs NO credits. Includes the same authenticated balance check as get_account; compare it with quote before generation. Set include_candidates:true to also see planned models that cannot be selected yet.",
"input_schema": {
"type": "object",
"properties": {
"include_candidates": {
"type": "boolean",
"description": "Also return planned models (no price, not selectable). Default false."
}
},
"additionalProperties": false
}
},
{
"name": "get_account",
"title": "Check Account Readiness",
"read_only": true,
"spends_credits": false,
"description": "Check this authenticated connection, available generation credits, and whether generation/upload services are configured. Free and read-only: does not create an upload session, generate media, refill credits or change billing. Call before the first generation; then use quote_ugc for make_ugc or quote for a direct generator and compare the cost with the balance. A positive balance is not a guarantee of sufficient funds for a specific request or provider availability.",
"input_schema": {
"type": "object",
"properties": {},
"additionalProperties": false
}
},
{
"name": "rate_run",
"title": "Rate Run",
"read_only": false,
"spends_credits": false,
"description": "Rate a finished generate_video / generate_image / generate_audio run 1 to 5, with an optional note (what was wrong or right). Costs nothing. Do this when the user reacts to an output, \"perfect\", \"her face changed\", \"too slow\", or when you can see a defect yourself. Ratings feed the per-model stats in list_models and the model:\"auto\" choice, so an honest 2 helps more than a polite 4.",
"input_schema": {
"type": "object",
"properties": {
"run_id": {
"type": "string",
"description": "The job id the generate tool returned."
},
"score": {
"type": "integer",
"minimum": 1,
"maximum": 5,
"description": "1 = unusable, 3 = usable with edits, 5 = shipped as-is."
},
"note": {
"type": "string",
"maxLength": 1000,
"description": "One line on why (optional)."
}
},
"required": [
"run_id",
"score"
],
"additionalProperties": false
}
},
{
"name": "open_upload_panel",
"title": "Upload images",
"read_only": false,
"spends_credits": false,
"description": "Optional: available only when temporary uploads are enabled; check tools/list before calling. Open a drag-and-drop image upload panel for the user. Use when the user wants to supply photos, portraits, products, or image references, especially in Claude or ChatGPT. PNG/JPEG/WebP, up to 25 MB each and 10 images, available for up to 24 hours. No generation credits. Returns a browser link for clients without inline panels. Never ask the user to paste base64. After the user uploads, call get_uploads with the returned session_id; use the exact image_url in refs, first_frame, or a skill image field. Do not generate before images are ready.",
"input_schema": {
"type": "object",
"properties": {},
"additionalProperties": false
}
},
{
"name": "get_uploads",
"title": "Get uploaded images",
"read_only": true,
"spends_credits": false,
"description": "Optional: available only when temporary uploads are enabled; check tools/list before calling. Retrieve uploaded images as native image previews plus original generation URLs and expiry times. Inspect the previews before describing the image or writing a prompt. Omit session_id to find recent unexpired sessions on this account if the session ID was lost; choose the session matching the user request, never silently mix unrelated uploads. Call after the user finishes uploading, not in a tight polling loop. Sessions and images expire 24 hours after the session opens; request a fresh upload if expired. Reuse these URLs for generation without downloading, re-encoding, or making a permanent copy.",
"input_schema": {
"type": "object",
"properties": {
"session_id": {
"type": "string",
"format": "uuid"
}
},
"additionalProperties": false
}
}
],
"models": {
"defaults": {
"image": "gpt-image-2.5",
"video": "seedance-2.0",
"audio": "elevenlabs-tts"
},
"auto_policy": "model:\"auto\" starts from the kind's default (image: gpt-image-2.5, video: seedance-2.0, audio: elevenlabs-tts); switches only when the default failed >25% of >=10 runs and another live model is healthy, or when a live model within 1.5x the default's price beats its auto score by >=0.1 over >=10 judged runs. Scores come from an auto-judge that grades every loose-surface job (3 frames or the image against the realism rubric, prompt adherence, identity match) plus rate_run.",
"live": [
{
"recent": null,
"id": "seedance-2.0",
"kind": "video",
"tier": "standard",
"status": "live",
"provider": "evolink",
"modes": [
"text-to-video",
"image-to-video",
"reference-to-video"
],
"features": [
"native-audio",
"lip-sync",
"first-frame",
"first-and-last-frame",
"image-references",
"video-references",
"audio-references"
],
"limits": {},
"video": {
"modes": [
{
"mode": "text",
"how": "prompt only",
"inputs": {
"prompt": "required"
},
"seconds": {
"min": 4,
"max": 15
},
"aspects": [
"9:16",
"16:9",
"1:1",
"4:3",
"3:4",
"21:9",
"adaptive"
],
"aspect_default": "9:16",
"qualities": [
"480p",
"720p",
"1080p"
],
"credits_per_second": {
"480p": 30,
"720p": 60,
"1080p": 150
},
"seed": false,
"prompt_syntax": null,
"notes": [
"No seed. Every render is new; keep a series consistent with references, not seeds."
],
"verified": {
"date": "2026-09-06",
"runId": "task-unified-1788681109-ghg38bm9",
"note": "4s, 16:9, 480p, native audio; rendered in 231 s"
}
},
{
"mode": "image",
"how": "pass first_frame (and optionally last_frame)",
"inputs": {
"first_frame": "required (https image)",
"last_frame": "optional (https image)"
},
"seconds": {
"min": 4,
"max": 15
},
"aspects": [
"9:16",
"16:9",
"1:1",
"4:3",
"3:4",
"21:9",
"adaptive"
],
"aspect_default": "adaptive",
"qualities": [
"480p",
"720p",
"1080p"
],
"credits_per_second": {
"480p": 30,
"720p": 60,
"1080p": 150
},
"seed": false,
"prompt_syntax": null,
"notes": [
"first_frame becomes frame one of the clip; last_frame (optional) becomes the final frame and the model animates between them.",
"Frames only: refs, video_refs and audio_refs are not accepted in this mode. To keep an identity AND set the frame, put the frame image in refs and describe it as @image1.",
"aspect \"adaptive\" (default) follows the first frame. Frame images: jpeg/png/webp, ratio between 0.4 and 2.5, 300 to 6000 px, up to 30 MB."
],
"verified": {
"date": "2026-09-06",
"runId": "task-unified-1788681109-qybq2r1j",
"note": "first_frame only (4s, 480p, adaptive) and first_frame + last_frame (task-unified-1788681109-w09254uu); both rendered in about 3 to 5 min"
}
},
{
"mode": "reference",
"how": "pass refs, video_refs and/or audio_refs",
"inputs": {
"refs": "up to 9 https images",
"video_refs": "up to 3 https clips, 15 s in total; their seconds are billed like output seconds",
"audio_refs": "up to 3 https audio files, 15 s in total; needs an image or video reference beside it"
},
"seconds": {
"min": 4,
"max": 15
},
"aspects": [
"9:16",
"16:9",
"1:1",
"4:3",
"3:4",
"21:9",
"adaptive"
],
"aspect_default": "9:16",
"qualities": [
"480p",
"720p",
"1080p"
],
"credits_per_second": {
"480p": 30,
"720p": 60,
"1080p": 150
},
"seed": false,
"prompt_syntax": "@image1 @video1 @audio1 (numbered per list, from 1)",
"notes": [
"Address references in the prompt: \"@image1 holds @image2 and says ...\". Numbering is per list: refs are @image1.., video_refs are @video1.., audio_refs are @audio1...",
"Reference clips: 2 to 15 s each, 15 s in total, mp4/mov 480p to 1080p, 24 to 60 fps, up to 50 MB. Their seconds are billed like output seconds.",
"Audio references: wav/mp3, 2 to 15 s each, 15 s in total, up to 15 MB. Audio alone is not accepted: add an image or video reference.",
"aspect \"adaptive\" follows the first video reference, else the first image, else the prompt."
],
"verified": {
"date": "2026-09-06",
"runId": "task-unified-1788681109-a6w7aq0y",
"note": "image ref (4s, 480p) and image ref + 8 s reference clip (task-unified-1788681110-hdbufncn); earlier 5s 720p portrait run b0011e92 via Claude Code"
}
}
],
"credits_per_second": {
"480p": 30,
"720p": 60,
"1080p": 150
},
"default_quality": "720p",
"timeout_minutes": 30
},
"credits": {
"unit": "second",
"perUnit": 60
},
"price_default": "60 credits per second at 720p",
"quality": "good",
"speed": "medium",
"best_for": [
"talking-head UGC",
"product in hands",
"crazy look",
"bulk daily posts",
"animating a still (first frame) into a clip"
],
"avoid_for": [
"clips over 15s",
"hero shots where 2.5 detail is worth the longer wait",
"anything that needs a seed"
],
"usage": {
"pick_when": "you need a real-looking person saying real words, or a still brought to life, at a normal budget",
"prompt_tips": [
"Write the shot as a director: who (age, look), where (setting, light), what happens, phone framing, and the exact spoken words in quotes. About 2.3 words per second.",
"Keep a person consistent across clips with refs (a portrait or a character sheet), addressed as @image1; the model has no seed.",
"To animate a specific still, pass it as first_frame; add last_frame to control where the motion ends."
],
"latency": "about 3 minutes for a 5 s clip at 720p"
},
"docs_url": "https://github.com/gitroomhq/agent-media/blob/main/reference/models/seedance-2.0.md",
"verified": [
{
"mode": "text",
"date": "2026-09-06",
"runId": "task-unified-1788681109-ghg38bm9",
"note": "4s, 16:9, 480p, native audio; rendered in 231 s"
},
{
"mode": "image",
"date": "2026-09-06",
"runId": "task-unified-1788681109-qybq2r1j",
"note": "first_frame only (4s, 480p, adaptive) and first_frame + last_frame (task-unified-1788681109-w09254uu); both rendered in about 3 to 5 min"
},
{
"mode": "reference",
"date": "2026-09-06",
"runId": "task-unified-1788681109-a6w7aq0y",
"note": "image ref (4s, 480p) and image ref + 8 s reference clip (task-unified-1788681110-hdbufncn); earlier 5s 720p portrait run b0011e92 via Claude Code"
}
],
"select_with": {
"field": "model",
"value": "seedance-2.0",
"on": [
"generate_video (MCP)",
"POST /v2/generate/video",
"as `engine` on: agent-media selfie --engine",
"agent-media crazy-look --engine",
"POST /v2/selfie",
"POST /v2/crazy-look"
],
"not_on": [
"make_ugc (always seedance-2.0)"
]
}
},
{
"recent": null,
"id": "seedance-2.5",
"kind": "video",
"tier": "premium",
"status": "live",
"provider": "evolink",
"modes": [
"text-to-video",
"image-to-video",
"reference-to-video"
],
"features": [
"native-audio",
"lip-sync",
"first-frame",
"first-and-last-frame",
"image-references",
"video-references",
"audio-references"
],
"limits": {},
"video": {
"modes": [
{
"mode": "text",
"how": "prompt only",
"inputs": {
"prompt": "required"
},
"seconds": {
"min": 4,
"max": 30
},
"aspects": [
"9:16",
"16:9",
"1:1",
"4:3",
"3:4",
"21:9",
"adaptive"
],
"aspect_default": "9:16",
"qualities": [
"480p",
"720p",
"1080p"
],
"credits_per_second": {
"480p": 28,
"720p": 60,
"1080p": 150
},
"seed": false,
"prompt_syntax": null,
"notes": [
"No seed."
],
"verified": {
"date": "2026-09-05",
"runId": "431f82ba-9e9e-4644-beb3-b1f67c0de91e",
"note": "generate_video, text only, 4s, 720p, 396 credits; the provider took about 25 min"
}
},
{
"mode": "image",
"how": "pass first_frame (and optionally last_frame)",
"inputs": {
"first_frame": "required (https image)",
"last_frame": "optional (https image)"
},
"seconds": {
"min": 4,
"max": 30
},
"aspects": [
"adaptive"
],
"aspect_default": "adaptive",
"qualities": [
"480p",
"720p",
"1080p"
],
"credits_per_second": {
"480p": 28,
"720p": 60,
"1080p": 150
},
"seed": false,
"prompt_syntax": null,
"notes": [
"first_frame becomes frame one; last_frame (optional) becomes the final frame.",
"aspect must be \"adaptive\" on this model in image mode: the clip takes the frame's ratio. Any other aspect is refused.",