Documentation Index
Fetch the complete documentation index at: https://docs.skills.video/llms.txt
Use this file to discover all available pages before exploring further.
This quick start shows how to call skills.video with a minimal fetch request: create a google-veo-3.1 generation with a prompt, receive an id, and poll until it finishes.
Send your first request
Use any runtime that supports fetch. Replace placeholders before running.
const API_KEY = "<YOUR_API_KEY>";
const BASE_API_URL = "https://open.skills.video/api";
async function createTask() {
const res = await fetch(`${BASE_API_URL}/v1/generation/google/veo-3.1`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
prompt: "sunrise over mountains in watercolor style"
})
});
if (!res.ok) {
throw new Error(`create failed: ${res.status} ${await res.text()}`);
}
const data = await res.json(); // { id, status, ... }
console.log("created task:", data.id);
return data.id;
}
Use file upload when a model needs local image, video, or audio input. JSON requests are enough for text and URLs, but they cannot carry raw file bytes directly.
For file inputs, switch to multipart/form-data and send files in the exact field names defined by that model’s OpenAPI schema.
For example, POST /v1/generation/google/nano-banana-pro accepts image_urls[], and each item can be either a public URL or a binary file.
curl -X POST "https://open.skills.video/api/v1/generation/google/nano-banana-pro" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-H "Accept: application/json" \
-F "prompt=Turn this sketch into a clean product mockup" \
-F "image_urls=@./assets/sketch.png" \
-F "image_urls=https://images.example.com/reference.jpg" \
-F "aspect_ratio=1:1" \
-F "resolution=2K"
If you use fetch in Node.js, send a FormData body and append files with the same field key.
import { readFile } from "node:fs/promises";
const API_KEY = "<YOUR_API_KEY>";
const BASE_API_URL = "https://open.skills.video/api";
async function createImageTaskWithFile() {
const bytes = await readFile("./assets/sketch.png");
const form = new FormData();
form.append("prompt", "Turn this sketch into a clean product mockup");
form.append("image_urls", new Blob([bytes], { type: "image/png" }), "sketch.png");
form.append("aspect_ratio", "1:1");
form.append("resolution", "2K");
const res = await fetch(`${BASE_API_URL}/v1/generation/google/nano-banana-pro`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`
},
body: form
});
if (!res.ok) {
throw new Error(`create failed: ${res.status} ${await res.text()}`);
}
return res.json();
}
If a model schema defines a direct file field, the upload shape is:
-F "file=@./path/to/input.png"
form.append("file", new Blob([bytes], { type: "image/png" }), "input.png");
Use the same pattern for other models: check that model’s OpenAPI schema for the exact file-capable fields, accepted MIME types, and limits.
Poll for the result
Poll the generation by id until it completes or fails.
const API_KEY = "<YOUR_API_KEY>";
const BASE_API_URL = "https://open.skills.video/api";
async function pollTask(id: string) {
for (let i = 0; i < 20; i++) {
const res = await fetch(`${BASE_API_URL}/v1/generation/${id}`, {
headers: { Authorization: `Bearer ${API_KEY}` }
});
if (!res.ok) {
throw new Error(`poll failed: ${res.status} ${await res.text()}`);
}
const task = await res.json(); // { status, outputUrl?, error? }
if (task.status === "succeeded") {
console.log("done:", task.outputUrl ?? task);
return task;
}
if (task.status === "failed") {
throw new Error(`task failed: ${task.error ?? "unknown error"}`);
}
await new Promise((r) => setTimeout(r, 3000));
}
throw new Error("polling timed out");
}
// Example usage
(async () => {
const id = await createTask();
await pollTask(id);
})();
Use SSE instead of polling (optional)
Use SSE when you need near real-time status updates in one long-lived response, and want to avoid repeated polling calls.
For full request and response details, see SSE Streaming.
If a model uses POST /v1/generation/{provider}/{model}, its SSE form is:
POST /v1/generation/sse/{provider}/{model}
For example:
curl -N -X POST "https://open.skills.video/api/v1/generation/sse/google/veo-3.1" \
-H "Authorization: Bearer <YOUR_API_KEY>" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"prompt": "sunrise over mountains in watercolor style"
}'
Typical stream output:
data: {"id":"<GENERATION_ID>","status":"IN_QUEUE"}
data: {"id":"<GENERATION_ID>","status":"IN_PROGRESS"}
data: {"id":"<GENERATION_ID>","status":"COMPLETED","data":{"<OUTPUT_FIELD>":"<OUTPUT_VALUE>"}}