Vercel AI SDK: generate video with a Sume API tool call
Generate video from the Vercel AI SDK with a tool() that calls Sume's POST /v1/videos on your server, returns the job id, and polls for the clip.

To generate video from the Vercel AI SDK with Sume, define a tool() whose execute function calls POST https://api.sume.com/v1/videos from your server with an Idempotency-Key, and return the job id instead of the video, because video generation typically takes 30 seconds to several minutes.
The Sume facts come from Video Generation, Jobs and results, and the TypeScript SDK page; the AI SDK facts come from its Tool Calling, MCP, and experimental_generateVideo pages for AI SDK 7.x, all read on 2026-09-27. The request shape itself is covered in An OpenRouter-compatible video API.
Can I use experimental_generateVideo with Sume?
Not directly. experimental_generateVideo() generates videos using a video model (its model parameter is a VideoModelV4), and the AI SDK marks video generation as experimental. Sume has no official AI SDK provider, so this post calls Sume over plain HTTPS from a tool you write. That also leaves room for Sume-only request values such as model: "sume/auto".
How do I define the video tool?
A tool has a description, an inputSchema that the model reads and the SDK uses to validate the model's tool calls, and an async execute function. execute also receives options as a second parameter, including the tool call id and the abort signal:
- The tool call id gives each tool call its own
Idempotency-Key, so a retry of that call reuses it. On/v1/videos, a replay of the same key returns the original job instead of a new one. modelandpromptare the required fields;duration(whole seconds) andaspect_ratioare optional.- The AI SDK says tool code runs wherever your application runs, so call
generateTextorstreamTextfrom a server route. A Sume API key spends your credits and has no browser-safe variant: never ship it to client JavaScript or aNEXT_PUBLIC_*variable. - An error thrown in
executeis added as atool-errorcontent part, so in a multi-step call the model can react to it.
import { tool } from "ai";
import { z } from "zod";
export const startVideo = tool({
description: "Start a Sume video job. Returns a job id; the video takes minutes.",
inputSchema: z.object({
prompt: z.string(),
aspect_ratio: z.string().optional().describe("For example 16:9 or 9:16"),
duration: z.number().optional().describe("Length in whole seconds"),
}),
execute: async (input, { toolCallId, abortSignal }) => {
const res = await fetch("https://api.sume.com/v1/videos", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SUME_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": `chat-video-${toolCallId}`,
},
body: JSON.stringify({ model: "sume/auto", ...input }),
signal: abortSignal,
});
if (!res.ok) throw new Error(`Sume returned ${res.status}`);
const job = await res.json();
return { job_id: job.id, status: job.status };
},
});Why return a job id instead of waiting for the video?
POST /v1/videos answers 202 at once with id, polling_url, and status: "pending". The video comes later, so return the id to the chat and read GET /v1/videos/{id} from your server, or from a second tool, at a reasonable interval; the docs suggest 30 seconds. Instead of polling, you can send callback_url (HTTPS), and Sume POSTs a signed webhook once the job reaches a terminal state; Sume's docs say to keep polling available for missed or retried deliveries.
| `status` | Meaning | What the chat shows |
|---|---|---|
pending | Submitted and queued. | Still working; check later. |
in_progress | The video is being generated. | Still working; check later. |
completed | The video is ready; unsigned_urls is filled. | The video. |
failed | Generation failed; read the error field. | The error. |
cancelled | Canceled before it finished. | That it was canceled. |
How do I get a URL the chat can show?
On completed, unsigned_urls points at GET /v1/videos/{id}/content, which the docs call with your API key, so fetch it from the server, never from the chat UI. The same job is also visible at GET /v1/jobs/{id}/result, where result.artifacts[].url is a media.sume.com URL, the form Sume returns generated outputs in. Sume's docs describe completed-job artifacts there as public, so that URL is the one to hand to the chat.
Does aborting the chat cancel the video?
No. The AI SDK forwards the abort signal from generateText and streamText to the tool, and passing it to fetch stops your request. The Sume job is another matter: a client-side timeout does not cancel it, and it keeps running and still bills. To stop it, call POST /v1/jobs/{id}/cancel. Cancellation succeeds only before generation work starts; after that the API answers 409 job_generation_already_started. See how to cancel an AI video job.
Can I load Sume's MCP tools instead?
Yes. createMCPClient from @ai-sdk/mcp takes an HTTP transport, the one the AI SDK recommends for production, with url: "https://mcp.sume.com/mcp". Unattended server code can put your key in headers: Sume's docs call API-key remote MCP the other path, for automation that does not speak OAuth. mcpClient.tools() loads every tool the server offers, and an API-key session on Sume can see write and paid tools. The AI SDK treats server annotations as untrusted hints and advises tool allowlists and your own toolApproval policy; passing schemas to tools() pulls only the tools you define. For a single request, close the client when the response is finished.
Sume's basics page says hosted MCP still works but is not part of the primary path today, so the REST tool above is the more direct route for a single clip.
Sources
Related posts
More in Integrations
- Vercel Cron Jobs: call the Sume API daily without duplicates
A Vercel cron job sends a GET to your route, which calls the Sume API with a date-based Idempotency-Key, so a duplicate invocation cannot bill twice.
- Windsurf MCP server: add Sume's hosted MCP in Devin Desktop
Windsurf is now Devin Desktop. Add Sume's hosted MCP server to the Devin Local agent or the legacy Cascade agent with an API-key header.
- Zapier AI video automation: two Zaps and one Sume webhook
One Zap starts a Sume video run with a Custom Request; a second catches Sume's signed webhook with Catch Raw Hook and verifies it in a Code step.
- Add Sume to Claude as a custom connector (remote MCP)
Add Sume's hosted MCP server to Claude under Customize > Connectors, see what Sume's OAuth consent grants, and decide whether to allow paid tools.
Written by Sume