GhostfeedGhostfeed MCPv8.2.0
MCP docs

UGC Reactions

Create, clone, and edit UGC images; generate videos from written or analyzed action, or directly guided source media. Source preparation and reusable assets are composable tools; legacy reaction calls remain available during migration.

generate_image

WRITE

REST: POST /api/v2/images/generate

Create one image from a written instruction with optional Avatar, Product image, or multiple image references. Text-only creation is supported. Use clone_image for recreating a composition with an Avatar, or edit_image for a specific change. Uses shared dashboard models and durable jobs; use a stable idempotencyKey for retries. To SHOW these results in an MCP Apps host, ALWAYS call render_image_results; never hand-build the presentation in chat (no markdown galleries, embedded thumbnails, numbered image lists, or artifacts), even after a widget error. Outside an Apps host, describe items in text and share the dashboard link.

Input schema
{
  "type": "object",
  "properties": {
    "model": {
      "default": "gemini_flash",
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "quality": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ]
    },
    "resolution": {
      "default": "standard",
      "type": "string",
      "enum": [
        "standard",
        "1080p"
      ]
    },
    "aspectRatio": {
      "type": "string",
      "enum": [
        "9:16",
        "16:9",
        "1:1"
      ]
    },
    "systemPrompt": {
      "description": "Exact replacement for the disclosed default. Omit to use the default; null removes it. No hidden default is appended.",
      "anyOf": [
        {
          "type": "string",
          "maxLength": 30000
        },
        {
          "type": "null"
        }
      ]
    },
    "maxCredits": {
      "description": "Optional hard ceiling for this single image generation.",
      "type": "number",
      "minimum": 0
    },
    "idempotencyKey": {
      "description": "A stable key to reuse if you retry this exact request; a repeat with the same key is NOT charged again.",
      "type": "string",
      "maxLength": 200
    },
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "instruction": {
      "type": "string",
      "minLength": 1,
      "maxLength": 30000
    },
    "avatarId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "productImageId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "referenceImages": {
      "default": [],
      "maxItems": 10,
      "type": "array",
      "items": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "frame"
              },
              "frameId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "kind",
              "frameId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "upload"
              },
              "mediaId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "kind",
              "mediaId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "product"
              },
              "productImageId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "kind",
              "productImageId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "avatar"
              },
              "avatarId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "kind",
              "avatarId"
            ],
            "additionalProperties": false
          }
        ]
      }
    }
  },
  "required": [
    "workspace",
    "instruction"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "generation": {
      "id": "gen_image_aa11bb22",
      "kind": "reaction_frame",
      "state": "queued",
      "phase": "pending",
      "input": {
        "operation": "generate_image",
        "model": "gemini_flash",
        "instruction": "Create a clean photograph."
      },
      "outputs": [],
      "creditsSpent": 1,
      "createdAt": "2026-09-15T12:00:00.000Z",
      "updatedAt": "2026-09-15T12:00:00.000Z"
    },
    "prompt": {
      "operation": "generate_image",
      "source": "user",
      "inspectWith": "get_generation_prompt"
    },
    "references": [],
    "nextSteps": "Poll get_generation. On success, generation.outputs[0].id is the image ID for editing or video generation."
  }
}

clone_image

WRITE

REST: POST /api/v2/images/clone

Recreate a Template or image composition with one Avatar and an optional Product image. Automatically uses the Avatar clone default or the Product-aware default, which inserts the supplied Product even if the source has none. Defaults are inspectable and replaceable via systemPrompt. Use get_source_frame to choose a precise source-video frame. Creates one image; it does not generate a video. To SHOW these results in an MCP Apps host, ALWAYS call render_image_results; never hand-build the presentation in chat (no markdown galleries, embedded thumbnails, numbered image lists, or artifacts), even after a widget error. Outside an Apps host, describe items in text and share the dashboard link.

Input schema
{
  "type": "object",
  "properties": {
    "model": {
      "default": "gemini_flash",
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "quality": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ]
    },
    "resolution": {
      "default": "standard",
      "type": "string",
      "enum": [
        "standard",
        "1080p"
      ]
    },
    "aspectRatio": {
      "type": "string",
      "enum": [
        "9:16",
        "16:9",
        "1:1"
      ]
    },
    "systemPrompt": {
      "description": "Exact replacement for the disclosed default. Omit to use the default; null removes it. No hidden default is appended.",
      "anyOf": [
        {
          "type": "string",
          "maxLength": 30000
        },
        {
          "type": "null"
        }
      ]
    },
    "maxCredits": {
      "description": "Optional hard ceiling for this single image generation.",
      "type": "number",
      "minimum": 0
    },
    "idempotencyKey": {
      "description": "A stable key to reuse if you retry this exact request; a repeat with the same key is NOT charged again.",
      "type": "string",
      "maxLength": 200
    },
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "composition": {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "template"
            },
            "templateId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "templateId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "frame"
            },
            "frameId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "frameId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "upload"
            },
            "mediaId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "mediaId"
          ],
          "additionalProperties": false
        }
      ]
    },
    "avatarId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "productImageId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "instruction": {
      "type": "string",
      "minLength": 1,
      "maxLength": 30000
    },
    "referenceImages": {
      "default": [],
      "maxItems": 10,
      "type": "array",
      "items": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "frame"
              },
              "frameId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "kind",
              "frameId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "upload"
              },
              "mediaId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "kind",
              "mediaId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "product"
              },
              "productImageId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "kind",
              "productImageId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "avatar"
              },
              "avatarId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "kind",
              "avatarId"
            ],
            "additionalProperties": false
          }
        ]
      }
    }
  },
  "required": [
    "workspace",
    "composition",
    "avatarId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "generation": {
      "id": "gen_image_aa11bb22",
      "kind": "reaction_frame",
      "state": "queued",
      "phase": "pending",
      "input": {
        "operation": "clone_image",
        "model": "gemini_flash",
        "instruction": "Create a clean photograph."
      },
      "outputs": [],
      "creditsSpent": 1,
      "createdAt": "2026-09-15T12:00:00.000Z",
      "updatedAt": "2026-09-15T12:00:00.000Z"
    },
    "prompt": {
      "operation": "clone_image",
      "source": "default",
      "defaultId": "avatar-clone",
      "inspectWith": "get_generation_prompt"
    },
    "references": [
      {
        "referenceId": "template:template_123",
        "role": "template",
        "address": {
          "kind": "indexed-image",
          "index": 1
        }
      },
      {
        "referenceId": "avatar:avatar_456",
        "role": "avatar",
        "address": {
          "kind": "indexed-image",
          "index": 2
        }
      }
    ],
    "nextSteps": "Poll get_generation. On success, generation.outputs[0].id is the image ID for editing or video generation."
  }
}

edit_image

WRITE

REST: POST /api/v2/images/edit

Create a new image by applying a requested change to one existing image or completed image upload. The default preserves unrequested content; replace it with systemPrompt when needed. The original image is preserved. Returns a generation ID to poll with get_generation. To SHOW these results in an MCP Apps host, ALWAYS call render_image_results; never hand-build the presentation in chat (no markdown galleries, embedded thumbnails, numbered image lists, or artifacts), even after a widget error. Outside an Apps host, describe items in text and share the dashboard link.

Input schema
{
  "type": "object",
  "properties": {
    "model": {
      "default": "gemini_flash",
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "quality": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ]
    },
    "resolution": {
      "default": "standard",
      "type": "string",
      "enum": [
        "standard",
        "1080p"
      ]
    },
    "aspectRatio": {
      "type": "string",
      "enum": [
        "9:16",
        "16:9",
        "1:1"
      ]
    },
    "systemPrompt": {
      "description": "Exact replacement for the disclosed default. Omit to use the default; null removes it. No hidden default is appended.",
      "anyOf": [
        {
          "type": "string",
          "maxLength": 30000
        },
        {
          "type": "null"
        }
      ]
    },
    "maxCredits": {
      "description": "Optional hard ceiling for this single image generation.",
      "type": "number",
      "minimum": 0
    },
    "idempotencyKey": {
      "description": "A stable key to reuse if you retry this exact request; a repeat with the same key is NOT charged again.",
      "type": "string",
      "maxLength": 200
    },
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "image": {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "frame"
            },
            "frameId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "frameId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "upload"
            },
            "mediaId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "mediaId"
          ],
          "additionalProperties": false
        }
      ]
    },
    "instruction": {
      "type": "string",
      "minLength": 1,
      "maxLength": 30000
    }
  },
  "required": [
    "workspace",
    "image",
    "instruction"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "generation": {
      "id": "gen_image_aa11bb22",
      "kind": "reaction_frame",
      "state": "queued",
      "phase": "pending",
      "input": {
        "operation": "edit_image",
        "model": "gemini_flash",
        "instruction": "Create a clean photograph."
      },
      "outputs": [],
      "creditsSpent": 1,
      "createdAt": "2026-09-15T12:00:00.000Z",
      "updatedAt": "2026-09-15T12:00:00.000Z"
    },
    "prompt": {
      "operation": "edit_image",
      "source": "default",
      "defaultId": "image-edit",
      "inspectWith": "get_generation_prompt"
    },
    "references": [
      {
        "referenceId": "image:frame_123",
        "role": "frame",
        "address": {
          "kind": "indexed-image",
          "index": 1
        }
      }
    ],
    "nextSteps": "Poll get_generation. On success, generation.outputs[0].id is the image ID for editing or video generation."
  }
}

request_media_upload

WRITE

REST: POST /api/v2/media/uploads

Request an upload URL for original image, video, or audio bytes. PUT the bytes to the URL, then complete_media_upload. No generation is started.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "uploadId": {
      "description": "Optional stable request ID. Repeat it with identical metadata when retrying.",
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]{8,64}$"
    },
    "contentType": {
      "type": "string",
      "enum": [
        "image/jpeg",
        "image/png",
        "image/webp",
        "video/mp4",
        "video/webm",
        "video/quicktime",
        "audio/mpeg",
        "audio/mp4",
        "audio/wav",
        "audio/x-wav",
        "audio/ogg",
        "audio/webm",
        "audio/aac"
      ]
    },
    "byteLength": {
      "type": "integer",
      "minimum": 1,
      "maximum": 209715200
    },
    "filename": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255
    }
  },
  "required": [
    "workspace",
    "contentType",
    "byteLength",
    "filename"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "uploadId": "upload-example",
    "uploadUrl": "https://upload.example.com/signed",
    "completed": false,
    "contentType": "image/png",
    "expiresInSeconds": 900,
    "maxBytes": 10485760
  }
}

complete_media_upload

WRITE

REST: POST /api/v2/media/uploads/complete

Validate and save uploaded original media. Returns mediaId for generation references. Retrying the same upload is safe.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "uploadId": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]{8,64}$"
    }
  },
  "required": [
    "workspace",
    "uploadId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "media": {
      "mediaId": "upload-example",
      "uploadId": "upload-example",
      "mediaKind": "image",
      "url": "https://media.example.com/original.png"
    }
  }
}

get_source_frame

WRITE

REST: POST /api/v2/media/source-frame

Extract and save a frame at a timestamp from an accessible source template or uploaded video. Use it to inspect sections or choose the exact image to recreate.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "source": {
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "templateId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "templateId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "mediaId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "mediaId"
          ],
          "additionalProperties": false
        }
      ],
      "description": "Exactly one ready accessible templateId or completed uploaded video mediaId. Audio and image uploads cannot supply a video frame."
    },
    "timestampSeconds": {
      "type": "number",
      "minimum": 0,
      "maximum": 3600,
      "multipleOf": 0.001,
      "description": "Source timestamp in seconds, to millisecond precision; must be before the end."
    }
  },
  "required": [
    "workspace",
    "source",
    "timestampSeconds"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "frameId": "source-example",
    "imageUrl": "https://media.example.com/frame.png",
    "templateId": "template-example",
    "timestampSeconds": 1,
    "sourceKind": "template"
  }
}

list_reaction_templates

READ

REST: GET /api/v2/reaction-templates

Browse source templates when the request needs an existing composition or motion reference: platform stock plus workspace imports/uploads. Custom image and prompt-directed video creation do not require a template search. Analyzed clips carry firstFrameScene and videoUnderstanding; older clips may expose opensOn and motion summaries. Use clone_image to recreate a composition. For generate_video_from_prompt, read source understanding and write the prompt yourself. Use generate_video_from_reference for media-guided motion. analyze_video gets or creates source analysis when needed.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "description": "Target workspace: a slug, id, or exact name from list_workspaces. Omit to use this connection's default workspace. Must be inside the credential's grant and your current access; overrides the connection-level X-Workspace-Id header.",
      "type": "string"
    },
    "mine": {
      "type": "boolean"
    },
    "includeUnusable": {
      "description": "Include templates that cannot be generated from yet: ones still importing, ones that failed. Off by default, because generating from them is refused anyway.",
      "type": "boolean"
    },
    "page": {
      "description": "Page number (default 1).",
      "type": "integer",
      "minimum": 1,
      "maximum": 9007199254740991
    },
    "limit": {
      "description": "Per page (max 25; lower than other tools because these rows carry long descriptions). Each tool documents its own default.",
      "type": "integer",
      "minimum": 1,
      "maximum": 25
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "templates": [
      {
        "id": "user-1a2b3c4d-1737100000000",
        "name": "Excited point",
        "category": "Reactions",
        "durationSeconds": 4.2,
        "thumbnailUrl": "https://cdn.ghostfeed.ai/reactions/user-1a2b3c4d/thumbnail.jpg",
        "kind": "owned",
        "status": "completed",
        "mention": "@template:Excited point (user-1a2b3c4d-1737100000000)",
        "opensOn": "Medium shot of a woman at a desk, looking just off camera, hands raised mid-gesture.",
        "motion": "She points at the camera, leans in, and breaks into a grin."
      }
    ],
    "total": 1,
    "page": 1,
    "pages": 1,
    "nextSteps": "Use a template with clone_image, analyze_video, or either video generation intent when a source is needed. Custom generation does not require a source search."
  }
}

get_reaction_template

READ

REST: GET /api/v2/reaction-templates/:id

Read one source template by its templateId (or a generated video’s sourceReactionId). Returns source media, import metadata, full opening-composition and legacy motion analysis when available, plus the canonical saved videoUnderstanding result. New uploads and social imports finish understanding before becoming ready; saved inspiration imports reuse its analysis. New crops are exact assets with their own understanding. Completed v8 understanding includes a provider-authored generationPrompt for generation as well as factual source evidence. Reading does not start a new analysis. Use analyze_video understanding only when the saved result is missing or failed and the user wants a retry.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "description": "Target workspace: a slug, id, or exact name from list_workspaces. Omit to use this connection's default workspace. Must be inside the credential's grant and your current access; overrides the connection-level X-Workspace-Id header.",
      "type": "string"
    },
    "templateId": {
      "type": "string",
      "minLength": 1,
      "description": "The template id from list_reaction_templates or sourceReactionId from a video."
    }
  },
  "required": [
    "templateId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "template": {
      "templateId": "reaction-7ab2",
      "name": "Excited point source",
      "category": "reaction",
      "kind": "owned",
      "status": "completed",
      "opensOn": "Waist-up, phone held at arm’s length in a bright kitchen. She looks straight down the lens, both hands empty, warm window light from the left.",
      "source": {
        "videoUrl": "https://cdn.ghostfeed.ai/reactions/excited-point.mp4",
        "thumbnailUrl": "https://cdn.ghostfeed.ai/reactions/excited-point-first-frame.jpg",
        "durationSeconds": 7,
        "aspectRatio": "9:16",
        "importSource": "tiktok",
        "originalUrl": "https://www.tiktok.com/@creator/video/123"
      },
      "videoUnderstanding": {
        "analysisId": "source-understanding-example",
        "status": "complete",
        "schemaVersion": 1,
        "analysisVersion": "7",
        "source": {
          "videoUrl": "https://cdn.ghostfeed.ai/reactions/excited-point.mp4",
          "durationSeconds": 7
        },
        "sectionTiming": "approximate",
        "model": "gemini-3.8-flash",
        "promptHash": "sha256-of-reviewed-understanding-prompt",
        "creditsSpent": 0,
        "understanding": {
          "description": "A person points with a surprised expression, then smiles at the camera.",
          "demoType": "none",
          "visualFormat": "live_action",
          "contentStructure": "short_reaction_only",
          "editingComplexity": {
            "level": "light",
            "explanation": "A continuous shot with captions."
          },
          "sections": [
            {
              "startSeconds": 0,
              "endSeconds": 7,
              "description": "The person points, reacts with surprise, then smiles."
            }
          ],
          "transcript": []
        },
        "warnings": [],
        "generatedAt": "2026-09-16T12:00:00.000Z"
      },
      "motionAnalysis": {
        "status": "complete",
        "prompt": "Timed section\\n0-7s: She points, then smiles.\\n\\nWhole-video description\\nAn upbeat point and smile.",
        "timeline": "0-7s: She points, then smiles.",
        "model": "gemini-3.1-flash-lite",
        "generatedAt": "2026-07-20T02:00:00.000Z"
      }
    }
  }
}

list_reaction_frames

READ

REST: GET /api/v2/reaction-frames

List reusable image frames on the workspace board, newest first, including dashboard results. Filter by avatar or template when relevant. Each row carries its image, lineage, generation metadata, preferenceStatus, videoStage, and animationStatus. A completed frame remains reusable. Pass an image reference {kind: frame, frameId} to generate_video_from_prompt or generate_video_from_reference, or use edit_image to change it. Follow the user’s review preferences when choosing an existing take. To SHOW these results in an MCP Apps host, ALWAYS call render_image_results; never hand-build the presentation in chat (no markdown galleries, embedded thumbnails, numbered image lists, or artifacts), even after a widget error. Outside an Apps host, describe items in text and share the dashboard link.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "description": "Target workspace: a slug, id, or exact name from list_workspaces. Omit to use this connection's default workspace. Must be inside the credential's grant and your current access; overrides the connection-level X-Workspace-Id header.",
      "type": "string"
    },
    "avatar": {
      "type": "string",
      "minLength": 1
    },
    "templateId": {
      "type": "string",
      "minLength": 1
    },
    "page": {
      "description": "Page number (default 1).",
      "type": "integer",
      "minimum": 1,
      "maximum": 9007199254740991
    },
    "limit": {
      "description": "Per page (max 100). Each tool documents its own default.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "frames": [
      {
        "frameId": "4b706a83-c035-427d-9f68-1091101c6dec",
        "imageUrl": "https://cdn.ghostfeed.ai/frames/frame-1737100000000-1.png",
        "avatarId": "d7d06ea3-a574-4fe0-9a39-d189a0b68698",
        "avatarName": "Ashley Gram",
        "templateId": "user-1a2b3c4d-1737100000000",
        "videoId": "1cc27551-5ad9-42bd-9a9c-899f83dcfec6",
        "imageModel": "gemini_flash",
        "imageOutputResolution": "standard",
        "videoStage": "selecting-frame",
        "preferenceStatus": "neutral",
        "animationStatus": "never",
        "isAnimated": false,
        "createdAt": "2026-07-20T02:22:50.374Z",
        "mention": "@frame:Ashley Gram (4b706a83-c035-427d-9f68-1091101c6dec)",
        "dashboardUrl": "https://app.ghostfeed.ai/w/client-a/ugc-reactions?frame=4b706a83-c035-427d-9f68-1091101c6dec"
      }
    ],
    "total": 1,
    "page": 1,
    "pages": 1,
    "nextSteps": "Reuse {kind: \"frame\", frameId} as the image for generate_video_from_prompt or generate_video_from_reference, or use edit_image to modify it."
  }
}

list_reaction_videos

READ

REST: GET /api/v2/reaction-videos

List the reaction VIDEOS in this workspace, newest first, agent-made or not. Each has a videoId, name, stage, a playable videoUrl once stage is "complete", a dashboardUrl, and sourceReactionId when it came from a template. videoUrl is the canonical clip: the post-edit version once one exists, otherwise the raw render. generation is a compact model/mode/duration summary. Rows carry avatarId but not the avatar name; resolve names with list_avatars when you need them. When sourceReactionId is present, get_reaction_template reads source media and stored analysis. get_reaction_video reads one render record; when generationId is known, get_generation_prompt and get_generation_setup provide exact saved instructions and reusable settings. Managing and deleting videos stays in the dashboard. To SHOW these results in an MCP Apps host, ALWAYS call render_video_result; never hand-build the presentation in chat (no markdown galleries, embedded thumbnails, numbered image lists, or artifacts), even after a widget error. Outside an Apps host, describe items in text and share the dashboard link.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "description": "Target workspace: a slug, id, or exact name from list_workspaces. Omit to use this connection's default workspace. Must be inside the credential's grant and your current access; overrides the connection-level X-Workspace-Id header.",
      "type": "string"
    },
    "avatar": {
      "type": "string",
      "minLength": 1
    },
    "stage": {
      "type": "string",
      "minLength": 1
    },
    "page": {
      "description": "Page number (default 1).",
      "type": "integer",
      "minimum": 1,
      "maximum": 9007199254740991
    },
    "limit": {
      "description": "Per page (max 100). Each tool documents its own default.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "videos": [
      {
        "videoId": "b9b2a07c-2119-455f-aebf-e7d0b2f32182",
        "name": "Excited point - Ashley Gram",
        "stage": "complete",
        "videoUrl": "https://cdn.ghostfeed.ai/generated-videos/b9b2a07c/final.mp4",
        "sourceReactionId": "reaction-7ab2",
        "generation": {
          "firstFrame": {
            "mode": "template",
            "imageModel": "gemini_flash"
          },
          "video": {
            "mode": "grok",
            "durationSeconds": 7
          }
        },
        "avatarId": "d7d06ea3-a574-4fe0-9a39-d189a0b68698",
        "createdAt": "2026-07-20T02:09:51.871Z",
        "dashboardUrl": "https://app.ghostfeed.ai/w/client-a/ugc-reactions?video=b9b2a07c-2119-455f-aebf-e7d0b2f32182"
      }
    ],
    "total": 1,
    "page": 1,
    "pages": 1,
    "nextSteps": "Use videoUrl to inspect generated clips. Call get_reaction_template with sourceReactionId for the original source, or get_reaction_video for exact prompts and settings. Rows carry avatarId but not the avatar name; resolve names with list_avatars."
  }
}

get_reaction_video

READ

REST: GET /api/v2/reaction-videos/:id

Read one reaction video’s full render record after finding it with list_reaction_videos. Returns the canonical generated video URL, sourceReactionId, exact first-frame and video prompts, selected frame, models, duration, and post-edit URL. When sourceReactionId is present, get_reaction_template reads source media and stored analysis. When generationId is known, prefer get_generation_prompt and get_generation_setup for exact saved instructions and reusable settings. Use this only for videos you need to recreate or inspect in detail; the list stays compact enough to inventory up to 100 videos. To SHOW these results in an MCP Apps host, ALWAYS call render_video_result; never hand-build the presentation in chat (no markdown galleries, embedded thumbnails, numbered image lists, or artifacts), even after a widget error. Outside an Apps host, describe items in text and share the dashboard link.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "description": "Target workspace: a slug, id, or exact name from list_workspaces. Omit to use this connection's default workspace. Must be inside the credential's grant and your current access; overrides the connection-level X-Workspace-Id header.",
      "type": "string"
    },
    "videoId": {
      "type": "string",
      "minLength": 1,
      "description": "The videoId from list_reaction_videos whose complete render metadata to read."
    }
  },
  "required": [
    "videoId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "video": {
      "videoId": "b9b2a07c-2119-455f-aebf-e7d0b2f32182",
      "name": "Excited point - Ashley Gram",
      "stage": "complete",
      "videoUrl": "https://cdn.ghostfeed.ai/generated-videos/b9b2a07c/final.mp4",
      "sourceReactionId": "reaction-7ab2",
      "generation": {
        "firstFrame": {
          "mode": "template",
          "imageModel": "gemini_flash",
          "prompt": "Render Mila in the source opening pose.",
          "stylingPrompt": "Keep the white blouse and bright kitchen.",
          "referenceImageUrl": "https://cdn.ghostfeed.ai/references/mila.jpg",
          "sourceFrameId": "frame-1737099999999-1",
          "aspectRatio": "9:16",
          "selectedFrameUrl": "https://cdn.ghostfeed.ai/frames/frame-1737100000000-1.png"
        },
        "video": {
          "mode": "grok",
          "prompt": "She points excitedly at the camera, then smiles.",
          "durationSeconds": 7,
          "finalVideoUrl": "https://cdn.ghostfeed.ai/generated-videos/b9b2a07c/final.mp4"
        }
      },
      "avatarId": "d7d06ea3-a574-4fe0-9a39-d189a0b68698",
      "avatarName": "Ashley Gram",
      "createdAt": "2026-07-20T02:09:51.871Z",
      "dashboardUrl": "https://app.ghostfeed.ai/w/client-a/ugc-reactions?video=b9b2a07c-2119-455f-aebf-e7d0b2f32182"
    },
    "nextSteps": "When sourceReactionId is present, get_reaction_template reads the original source. When generationId is known, prefer get_generation_prompt and get_generation_setup for exact saved instructions and reusable settings. Follow the user’s review preferences."
  }
}

generate_video_from_prompt

WRITE

REST: POST /api/v2/videos/generate-from-prompt

Create one first-frame-guided video from the prompt you write. When recreating a source, read its saved videoUnderstanding and write the requested performance yourself; this tool never inserts source text automatically. Use this for H3, H3 Max, and other prompt-directed models. Use generate_video_from_reference for every audio-guided or video-guided request. Ghostfeed does not add hidden guided text. Use a stable idempotencyKey for retries. To SHOW these results in an MCP Apps host, ALWAYS call render_video_result; never hand-build the presentation in chat (no markdown galleries, embedded thumbnails, numbered image lists, or artifacts), even after a widget error. Outside an Apps host, describe items in text and share the dashboard link.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "image": {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "frame"
            },
            "frameId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "frameId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "upload"
            },
            "mediaId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "mediaId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "product"
            },
            "productImageId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "productImageId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "avatar"
            },
            "avatarId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "avatarId"
          ],
          "additionalProperties": false
        }
      ],
      "description": "The anchor Image: an existing frame, completed image upload, Avatar, or Product image."
    },
    "outputResolution": {
      "type": "string",
      "enum": [
        "480p",
        "720p",
        "768p",
        "1080p",
        "2k"
      ]
    },
    "enableAudio": {
      "type": "boolean"
    },
    "cameraFixed": {
      "type": "boolean"
    },
    "aspectRatio": {
      "type": "string",
      "enum": [
        "9:16",
        "16:9",
        "1:1"
      ]
    },
    "systemPrompt": {
      "description": "Exact system guidance override. Wan 3 Video Guided uses the inspectable wan3-video-guided default when omitted; pass null to remove it. Other modes have no automatic system guidance. The action remains separate.",
      "anyOf": [
        {
          "type": "string",
          "maxLength": 30000
        },
        {
          "type": "null"
        }
      ]
    },
    "maxCredits": {
      "description": "Hard ceiling for one output, including reference and preparation charges.",
      "type": "number",
      "minimum": 0
    },
    "idempotencyKey": {
      "description": "A stable key to reuse if you retry this exact request; a repeat with the same key is NOT charged again.",
      "type": "string",
      "maxLength": 200
    },
    "durationSeconds": {
      "anyOf": [
        {
          "type": "string",
          "const": "auto"
        },
        {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 9007199254740991
        }
      ]
    },
    "mode": {
      "description": "A prompt-directed mode from list_reaction_video_modes. H3 and H3 Max belong here. Defaults to minimax_h3_max.",
      "type": "string",
      "enum": [
        "one_to_one_standard",
        "one_to_one_clone_premium",
        "grok",
        "pixverse",
        "pixverse_1080p",
        "kling_2_5_turbo",
        "seedance_2_0",
        "seedance_2_0_fast",
        "seedance_2_0_mini",
        "minimax_h3",
        "minimax_h3_max",
        "wan_3",
        "seedance_2_5"
      ]
    },
    "modeInput": {
      "description": "Wan 3 prompt generation only: first-frame guidance and Prime selection. Use generate_video_from_reference for audio-guided or video-guided generation.",
      "type": "object",
      "properties": {
        "guidance": {
          "type": "string",
          "enum": [
            "first_frame",
            "audio_guided",
            "video_guided"
          ]
        },
        "prime": {
          "type": "boolean"
        }
      },
      "required": [
        "guidance",
        "prime"
      ],
      "additionalProperties": false
    },
    "prompt": {
      "type": "string",
      "minLength": 1,
      "maxLength": 30000,
      "description": "The complete action prompt written by the caller. Read videoUnderstanding to understand a source, then write the requested action yourself. No source prompt is inserted automatically."
    },
    "references": {
      "description": "Additional authorized Image, Video, or Audio references. Only capabilities supported by the selected mode are accepted; unsupported inputs are never silently dropped.",
      "maxItems": 14,
      "type": "array",
      "items": {
        "anyOf": [
          {
            "oneOf": [
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "const": "frame"
                  },
                  "frameId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  }
                },
                "required": [
                  "kind",
                  "frameId"
                ],
                "additionalProperties": false
              },
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "const": "upload"
                  },
                  "mediaId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  }
                },
                "required": [
                  "kind",
                  "mediaId"
                ],
                "additionalProperties": false
              },
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "const": "product"
                  },
                  "productImageId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  }
                },
                "required": [
                  "kind",
                  "productImageId"
                ],
                "additionalProperties": false
              },
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "const": "avatar"
                  },
                  "avatarId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  }
                },
                "required": [
                  "kind",
                  "avatarId"
                ],
                "additionalProperties": false
              }
            ]
          },
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "template"
              },
              "templateId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "kind",
              "templateId"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "kind": {
                "type": "string",
                "const": "video"
              },
              "videoId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              }
            },
            "required": [
              "kind",
              "videoId"
            ],
            "additionalProperties": false
          }
        ]
      }
    }
  },
  "required": [
    "workspace",
    "image",
    "prompt"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "workspace_123",
      "name": "Client A",
      "slug": "client-a"
    },
    "generation": {
      "id": "gen_video_123",
      "kind": "reaction_video",
      "state": "queued",
      "outputs": [],
      "creditsSpent": 8,
      "input": {
        "operation": "generate_video_from_prompt",
        "mode": "minimax_h3",
        "prompt": "Wave to camera."
      },
      "createdAt": "2026-09-15T12:00:00.000Z",
      "updatedAt": "2026-09-15T12:00:00.000Z"
    },
    "prompt": {
      "operation": "generate_video_from_prompt",
      "source": "user",
      "inspectWith": "get_generation_prompt",
      "overrideWith": "systemPrompt"
    },
    "nextSteps": "Poll get_generation, then show the successful video with render_video_result."
  }
}

generate_video_from_reference

WRITE

REST: POST /api/v2/videos/generate-from-reference

Create one video controlled by reference motion or audio. Default recommendation for direct cloning: Wan 3 Smart Motion, mode wan_3 with guidance video_guided; it uses the inspectable wan3-video-guided system template and needs no custom action prompt or source analysis by default. Every accepted mode takes output duration from the measured source in the backend; this tool has no duration input. H3 has a four-second minimum; Wan 3 has a two-second minimum. Supply actionPrompt only for an explicit change. systemPrompt replaces the default exactly; null removes it. Use Wan 3 audio_guided for audio-led performance. Respect explicit model choices and check catalog limits/pricing. Kling 2.6 Motion Control and Kling 3 Motion Control remain alternatives when explicitly selected. MiniMax H3 guided inputs remain accepted for compatibility but are not recommended for new work. One output; stable idempotencyKey prevents duplicate charges. To SHOW these results in an MCP Apps host, ALWAYS call render_video_result; never hand-build the presentation in chat (no markdown galleries, embedded thumbnails, numbered image lists, or artifacts), even after a widget error. Outside an Apps host, describe items in text and share the dashboard link.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "image": {
      "oneOf": [
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "frame"
            },
            "frameId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "frameId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "upload"
            },
            "mediaId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "mediaId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "product"
            },
            "productImageId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "productImageId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "const": "avatar"
            },
            "avatarId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "kind",
            "avatarId"
          ],
          "additionalProperties": false
        }
      ],
      "description": "The anchor Image: an existing frame, completed image upload, Avatar, or Product image."
    },
    "outputResolution": {
      "type": "string",
      "enum": [
        "480p",
        "720p",
        "768p",
        "1080p",
        "2k"
      ]
    },
    "enableAudio": {
      "type": "boolean"
    },
    "cameraFixed": {
      "type": "boolean"
    },
    "aspectRatio": {
      "type": "string",
      "enum": [
        "9:16",
        "16:9",
        "1:1"
      ]
    },
    "systemPrompt": {
      "description": "Exact system guidance override. Wan 3 Video Guided uses the inspectable wan3-video-guided default when omitted; pass null to remove it. Other modes have no automatic system guidance. The action remains separate.",
      "anyOf": [
        {
          "type": "string",
          "maxLength": 30000
        },
        {
          "type": "null"
        }
      ]
    },
    "maxCredits": {
      "description": "Hard ceiling for one output, including reference and preparation charges.",
      "type": "number",
      "minimum": 0
    },
    "idempotencyKey": {
      "description": "A stable key to reuse if you retry this exact request; a repeat with the same key is NOT charged again.",
      "type": "string",
      "maxLength": 200
    },
    "mode": {
      "type": "string",
      "enum": [
        "one_to_one_standard",
        "one_to_one_clone_premium",
        "minimax_h3",
        "wan_3"
      ]
    },
    "prime": {
      "description": "Wan 3 only: enable native Prime quality and its catalog pricing.",
      "type": "boolean"
    },
    "guidance": {
      "description": "Required for minimax_h3 or wan_3: Smart Motion Audio Guided or Video Guided for the selected model.",
      "type": "string",
      "enum": [
        "audio_guided",
        "video_guided"
      ]
    },
    "reference": {
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "templateId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "templateId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "mediaId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "mediaId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "videoId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "videoId"
          ],
          "additionalProperties": false
        }
      ],
      "description": "An accessible templateId, completed generated videoId, or uploaded mediaId supplying motion Video or Wan 3/H3 Audio/Video guidance. Does not need to be the image’s original source."
    },
    "actionPrompt": {
      "description": "H3 or Wan 3 only: explicit custom action replaces source-derived action and skips analysis. Wan 3 Video Guided needs no custom action by default; its system guidance is separate.",
      "type": "string",
      "minLength": 1,
      "maxLength": 30000
    },
    "adaptation": {
      "description": "H3 or Wan 3 only: requested change to automatically analyzed source action. Wan 3 Video Guided analyzes the source only when adaptation is supplied; audio-only inputs use this as the user instruction.",
      "type": "string",
      "minLength": 1,
      "maxLength": 30000
    }
  },
  "required": [
    "workspace",
    "image",
    "mode",
    "reference"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "workspace_123",
      "name": "Client A",
      "slug": "client-a"
    },
    "generation": {
      "id": "gen_video_456",
      "kind": "reaction_video",
      "state": "queued",
      "outputs": [],
      "creditsSpent": 8,
      "input": {
        "operation": "generate_video_from_reference",
        "mode": "minimax_h3",
        "guidance": "audio_guided",
        "reference": {
          "mediaId": "audio_upload_123"
        }
      },
      "createdAt": "2026-09-15T12:00:00.000Z",
      "updatedAt": "2026-09-15T12:00:00.000Z"
    },
    "prompt": {
      "operation": "generate_video_from_reference",
      "source": "user",
      "inspectWith": "get_generation_prompt",
      "overrideWith": "systemPrompt"
    },
    "nextSteps": "Poll get_generation, then show the successful video with render_video_result."
  }
}

analyze_video

WRITEIDEMPOTENT

REST: POST /api/v2/videos/analyze

Read or prepare video analysis for an accessible template or uploaded VIDEO. Use understanding for saved structure, sections, and the provider-authored generationPrompt. For template standard/audio_guided/video_guided profiles, the saved canonical generationPrompt is reused without another provider request; older templates and direct media use durable legacy action analysis. Guided profiles return reference system guidance and action text in separate fields. They remain available for compatible saved MiniMax H3 workflows but are not recommended for new work; prefer Wan 3 reference guidance. Audio-only media cannot provide visual action analysis; use it directly for audio-guided generation.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "source": {
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "videoId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "videoId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "templateId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "templateId"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "properties": {
            "mediaId": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "required": [
            "mediaId"
          ],
          "additionalProperties": false
        }
      ],
      "description": "Exactly one accessible templateId or completed uploaded video mediaId. Audio-only media has no visual action to analyze."
    },
    "profile": {
      "default": "standard",
      "description": "understanding: free, asynchronous factual source description, contentStructure, demoType, sections, and optional visual/editing/transcript fields; standard: action for prompt-directed H3/H3 Max and other models; audio_guided: visible action and speech for H3 Smart Motion Audio Guided; video_guided: normal action plus separate H3 Smart Motion Video Guided system guidance.",
      "type": "string",
      "enum": [
        "understanding",
        "standard",
        "audio_guided",
        "video_guided"
      ]
    },
    "retryFailed": {
      "description": "Understanding only: explicitly retry a failed attempt. Ordinary reads never retry failed provider work.",
      "type": "boolean"
    },
    "outputDurationSeconds": {
      "description": "Required for audio_guided analysis; changing this prepares a duration-specific result.",
      "type": "integer",
      "minimum": 4,
      "maximum": 15
    }
  },
  "required": [
    "workspace",
    "source"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "analysisId": "939fa80f338e7ae11396f6f0d362043391a84c4f9fb75f3d729b3699990c0755",
    "sourceId": "user-1a2b3c4d-1737100000000",
    "sourceDurationSeconds": 7,
    "profile": "standard",
    "actionPrompt": "Timed section\n0-7s: Lean forward, point once, then smile.\n\nWhole-video description\nAn expressive presentation ending in a warm smile.",
    "systemPrompt": null,
    "timeline": "0-7s: Lean forward, point once, then smile.",
    "model": "gemini-3.1-flash-lite",
    "cached": true,
    "analysisVersion": 3,
    "nextSteps": "Action and system guidance are separate. Use these for inspection or explicit overrides; video generation can prepare source analysis automatically."
  }
}

generate_reaction_prompt

WRITE

REST: POST /api/v2/reaction-prompts

generate_reaction_prompt is deprecated and scheduled to stop working on 2026-10-15. Migrate to the replacement tools. This compatibility release continues serving the existing call. Read the template videoUnderstanding generationPrompt for new imports. Use analyze_video standard only when an older source has no canonical prompt; source-directed generation performs that fallback automatically. Guided generation receives no hidden MCP system text.

Legacy behavior: Generate the exact prompt the user will review before video creation. promptProfile prompt_based returns the normal visual-action prompt and remains a repair path when the template motionAnalysis is missing. For MiniMax H3, audio_guided and video_guided are on-demand profiles and require outputDurationSeconds. Their returned prompt visibly includes a Mandatory reference guidance section followed by Action guidance. Show the complete returned prompt, H3 plan, settings, warning, and estimated credits to the user. Tell the user not to change Mandatory reference guidance and to make only small changes inside Action guidance. Every profile still uses the selected first frame during video generation.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "templateId": {
      "type": "string",
      "minLength": 1
    },
    "promptProfile": {
      "type": "string",
      "enum": [
        "prompt_based",
        "audio_guided",
        "video_guided"
      ]
    },
    "outputDurationSeconds": {
      "type": "integer",
      "minimum": 4,
      "maximum": 15
    },
    "outputResolution": {
      "type": "string",
      "enum": [
        "768p",
        "2k"
      ]
    }
  },
  "required": [
    "workspace",
    "templateId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "templateId": "user-1a2b3c4d-1737100000000",
    "prompt": "Use the supplied reference video as the authoritative guide for motion and editing. When original reference audio is supplied, use it as the only audio. When no reference audio is supplied, keep the generated clip silent.\n\nAction guidance - small edits only\n\nSource clip plan\nClip 1 — 0-2.5s: Lean forward with a surprised smile.\nHARD CUT at 2.5s. Do not morph or interpolate.\nClip 2 — 2.5-7s: Point once, then settle into a warm expression.",
    "timeline": "0.0-2.5s: She leans toward the camera with a surprised smile.\n2.5-7.0s: She points once, then settles into a warm expression.",
    "model": "gemini-3.1-flash-lite",
    "cached": false,
    "promptProfile": "video_guided",
    "sourceDurationSeconds": 7,
    "minimaxH3Plan": {
      "mode": "video_guided",
      "outputDurationSeconds": 7,
      "outputResolution": "768p",
      "estimatedCredits": 14,
      "lineItems": [
        {
          "kind": "output_seconds",
          "seconds": 7,
          "creditsPerSecond": 1,
          "credits": 7
        },
        {
          "kind": "reference_video_seconds",
          "seconds": 7,
          "creditsPerSecond": 1,
          "credits": 7
        }
      ],
      "warning": "The complete provider prompt is shown above. Do not change the Mandatory reference guidance section. Make only small changes inside Action guidance because larger changes can reduce transfer accuracy."
    }
  }
}

list_inspiration_reactions

READ

REST: GET /api/v2/inspiration-reactions

Browse the curated inspiration library when the user needs a source composition or motion reference. Captioned clips include opensOn and motion. render_inspiration_browser loads 12 library items per page and changes pages without another model turn; selecting a clip asks what to create and does not start paid work. Pass the inspiration id to import_reaction_template, wait for readiness, then use the returned templateId with clone_image, analyze_video, or either video generation intent. Source browsing is optional for custom generation and user-supplied references. To SHOW these results in an MCP Apps host, ALWAYS call render_inspiration_browser; never hand-build the presentation in chat (no markdown galleries, embedded thumbnails, numbered image lists, or artifacts), even after a widget error. Outside an Apps host, describe items in text and share the dashboard link.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "description": "Target workspace: a slug, id, or exact name from list_workspaces. Omit to use this connection's default workspace. Must be inside the credential's grant and your current access; overrides the connection-level X-Workspace-Id header.",
      "type": "string"
    },
    "category": {
      "type": "string",
      "maxLength": 80
    },
    "page": {
      "description": "Page number (default 1).",
      "type": "integer",
      "minimum": 1,
      "maximum": 9007199254740991
    },
    "limit": {
      "description": "Per page (max 100). Each tool documents its own default.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "inspiration": [
      {
        "id": "insp_9f8e7d6c",
        "name": "Grandma tastes pickle",
        "category": "Food",
        "durationSeconds": 6.1,
        "videoUrl": "https://cdn.ghostfeed.ai/inspiration/insp_9f8e7d6c/video.mp4",
        "thumbnailUrl": "https://cdn.ghostfeed.ai/inspiration/insp_9f8e7d6c/thumb.jpg",
        "mention": "@inspiration:Grandma tastes pickle (insp_9f8e7d6c)"
      }
    ],
    "total": 1,
    "page": 1,
    "pages": 1,
    "nextSteps": "Import the inspiration id with import_reaction_template, wait for readiness, then use the returned templateId with clone_image, analyze_video, or either video generation intent."
  }
}

list_reaction_video_modes

READ

REST: GET /api/v2/reaction-video-modes

List video modes for generate_video_from_prompt and generate_video_from_reference, with supported intent tools, reference capabilities, costs, resolutions, prompt rules, and audio behavior. MiniMax H3 also returns minimaxH3Modes: prompt_based, audio_guided, and video_guided. Every H3 mode uses the selected frame. Audio-guided adds free source audio. Video-guided adds billed source-video input and includes its audio when present. Read these fields before creating an H3 prompt or video.

No input. Call with no arguments.

Example response
{
  "success": true,
  "data": {
    "modes": [
      {
        "mode": "one_to_one_standard",
        "label": "Kling 2.6 Motion Control",
        "family": "clone",
        "creditsPerSecond": 1,
        "creditsPerSecondByResolution": {
          "720p": 1,
          "1080p": 2
        },
        "supportedResolutions": [
          "720p",
          "1080p"
        ],
        "defaultResolution": "720p",
        "supportsAudio": false,
        "audioEnabledByDefault": false,
        "needsPrompt": false,
        "isDefault": false,
        "isFamilyDefault": true
      },
      {
        "mode": "seedance_2_0_fast",
        "label": "Seedance 2.0 Fast",
        "family": "prompt",
        "creditsPerSecond": 1.5,
        "creditsPerSecondByResolution": {
          "720p": 1.5,
          "1080p": 2.5
        },
        "supportedResolutions": [
          "720p"
        ],
        "defaultResolution": "720p",
        "supportsAudio": true,
        "audioEnabledByDefault": true,
        "needsPrompt": true,
        "maxPromptCharacters": 2000,
        "durationOptions": [
          4,
          5,
          6,
          7,
          8,
          9,
          10,
          11,
          12,
          13,
          14,
          15
        ],
        "supportsAutoDuration": true,
        "isDefault": false,
        "isFamilyDefault": false
      },
      {
        "mode": "minimax_h3_max",
        "label": "MiniMax H3 Max",
        "family": "prompt",
        "creditsPerSecond": 1,
        "creditsPerSecondByResolution": {
          "480p": 0.75,
          "768p": 1,
          "1080p": 2
        },
        "supportedResolutions": [
          "480p",
          "768p",
          "1080p"
        ],
        "defaultResolution": "768p",
        "supportsAudio": false,
        "audioEnabledByDefault": false,
        "needsPrompt": true,
        "durationOptions": [
          5,
          6,
          7,
          8,
          9,
          10,
          11,
          12,
          13,
          14,
          15
        ],
        "supportsAutoDuration": false,
        "isDefault": true,
        "isFamilyDefault": true
      },
      {
        "mode": "seedance_2_5",
        "label": "Seedance 2.5",
        "family": "prompt",
        "creditsPerSecond": 3,
        "creditsPerSecondByResolution": {
          "480p": 1.5,
          "720p": 3,
          "1080p": 6
        },
        "supportedResolutions": [
          "480p",
          "720p",
          "1080p"
        ],
        "defaultResolution": "720p",
        "supportsAudio": true,
        "audioEnabledByDefault": true,
        "needsPrompt": true,
        "durationOptions": [
          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
        ],
        "supportsAutoDuration": true,
        "isDefault": false,
        "isFamilyDefault": false
      },
      {
        "mode": "minimax_h3",
        "label": "MiniMax H3",
        "family": "prompt",
        "creditsPerSecond": 1,
        "creditsPerSecondByResolution": {
          "768p": 1,
          "2k": 2
        },
        "supportedResolutions": [
          "768p",
          "2k"
        ],
        "defaultResolution": "768p",
        "supportsAudio": false,
        "audioEnabledByDefault": false,
        "needsPrompt": true,
        "maxPromptCharacters": 7000,
        "durationOptions": [
          4,
          5,
          6,
          7,
          8,
          9,
          10,
          11,
          12,
          13,
          14,
          15
        ],
        "supportsAutoDuration": false,
        "minimaxH3Modes": [
          {
            "mode": "prompt_based",
            "label": "Prompt based",
            "requiredInputs": [
              "selected_frame",
              "prompt"
            ],
            "inputCreditsPerSecondByResolution": {
              "768p": 0,
              "2k": 0
            }
          },
          {
            "mode": "audio_guided",
            "label": "Audio guided",
            "requiredInputs": [
              "selected_frame",
              "source_audio",
              "prompt"
            ],
            "inputCreditsPerSecondByResolution": {
              "768p": 0,
              "2k": 0
            }
          },
          {
            "mode": "video_guided",
            "label": "Video guided",
            "requiredInputs": [
              "selected_frame",
              "source_video",
              "prompt"
            ],
            "inputCreditsPerSecondByResolution": {
              "768p": 1,
              "2k": 2
            }
          }
        ],
        "defaultMiniMaxH3Mode": "prompt_based",
        "isDefault": false
      }
    ],
    "maxCreditsPerClip": 60,
    "defaults": {
      "clone": "one_to_one_standard",
      "prompt": "minimax_h3_max"
    },
    "nextSteps": "Clone modes reuse a template motion; prompt modes animate from text. Check each mode’s supportedResolutions and creditsPerSecondByResolution before selecting a resolution. The complete charge must fit the mode’s maxCreditsPerClip. Seedance 2.5 Auto reserves 30 seconds. MiniMax H3 defaults to 768p and has prompt_based, audio_guided, and video_guided modes. Every H3 mode uses the selected frame. Modes with audioEnabledByDefault true generate audio unless enableAudio is false."
  }
}

request_reaction_upload

WRITEIDEMPOTENT

REST: POST /api/v2/reactions/upload-url

Get a short-lived presigned R2 upload URL for a LOCAL video file (a video is too large for a tool argument). PUT the raw bytes to uploadUrl with the given Content-Type, then pass the returned fileUrl to import_reaction_template as uploadedFileUrl. Costs no credits.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "filename": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    },
    "contentType": {
      "type": "string",
      "minLength": 3,
      "maxLength": 100
    }
  },
  "required": [
    "workspace"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "upload": {
      "method": "PUT",
      "uploadUrl": "https://abc123.r2.cloudflarestorage.com/shortsbro/users/1a2b3c4d/reactions-uploads/2026/07/18/uuid.mp4?X-Amz-Signature=...",
      "fileUrl": "https://cdn.ghostfeed.ai/users/1a2b3c4d/reactions-uploads/2026/07/18/uuid.mp4",
      "contentType": "video/mp4",
      "expiresInSeconds": 900
    },
    "nextSteps": "PUT the bytes to uploadUrl, then import_reaction_template with uploadedFileUrl=fileUrl."
  }
}

crop_reaction_template

WRITEIDEMPOTENT

REST: POST /api/v2/reaction-templates/crop

Create one reusable reaction template from an exact timestamp range of an existing owned/imported template. Async and free to the user: poll the returned reaction_crop generation; on success output.id is the new template id. Crop-specific video understanding may still be processing, so read the new template before using its descriptions or prompt. Use when the user supplies or approves exact start/end times and a shorter or cleaner reference is useful. For a full clone longer than a model's reference limit, choose natural boundaries and crop adjacent ranges from the original source; each call creates one crop, not a stitched video. The source remains usable.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "templateId": {
      "type": "string",
      "minLength": 1
    },
    "startSeconds": {
      "type": "number",
      "minimum": 0
    },
    "endSeconds": {
      "type": "number",
      "exclusiveMinimum": 0
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 180
    },
    "category": {
      "type": "string",
      "minLength": 1,
      "maxLength": 80
    },
    "idempotencyKey": {
      "description": "A stable key to reuse if you retry this exact request; a repeat with the same key is NOT charged again.",
      "type": "string",
      "maxLength": 200
    }
  },
  "required": [
    "workspace",
    "templateId",
    "startSeconds",
    "endSeconds"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "generation": {
      "id": "gen_crop_aa11bb22",
      "kind": "reaction_crop",
      "state": "running",
      "phase": "cropping",
      "input": {
        "templateId": "user-1a2b3c4d-1737100000000",
        "startSeconds": 2,
        "endSeconds": 9
      },
      "outputs": [],
      "dashboardUrl": "https://ghostfeed.ai/w/client-a/ugc-reactions?template=user-1a2b3c4d-1737100000000&ref=agent",
      "createdAt": "2026-07-28T12:00:00.000Z",
      "updatedAt": "2026-07-28T12:00:00.000Z"
    },
    "nextSteps": "Poll get_generation; output.id is the new cropped template id."
  }
}

import_reaction_template

WRITE

REST: POST /api/v2/reaction-templates/import

Import a reaction TEMPLATE from exactly one source: sourceUrl (a TikTok/Instagram link), uploadedFileUrl (from request_reaction_upload, the local-file path), or inspirationId (a curated clip). Async: returns a reaction_import generation to poll with get_generation. succeeded means the complete source media is ready to use, including sources longer than 30 seconds. Sources over 120 seconds are rejected. Costs no credits. videoUnderstanding is filled in afterwards in the background (inspiration imports reuse the saved result immediately); check its status on get_reaction_template when you need it. Read get_reaction_template for status, description, contentStructure, demoType, sections, generationPrompt, and optional transcript/editing fields. Crop only when the chosen workflow needs a shorter reference. For cloning, load ghostfeed-ugc-reactions and establish which part the user wants before generation. Importing does not authorize paid generation. Deleting templates stays in the dashboard.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 120
    },
    "category": {
      "type": "string",
      "minLength": 1,
      "maxLength": 80
    },
    "sourceUrl": {
      "type": "string",
      "format": "uri"
    },
    "uploadedFileUrl": {
      "type": "string",
      "format": "uri"
    },
    "inspirationId": {
      "type": "string",
      "minLength": 1
    },
    "idempotencyKey": {
      "description": "A stable key to reuse if you retry this exact request; a repeat with the same key is NOT charged again.",
      "type": "string",
      "maxLength": 200
    }
  },
  "required": [
    "workspace",
    "name"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "generation": {
      "id": "gen_5b6c7d8e9f0a",
      "kind": "reaction_import",
      "state": "running",
      "title": "Excited point",
      "input": {
        "templateId": "user-1a2b3c4d-1737100000000",
        "source": "link"
      },
      "outputs": [],
      "dashboardUrl": "https://ghostfeed.ai/w/client-a/ugc-reactions?template=user-1a2b3c4d-1737100000000&ref=agent",
      "createdAt": "2026-07-18T12:00:00.000Z",
      "updatedAt": "2026-07-18T12:00:00.000Z"
    },
    "templateId": "user-1a2b3c4d-1737100000000",
    "mention": "@template:Excited point (user-1a2b3c4d-1737100000000)",
    "nextSteps": "Poll get_generation until terminal. On success read the template and use its id with clone_image, analyze_video, or either video generation intent. Crop only when a shorter reference is useful."
  }
}

generate_reaction_frames

WRITE

REST: POST /api/v2/reactions/frames

generate_reaction_frames is deprecated and scheduled to stop working on 2026-10-15. Migrate to the replacement tools. This compatibility release continues serving the existing call. Use clone_image to recreate a source composition with an Avatar and optional Product image. Use generate_image for prompt-led creation. Each call creates one image; poll get_generation.

Legacy behavior: PHASE 1 of a UGC reaction: create ONE first frame per avatar. With a source, render the avatar into the source pose. Without a source, supply a non-empty stylingPrompt to create the frame directly from the avatar. Source is at most one of templateId, inspirationId (auto-saved to a template first), or referenceImageUrl. For a source-based request, search list_reaction_templates first, then list_inspiration_reactions if the user did not supply an exact source. imageOutputResolution defaults to standard. Source-based work is async and must be polled. Prompt-only work normally returns succeeded reaction_frame generations; a concurrent idempotent replay can return the same queued generation and must be polled. In both flows, the finished frame is output.url and output.id is the frameId. For async generations, immediately call render_image_results with one generating frame item per generation: set generationId to the returned generation id and keep the shared prompt, image model, and requested aspect ratio. The widget polls the read-only result itself. The selected image model and resolution charge applies per avatar. Show all frames and get approval before generate_reaction_video.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "avatars": {
      "minItems": 1,
      "maxItems": 10,
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1
      }
    },
    "templateId": {
      "type": "string",
      "minLength": 1
    },
    "inspirationId": {
      "type": "string",
      "minLength": 1
    },
    "referenceImageUrl": {
      "type": "string",
      "format": "uri"
    },
    "imageModel": {
      "type": "string",
      "enum": [
        "gemini_flash_lite",
        "gemini_flash",
        "nano_banana_2_1",
        "gemini_pro",
        "gpt_low",
        "gpt_medium",
        "gpt_high",
        "gpt_flare",
        "gpt_sunburst"
      ]
    },
    "imageQuality": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ]
    },
    "imageOutputResolution": {
      "type": "string",
      "enum": [
        "standard",
        "1080p"
      ]
    },
    "stylingPrompt": {
      "type": "string",
      "maxLength": 500
    },
    "aspectRatio": {
      "type": "string",
      "enum": [
        "9:16",
        "16:9",
        "1:1"
      ]
    },
    "idempotencyKey": {
      "description": "A stable key to reuse if you retry this exact request; a repeat with the same key is NOT charged again.",
      "type": "string",
      "maxLength": 200
    }
  },
  "required": [
    "workspace",
    "avatars"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "generations": [
      {
        "id": "gen_frame_aa11bb22",
        "kind": "reaction_frame",
        "state": "running",
        "phase": "generating-frames",
        "input": {
          "videoId": "vid_aa11bb22",
          "source": "template",
          "imageModel": "gemini_flash"
        },
        "outputs": [],
        "dashboardUrl": "https://ghostfeed.ai/w/client-a/ugc-reactions?ref=agent",
        "createdAt": "2026-07-18T12:01:00.000Z",
        "updatedAt": "2026-07-18T12:01:00.000Z"
      }
    ],
    "estimatedCreditCost": 1,
    "creditsRemaining": 46,
    "nextSteps": "Poll each generation; the frame image is output.url. Get the user to approve before generate_reaction_video."
  }
}

edit_reaction_frame

WRITE

REST: POST /api/v2/reactions/frames/edit

edit_reaction_frame is deprecated and scheduled to stop working on 2026-10-15. Migrate to the replacement tools. This compatibility release continues serving the existing call. Call edit_image with image:{kind:"frame",frameId} and instruction. Poll the returned generation with get_generation.

Legacy behavior: Edit one existing reaction frame with a text prompt. Use frameId from list_reaction_frames. This creates a new frame and preserves the source frame plus its lineage. It charges the selected image-model and resolution cost once. The returned reaction_frame generation is normally succeeded; a concurrent idempotent replay can return the same queued generation and must be polled. On success, output.url is the edited image and output.id is the new frameId. Show the edit to the user and get approval before generate_reaction_video.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "frameId": {
      "type": "string",
      "minLength": 1,
      "description": "The frameId from list_reaction_frames to edit. The source frame stays unchanged."
    },
    "prompt": {
      "type": "string",
      "minLength": 1,
      "maxLength": 1500,
      "description": "Describe the change to make while preserving the source frame identity and composition."
    },
    "imageModel": {
      "type": "string",
      "enum": [
        "gemini_flash_lite",
        "gemini_flash",
        "nano_banana_2_1",
        "gemini_pro",
        "gpt_low",
        "gpt_medium",
        "gpt_high",
        "gpt_flare",
        "gpt_sunburst"
      ]
    },
    "imageQuality": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ]
    },
    "imageOutputResolution": {
      "type": "string",
      "enum": [
        "standard",
        "1080p"
      ]
    },
    "idempotencyKey": {
      "description": "A stable key to reuse if you retry this exact request; a repeat with the same key is NOT charged again.",
      "type": "string",
      "maxLength": 200
    }
  },
  "required": [
    "workspace",
    "frameId",
    "prompt"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "generation": {
      "id": "gen_frame_edit_bb22cc33",
      "kind": "reaction_frame",
      "state": "succeeded",
      "input": {
        "sourceFrameId": "frm_ee55ff66",
        "prompt": "Replace the shirt with a blue jacket.",
        "imageModel": "gemini_flash",
        "imageOutputResolution": "standard",
        "workspaceSlug": "client-a"
      },
      "outputs": [
        {
          "type": "image",
          "url": "https://cdn.ghostfeed.ai/reactions/frame-edit-bb22cc33.jpg",
          "id": "frm_edit_bb22cc33"
        }
      ],
      "creditsSpent": 1,
      "dashboardUrl": "https://ghostfeed.ai/w/client-a/ugc-reactions?ref=agent",
      "createdAt": "2026-08-08T12:01:00.000Z",
      "updatedAt": "2026-08-08T12:01:02.000Z"
    },
    "creditsRemaining": 45,
    "nextSteps": "Show the edited frame to the user and get approval before generate_reaction_video."
  }
}

generate_reaction_video

WRITE

REST: POST /api/v2/reactions/videos

generate_reaction_video is deprecated and scheduled to stop working on 2026-10-15. Migrate to the replacement tools. This compatibility release continues serving the existing call. Use generate_video_from_prompt for first-frame-guided written action, including H3 and H3 Max. A source template uses its canonical generationPrompt when present and legacy motion analysis otherwise. Use generate_video_from_reference for every audio-guided, video-guided, or motion-control request. Poll get_generation.

Legacy behavior: PHASE 2 of a UGC reaction: animate approved frame(s) into video. Only call after the user has reviewed and approved the frames and exact prompt. For MiniMax H3, set minimaxH3Mode explicitly: prompt_based sends the selected frame and text; audio_guided also sends source audio; video_guided also sends the source video and includes its audio when present. Guided H3 calls require sourceTemplateId, and sourceTemplateId must match every frame lineage. Omit durationSeconds for guided and motion-control calls; the backend derives output duration from the measured source. First call generate_reaction_prompt with the matching profile and show its complete prompt. The prompt already includes visible Mandatory reference guidance; do not remove or rewrite that section. Small user-approved changes belong only inside Action guidance. Ghostfeed sends the approved prompt without adding hidden text. Then call here with promptApproved true and a protective maxCredits. Other clone modes take no prompt and follow source duration. Other prompt modes use text and may support enableAudio. H3 defaults to 768p and supports optional 2k. Async: returns one reaction_video generation per frame to poll. Immediately call render_video_result with status generating, the generationId, prompt, model, method, aspect ratio, and relevant frame/avatar reference images. The view polls and replaces the pending card with the playable video.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "frameIds": {
      "minItems": 1,
      "maxItems": 8,
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1
      }
    },
    "mode": {
      "type": "string",
      "enum": [
        "one_to_one_standard",
        "one_to_one_clone_premium",
        "grok",
        "pixverse",
        "pixverse_1080p",
        "kling_2_5_turbo",
        "seedance_2_0",
        "seedance_2_0_fast",
        "seedance_2_0_mini",
        "minimax_h3",
        "minimax_h3_max",
        "wan_3",
        "seedance_2_5"
      ]
    },
    "minimaxH3Mode": {
      "description": "MiniMax H3 input mode. Every value uses the selected frame. prompt_based adds text only; audio_guided also sends source audio; video_guided also sends the source video and includes its audio when present.",
      "type": "string",
      "enum": [
        "prompt_based",
        "audio_guided",
        "video_guided"
      ]
    },
    "modeInput": {
      "description": "Wan 3 mode input. Use only when mode is wan_3; Prime selects the higher quality endpoint and rate.",
      "type": "object",
      "properties": {
        "guidance": {
          "default": "first_frame",
          "type": "string",
          "enum": [
            "first_frame",
            "audio_guided",
            "video_guided"
          ]
        },
        "prime": {
          "default": false,
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "sourceTemplateId": {
      "description": "Required for MiniMax H3 audio_guided and video_guided. It must match the source-template lineage of every selected frame.",
      "type": "string",
      "minLength": 1
    },
    "prompt": {
      "type": "string",
      "description": "Motion prompt for prompt modes. Call list_reaction_video_modes and obey the selected mode’s maxPromptCharacters; clone modes reject prompt."
    },
    "promptApproved": {
      "description": "Required as true for prompt modes. Set it only after showing the user the exact prompt (after trimming surrounding whitespace) and receiving explicit approval. Clone modes do not use a prompt and do not require this.",
      "type": "boolean"
    },
    "durationSeconds": {
      "type": "number",
      "exclusiveMinimum": 0
    },
    "enableAudio": {
      "description": "Controls synchronized generated audio for modes that advertise supportsAudio true. Unsupported modes reject true; MiniMax H3 output audio is provider-native and is not configurable here.",
      "type": "boolean"
    },
    "outputResolution": {
      "description": "Requested output resolution. Call list_reaction_video_modes first and use the selected mode’s supportedResolutions. Resolution availability and defaults are mode-specific; MiniMax H3 defaults to 768p and supports an optional 2k upgrade.",
      "type": "string",
      "enum": [
        "480p",
        "720p",
        "768p",
        "1080p",
        "2k"
      ]
    },
    "maxCredits": {
      "description": "Refuse to start any clip that would cost more than this many credits. Clone modes use the source clip length and the selected model/resolution rate. The mode’s maxCreditsPerClip (from list_reaction_video_modes) always applies; this only tightens it.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "idempotencyKey": {
      "description": "A stable key to reuse if you retry this exact request; a repeat with the same key is NOT charged again.",
      "type": "string",
      "maxLength": 200
    }
  },
  "required": [
    "workspace",
    "frameIds"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "generations": [
      {
        "id": "gen_vid_cc33dd44",
        "kind": "reaction_video",
        "state": "running",
        "phase": "generating-video",
        "input": {
          "videoId": "vid_aa11bb22",
          "frameId": "frm_ee55ff66",
          "mode": "minimax_h3",
          "minimaxH3Mode": "video_guided",
          "sourceTemplateId": "user-1a2b3c4d-1737100000000"
        },
        "outputs": [],
        "dashboardUrl": "https://ghostfeed.ai/w/client-a/ugc-reactions?video=vid_aa11bb22&ref=agent",
        "createdAt": "2026-07-18T12:05:00.000Z",
        "updatedAt": "2026-07-18T12:05:00.000Z"
      }
    ],
    "skipped": [],
    "creditsSpent": 8,
    "creditsRemaining": 38,
    "nextSteps": "Poll each generation until its state is succeeded; the clip is output.url. Report spend to the user."
  }
}

regenerate_reaction_frame

WRITE

REST: POST /api/v2/reactions/frames/regenerate

regenerate_reaction_frame is deprecated and scheduled to stop working on 2026-10-15. Migrate to the replacement tools. This compatibility release continues serving the existing call. Read get_generation_setup for saved generation inputs, or get_image for frame lineage. Start clone_image or generate_image with the intended settings and a new idempotencyKey. Reuse a key only to retry the same request.

Legacy behavior: Redo a frame the user was not happy with. Identify it with EITHER frameId (any frame from list_reaction_frames, including ones a person made in the dashboard) OR generationId (a frame this API started); pass exactly one. Re-runs frame generation on the same avatar + source and charges another frame credit. Poll the same generation until it succeeds with a fresh frame, then get approval before generate_reaction_video.

Input schema
{
  "type": "object",
  "properties": {
    "workspace": {
      "type": "string",
      "minLength": 1,
      "description": "Required write target: a workspace slug or id from list_workspaces. Writes never inherit the connection default."
    },
    "generationId": {
      "description": "The generationId of a frame you started through the agent API.",
      "type": "string",
      "minLength": 1
    },
    "frameId": {
      "description": "A frameId from list_reaction_frames. Use this for any frame, including ones a person made in the dashboard, which have no generationId. Pass exactly one of the two.",
      "type": "string",
      "minLength": 1
    }
  },
  "required": [
    "workspace"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
Example response
{
  "success": true,
  "data": {
    "workspace": {
      "id": "6a18c36ee586c7e44e4ece67",
      "name": "Client A",
      "slug": "client-a"
    },
    "generation": {
      "id": "gen_frame_aa11bb22",
      "kind": "reaction_frame",
      "state": "running",
      "phase": "generating-frames",
      "input": {
        "videoId": "vid_aa11bb22",
        "source": "template",
        "imageModel": "gemini_flash"
      },
      "outputs": [],
      "dashboardUrl": "https://ghostfeed.ai/w/client-a/ugc-reactions?ref=agent",
      "createdAt": "2026-07-18T12:01:00.000Z",
      "updatedAt": "2026-07-18T12:07:00.000Z"
    },
    "nextSteps": "Poll until it succeeds with a fresh frame, then get approval before the video."
  }
}