Quick Start
Everything you need to start generating videos with the Golpo REST API v2.
Auth header
x-api-key: YOUR_API_KEYContent-Type
application/jsonBest for
Server-to-server integrations, automation workflows, internal dashboards, partner apps
Prerequisites
Valid API plan · API key issued per workspace · HTTPS requests only · 15 MB max file upload
POST /api/v2/videos/generate requires x-api-key. Returns 403 with the message “API v2 requires API key authentication. Provide ‘x-api-key’ header.” if the header is missing.Endpoints
Five REST endpoints covering the full video lifecycle — generate, list, retrieve, update, and delete.
Generate a video from a prompt or script. JSON body, x-api-key required.
import fetch from "node-fetch";
const API_KEY = "api-key"; // Replace with your Golpo API key
const payload = {
prompt: "Explain the quarterly roadmap",
background_track: "engaging"
};
const BASE_URL = "{BASE_URL}"; // You will receive this when creating an API key
const response = await fetch(`${BASE_URL}/api/v2/videos/generate`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY
},
body: JSON.stringify(payload)
});
const data = await response.json();
console.log(data);Run with: node --env-file=.env generate.js
Retrieve videos belonging to the authenticated user. Supports limit and offset query params. x-api-key required.
import fetch from "node-fetch";
const BASE_URL = "{BASE_URL}"; // You will receive this when creating an API key
// Query params:
// limit — max number of videos to return (optional)
// offset — number of videos to skip (optional, for pagination)
const response = await fetch(`${BASE_URL}/api/v2/videos?limit=10&offset=0`, {
headers: {
"x-api-key": "api-key"
}
});
const data = await response.json();
console.log(data.videos); // array of video objects
console.log(data.total); // total number of videosRun with: node --env-file=.env list-videos.js
Retrieve metadata for a single video by ID. x-api-key required.
const BASE_URL = "{BASE_URL}"; // You will receive this when creating an API key
const VIDEO_ID = "video_id";
const response = await fetch(`${BASE_URL}/api/v2/videos/${VIDEO_ID}`, {
headers: { "x-api-key": "api-key" }
});
console.log(await response.json());Run with: node --env-file=.env get-video.js <video_id>
Update video metadata. Only 'title' and 'visibility' can be updated.
const BASE_URL = "{BASE_URL}"; // You will receive this when creating an API key
const VIDEO_ID = "video_id";
const payload = { title: "Updated internal briefing", visibility: "private" };
const response = await fetch(`${BASE_URL}/api/v2/videos/${VIDEO_ID}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
"x-api-key": "api-key"
},
body: JSON.stringify(payload)
});
console.log(await response.json());Run with: node --env-file=.env update-video.js <video_id>
Delete a generated video (soft delete). x-api-key required.
const BASE_URL = "{BASE_URL}"; // You will receive this when creating an API key
const VIDEO_ID = "video_id";
const response = await fetch(`${BASE_URL}/api/v2/videos/${VIDEO_ID}`, {
method: "DELETE",
headers: { "x-api-key": "api-key" }
});
console.log(await response.json());Run with: node --env-file=.env delete-video.js <video_id>
Request Body
Full parameter reference for POST /api/v2/videos/generate.
prompt is required. All other parameters are optional.| Parameter | Type | Default | Required | Description |
|---|---|---|---|---|
| prompt | string | — | Required | Main prompt/topic for the video. |
| reference_source | array[string] | None | Optional | List of document URLs (https/s3) used as reference material. Use /upload-file to obtain URLs; server-side callers may also pass local file paths. |
| narration_instructions | string | "" | Optional | Describe how the narration voice should sound — accent, tone, pace, and delivery style. Examples: "Speak in a warm British accent with a calm, professorial tone", "Fast-paced sports commentator style". |
| enable_script_only_mode | boolean | false | Optional | Only generate the script — skip TTS and video rendering. Status response returns script_text. |
| custom_script | string | None | Optional | Use a script you supply instead of generating one. Capped at approximately 15 estimated minutes. NOTE:Scripts longer than ~15 estimated minutes are rejected with 422. If timing is also set, it must be greater than or equal to the estimated script duration. Embedding paired [START][IMAGE N]...[END][IMAGE N] and [START][VIDEO N]...[END][VIDEO N] markers in your script controls where your uploaded custom_images and custom_videos appear. See the Inserting Images in Script and Inserting Videos in Script sections for the placement rules — markers that violate the format are silently dropped. |
| narration_voice | string | "female-1" | Optional | Narration voice. Allowed values: "female-1" (default), "female-2", "male-1", "male-2". |
| enable_color | boolean | true | Optional | Enable color video generation pipeline. |
| narration_language | string | "en" | Optional | Language for narration. Lowercase only — accepts language keywords (e.g. "english", "hindi"), ISO 639-1 codes (e.g. "en", "hi"), or code-switch variants (e.g. "hi-en"). |
| background_track | string | None | Optional | Background music track. Allowed values: "jazz", "lofi", "dramatic", "engaging", "hyper", "inspirational", "documentary". |
| video_orientation | string | "horizontal" | Optional | Video orientation: "horizontal" (16:9) or "vertical" (9:16). |
| enable_podcast_engine | boolean | false | Optional | When true, generate audio-only podcast output (no video). Status response returns podcast_url. |
| timing | string | "1" | Optional | Video/podcast duration in minutes (as string) or "auto" to let the system determine it. Supported values: "0.25", "0.5", "1", "2", "4", "8", "10", "15", "auto". NOTE:"15" is only available on the Enterprise Custom plan. Other plans receive a 403 when requesting 15-minute videos. Contact founders@golpoai.com to upgrade. |
| watermark | boolean | false | Optional | Include a watermark in the video. |
| custom_logo | string | None | Optional | Custom logo URL (https/s3). Use /upload-file first; server-side callers may also pass local file paths. |
| logo_position | string | None | Optional | Logo placement. Allowed values: "tl" (top-left), "tr" (top-right), "bl" (bottom-left), "br" (bottom-right). NOTE:Only valid when watermark=true or custom_logo is provided. Setting logo_position without either is rejected with 422, since no logo or watermark would render. |
| visual_instructions | string | "" | Optional | Visual instructions to guide how the video looks. Examples: "Show more graphs and charts", "Cinematic transitions", "Dark moody aesthetic with neon accents". |
| golpo_video_engine | string | "golpo_canvas" | Optional | Video generation engine: "golpo_canvas" (default) or "golpo_sketch". NOTE:When using golpo_canvas, canvas_style_variant is required. When using golpo_sketch, sketch_style_variant is required. Setting either to null is rejected with 422. |
| canvas_style_variant | string | "chalkboard_color" | Optional | Golpo Canvas style variant. Allowed values: "chalkboard_bw", "chalkboard_color" (default), "whiteboard", "modern_minimal", "technical", "sharpie", "playful", "editorial", "illustrations". Required when golpo_video_engine is "golpo_canvas". |
| sketch_style_variant | string | "classic" | Optional | Golpo Sketch style variant. Allowed values: "classic" (default), "improved(beta)", "formal", "crayon", "dry_erase", "professional_clean", "creative", "infographics". Required when golpo_video_engine is "golpo_sketch". |
| own_narration_source | string | None | Optional | URL (https/s3) to an audio or video file to use instead of generating script and TTS. Server-side callers may also pass local file paths. Useful for generating a video from your own existing audio or video narration. |
| use_ai_audio_at | array[integer] | None | Optional | List of 1-indexed positions in custom_videos whose original audio should be replaced with AI-generated narration. Videos not listed keep their original audio. NOTE:Only valid when custom_videos is provided. Length must not exceed the number of custom_videos. |
| custom_images | array[string] | None | Optional | List of image URLs (https/s3) to insert into the video. Server-side callers may also pass local file paths. |
| custom_images_description | array[string] | None | Optional | List of descriptions for custom images (one per image). NOTE:Required when custom_images is provided. Must have the same length as custom_images. Descriptions tell the Golpo AI what each image shows, so it can place each image at the right moment in the script and reference it in the narration. More specific descriptions produce more contextually accurate videos. |
| keep_original_images | array[boolean] | None | Optional | List of booleans indicating whether to use each image as-is without AI processing (one per image). NOTE:Only valid when custom_images is provided. Length must not exceed the number of custom_images. |
| disable_image_animation | array[boolean] | None | Optional | List of booleans indicating whether to skip animation for each image (one per image). NOTE:Only valid when custom_images is provided. Length must not exceed the number of custom_images. |
| custom_videos | array[string] | None | Optional | List of video URLs (https/s3) to insert into the video. Server-side callers may also pass local file paths. |
| custom_videos_description | array[string] | None | Optional | List of descriptions for custom videos (one per video). NOTE:Required when custom_videos is provided. Must have the same length as custom_videos. Descriptions tell the Golpo AI what each video shows, so it can cut to each clip at the right moment in the script and frame the surrounding narration. More specific descriptions produce more contextually accurate videos. |
| visibility | string | None | Optional | Video visibility. Allowed values: "public" (appears in the Golpo gallery) or "private". |
| video_id | string | None | Optional | Optional custom video/job id assigned by the caller. |
| reference_images | array[string] | None | Optional | List of reference image URLs (https/s3) for problem-solving mode. The video is generated around the provided images. Server-side callers may also pass local file paths. Best suited for explaining math, science, or any problem captured as an image — pair with timing: "auto" so the Golpo AI picks a duration that matches the complexity of the problem. |
| pen_animation_style | string | None | Optional | Pen cursor animation style. Allowed values: "stylus", "marker", "pen". NOTE:Only supported with the Golpo Canvas engine. Setting this field with "golpo_video_engine": "golpo_sketch" is rejected with 422. |
| own_narration_video_mode | boolean | None | Optional | When true, the user's own narration video is overlaid as a picture-in-picture thumbnail. Requires own_narration_source to point to a video file. NOTE:Setting own_narration_video_mode=true with a non-video own_narration_source returns 422. |
| own_narration_video_position | string | "left-top" | Optional | Corner for the picture-in-picture overlay. Allowed values: "left-top" (default), "right-top", "left-bottom", "right-bottom". |
| scene_pacing | string | "normal" | Optional | Pacing level: "normal" (15s max per scene) or "fast" (10s max per scene). Works with both Golpo Canvas and Golpo Sketch. |
| onscreen_text_language | string | None | Optional | Language for on-screen text. Same value space as narration_language. Useful when displayed text should differ from the narration language. NOTE:Only supported with the Golpo Canvas engine. Setting this field with "golpo_video_engine": "golpo_sketch" is rejected with 422. If omitted, on-screen text uses the same language as narration_language. Example: narration_language: "hindi", onscreen_text_language: "english" — narration in Hindi, on-screen text in English. |
Parameter Groups
Parameters organized by purpose for easier discovery.
Content
Narration
Visual
User Media
Audio
Format
Branding
Workflow
Upload File
Use /api/v2/videos/upload-file to get a hosted URL before calling /generate.
/upload-file into reference_source, the file is permanently deleted from storage after its text is extracted during generation. The same URL cannot be reused for another video or podcast — you must upload the document again via /upload-file to get a fresh URL for each new generation.multipart/form-data| Field | Type | Required | Description |
|---|---|---|---|
| file | File | Yes | Single file to upload (file metadata is used to generate a presigned URL). |
Documents
PDF · DOC · DOCX · TXT · MD · CSV · XLSX · XLS · PPT · PPTX
Audio
MP3 · WAV · M4A · OGG · FLAC
Video
MP4 · MOV · M4V · AVI · MKV · WEBM
Images
JPG · JPEG · PNG · GIF · WEBP
// Response from POST /api/v2/videos/upload-file
{
"upload_url": "https://...", // Presigned PUT URL — upload the file here
"file_url": "https://...", // Pass this into /generate
"file_name": "document.pdf",
"content_type": "application/pdf"
}const API_KEY = "api-key";
const BASE_URL = "{BASE_URL}";
// Step 1: Get presigned URL
async function uploadFile(file) {
const formData = new FormData();
formData.append('file', file);
const response = await fetch(`${BASE_URL}/api/v2/videos/upload-file`, {
method: 'POST',
headers: { 'x-api-key': API_KEY },
body: formData
});
const { upload_url, file_url, content_type } = await response.json();
// Step 2: Upload bytes to the presigned URL
await fetch(upload_url, {
method: 'PUT',
headers: { 'Content-Type': content_type },
body: file
});
// Step 3: Return file_url for use in /generate
return file_url;
}
// Usage
const fileInput = document.querySelector('#file-input');
const fileUrl = await uploadFile(fileInput.files[0]);
console.log('File uploaded, URL:', fileUrl);
// Use fileUrl in your /generate request (reference_source, custom_logo, etc.)User Assets
Upload images or videos to embed directly into the generated video.
custom_images and custom_videos accept the file_url returned by /upload-file. Server-side callers may pass local file paths directly. Description arrays (custom_images_description, custom_videos_description) are required and must match the length of their image/video arrays.const API_KEY = "api-key";
const BASE_URL = "{BASE_URL}";
async function uploadFile(file) {
const formData = new FormData();
formData.append('file', file);
const presign = await fetch(`${BASE_URL}/api/v2/videos/upload-file`, {
method: 'POST',
headers: { 'x-api-key': API_KEY },
body: formData
});
const { upload_url, file_url, content_type } = await presign.json();
await fetch(upload_url, {
method: 'PUT',
headers: { 'Content-Type': content_type },
body: file
});
return file_url;
}
// Step 1: Upload images and videos
const image1Url = await uploadFile(imageFile1);
const image2Url = await uploadFile(imageFile2);
const video1Url = await uploadFile(videoFile1);
const video2Url = await uploadFile(videoFile2);
// Step 2: Generate with custom images and videos
const generatePayload = {
prompt: "Create a product showcase video",
custom_images: [image1Url, image2Url],
custom_images_description: [
"Product front view with logo",
"Product in use by customer"
],
keep_original_images: [false, false],
disable_image_animation: [false, true],
custom_videos: [video1Url, video2Url],
custom_videos_description: [
"Customer testimonial",
"Product walkthrough"
],
// 1-indexed positions in custom_videos whose original audio
// should be replaced with AI-generated narration.
use_ai_audio_at: [2],
video_orientation: "horizontal",
watermark: false
};
const response = await fetch(`${BASE_URL}/api/v2/videos/generate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': API_KEY
},
body: JSON.stringify(generatePayload)
});
const result = await response.json();
console.log('Job ID:', result.job_id);Local Paths
Pass absolute or relative file paths directly from server-side environments — the v2 backend uploads them transparently.
/upload-file first.import fetch from "node-fetch";
const API_KEY = "api-key";
const BASE_URL = "{BASE_URL}";
// Server-side only: when the API server has filesystem access
// to these files, it uploads them transparently before generation.
const payload = {
prompt: "Create a comprehensive product demo video",
reference_source: [
"./documents/product-spec.pdf",
"C:\\Users\\Documents\\brief.docx",
"/home/user/documents/slides.pptx"
],
custom_logo: "./assets/company-logo.png",
custom_images: [
"./images/product-front.jpg",
"./images/product-in-use.jpg"
],
custom_images_description: [
"Product front view with branding",
"Product being used by customer"
],
keep_original_images: [false, false],
disable_image_animation: [false, true],
own_narration_source: "./audio/founder-narration.mp3",
narration_voice: "female-1",
background_track: "engaging",
video_orientation: "horizontal",
watermark: false,
enable_color: true,
narration_language: "en",
timing: "5"
};
const response = await fetch(`${BASE_URL}/api/v2/videos/generate`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY
},
body: JSON.stringify(payload)
});
const data = await response.json();
console.log("Job ID:", data.job_id);Local paths only work when the API server can access these files. Remote clients must upload via /upload-file first.
Language Quickstarts
Ready-to-run examples for the most common video generation patterns.
Upload Workflow
Full pattern: upload supporting files via /upload-file, then call /generate with the returned URLs in reference_source.
const API_KEY = "api-key";
const BASE_URL = "{BASE_URL}";
// Step 1: Helper to upload a file via /upload-file
async function uploadFile(file) {
const formData = new FormData();
formData.append('file', file);
const presign = await fetch(`${BASE_URL}/api/v2/videos/upload-file`, {
method: 'POST',
headers: { 'x-api-key': API_KEY },
body: formData
});
const { upload_url, file_url, content_type } = await presign.json();
await fetch(upload_url, {
method: 'PUT',
headers: { 'Content-Type': content_type },
body: file
});
return file_url;
}
// Step 2: Upload all reference docs and collect URLs
const fileInput = document.querySelector('#uploads');
const referenceUrls = await Promise.all(
Array.from(fileInput.files).map((f) => uploadFile(f))
);
// Step 3: Generate the video with the uploaded references
const generatePayload = {
prompt: 'Summarize this slide deck for executives',
reference_source: referenceUrls,
narration_voice: 'female-1',
narration_language: 'spanish'
};
const response = await fetch(`${BASE_URL}/api/v2/videos/generate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': API_KEY
},
body: JSON.stringify(generatePayload)
});
const result = await response.json();
console.log('Generation started:', result);Attach files via <input id="uploads" type="file" multiple /> before calling this helper.
Golpo Sketch
golpo_video_engine: golpo_sketchWhiteboard-style sketch animation. Pick a sketch_style_variant and optionally tune scene_pacing (normal/fast).
import fetch from "node-fetch";
const API_KEY = "api-key";
const BASE_URL = "{BASE_URL}";
const payload = {
prompt: "Explain how neural networks work",
golpo_video_engine: "golpo_sketch",
// sketch_style_variant options:
// "classic" (default), "improved(beta)", "formal",
// "crayon", "dry_erase", "professional_clean",
// "creative", "infographics"
sketch_style_variant: "improved(beta)",
scene_pacing: "fast", // "normal" (15s max) | "fast" (10s max)
background_track: "engaging",
watermark: false
};
const response = await fetch(`${BASE_URL}/api/v2/videos/generate`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY
},
body: JSON.stringify(payload)
});
console.log(await response.json());Run with: node --env-file=.env golpo-sketch.js
Golpo Canvas
golpo_video_engine: golpo_canvasCanvas-based video with rich style variants (chalkboard, whiteboard, editorial…) plus pen_animation_style and scene_pacing.
import fetch from "node-fetch";
const API_KEY = "api-key";
const BASE_URL = "{BASE_URL}";
const payload = {
prompt: "Create a product overview video",
golpo_video_engine: "golpo_canvas",
// canvas_style_variant options:
// "chalkboard_bw", "chalkboard_color" (default), "whiteboard",
// "modern_minimal", "technical", "sharpie", "playful", "editorial",
// "illustrations"
canvas_style_variant: "modern_minimal",
pen_animation_style: "stylus", // "stylus" | "marker" | "pen"
scene_pacing: "normal", // "normal" (15s max) | "fast" (10s max)
watermark: false
};
const response = await fetch(`${BASE_URL}/api/v2/videos/generate`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY
},
body: JSON.stringify(payload)
});
console.log(await response.json());Run with: node --env-file=.env golpo-canvas.js
Display Language
Generate a video where the narration and the on-screen text are in different languages. Only supported with the Golpo Canvas engine.
Display Language
onscreen_text_languageGenerate a video where the narration and the on-screen text are in different languages — e.g. Hindi voice-over with English text displayed in the video. Only supported with the Golpo Canvas engine; setting onscreen_text_language with golpo_video_engine: golpo_sketch is rejected with 422.
import fetch from "node-fetch";
const API_KEY = "api-key";
const BASE_URL = "{BASE_URL}";
// Narrator speaks Hindi; on-screen text, titles, and labels are in English.
const payload = {
prompt: "Explain the water cycle",
narration_language: "hindi",
onscreen_text_language: "english",
narration_voice: "female-1",
watermark: false
};
const response = await fetch(`${BASE_URL}/api/v2/videos/generate`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY
},
body: JSON.stringify(payload)
});
console.log(await response.json());Run with: node --env-file=.env display-language.js
Generate Video
POST /api/v2/videos/generateGenerate a video from a prompt or script with customizable voice, visuals, music, and branding.
import fetch from "node-fetch";
const API_KEY = "api-key";
const BASE_URL = "{BASE_URL}";
const payload = {
prompt: "Explain the quarterly roadmap",
background_track: "engaging"
};
const response = await fetch(`${BASE_URL}/api/v2/videos/generate`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY
},
body: JSON.stringify(payload)
});
console.log(await response.json());Run with: node --env-file=.env generate.js
List Videos
GET /api/v2/videosRetrieve videos belonging to the authenticated user. Supports limit and offset query params.
import fetch from "node-fetch";
const BASE_URL = "{BASE_URL}";
// Query params:
// limit — max number of videos to return (optional)
// offset — number of videos to skip (optional, for pagination)
const response = await fetch(`${BASE_URL}/api/v2/videos?limit=10&offset=0`, {
headers: { "x-api-key": "api-key" }
});
const data = await response.json();
console.log(data.videos);
console.log(data.total);Run with: node --env-file=.env list-videos.js
Get Video
GET /api/v2/videos/{video_id}Retrieve metadata for a single video by ID.
const BASE_URL = "{BASE_URL}";
const VIDEO_ID = "video_id";
const response = await fetch(`${BASE_URL}/api/v2/videos/${VIDEO_ID}`, {
headers: { "x-api-key": "api-key" }
});
console.log(await response.json());Run with: node --env-file=.env get-video.js <video_id>
Update Video
PATCH /api/v2/videos/{video_id}Update video metadata. Only 'title' and 'visibility' can be updated.
const BASE_URL = "{BASE_URL}";
const VIDEO_ID = "video_id";
// Only 'title' and 'visibility' are accepted.
const payload = { title: "Updated internal briefing", visibility: "private" };
const response = await fetch(`${BASE_URL}/api/v2/videos/${VIDEO_ID}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
"x-api-key": "api-key"
},
body: JSON.stringify(payload)
});
console.log(await response.json());Run with: node --env-file=.env update-video.js <video_id>
Delete Video
DELETE /api/v2/videos/{video_id}Soft-delete a generated video.
const BASE_URL = "{BASE_URL}";
const VIDEO_ID = "video_id";
const response = await fetch(`${BASE_URL}/api/v2/videos/${VIDEO_ID}`, {
method: "DELETE",
headers: { "x-api-key": "api-key" }
});
console.log(await response.json());Run with: node --env-file=.env delete-video.js <video_id>
Job Status
GET /api/v2/videos/status/{job_id}Poll the status endpoint to track generation progress. Response shape depends on the original /generate request — script_text, podcast_url, or video_url.
const BASE_URL = "{BASE_URL}";
const JOB_ID = "job-id";
const response = await fetch(`${BASE_URL}/api/v2/videos/status/${JOB_ID}`, {
headers: { "x-api-key": "api-key" }
});
const body = await response.json();
console.log(body);
// Three response shapes (depending on original generate request):
// { job_id, status, created_at, script_text } // enable_script_only_mode=true
// { job_id, status, created_at, podcast_url } // enable_podcast_engine=true
// { job_id, status, created_at, video_url } // default (video)Run with: node --env-file=.env job-status.js <job_id>
Style Previews
Short sample videos for every canvas_style_variant and sketch_style_variant. Click any tile to play.
Golpo Canvas
Use with golpo_video_engine: "golpo_canvas".
chalkboard_bwchalkboard_colorwhiteboardmodern_minimaltechnicalsharpieplayfuleditorialillustrationsGolpo Sketch
Use with golpo_video_engine: "golpo_sketch".
classicimproved(beta)formalcrayondry_eraseprofessional_cleancreativeinfographicsTiming
Timing parameter reference — provide duration in minutes as a string, or "auto" to let the system determine the optimal duration.
| Value | Duration |
|---|---|
| "0.25" | 15 seconds |
| "0.5" | 30 seconds |
| "1" | 1 minute |
| "2" | 2 minutes |
| "4" | 4 minutes |
| "8" | 8 minutesBeta |
| "10" | 10 minutesBeta |
| "15" | 15 minutesBeta |
| "auto" | System-determined |
"0.25", "0.5", "1", "2", "4", "8", "10", "15", "auto"."15" is restricted: 15-minute videos are only available on the Enterprise Custom plan. Other plans receive a 403 when requesting 15-minute videos. Contact founders@golpoai.com to upgrade."auto" timing: Use auto timing when the content complexity should determine the video length. Especially useful for problem-solving — pass a math or physics problem via reference_images and the golpo engine will analyze the complexity and generate a script of the appropriate length.Example: Auto Timing with Problem Solving
Pass a problem image via reference_images with Golpo Canvas and let the engine decide how long the explanation should be.
{
"prompt": "Solve and explain this calculus problem step by step",
"reference_images": [
"https://your-bucket.s3.amazonaws.com/calculus-problem.png"
],
"golpo_video_engine": "golpo_canvas",
"canvas_style_variant": "whiteboard",
"timing": "auto",
"narration_voice": "male-1",
"video_orientation": "horizontal"
}Video Orientation
Controls the video aspect ratio and orientation.
| Value | Format | Dimensions | Use Cases |
|---|---|---|---|
| "vertical" | Vertical / Portrait | 1024×1536 px | TikTok, Instagram Reels, YouTube Shorts |
| "horizontal" | Horizontal / Landscape (Default) | 1536×1024 px | YouTube, standard video content |
vertical
1024×1536 px
horizontal (default)
1536×1024 px
Narration Voices
Pick the voice that narrates your video. Pass your choice in the narration_voice parameter — two female voices and two male voices are available, each with its own tone and style.
| Value | Voice Type | Description |
|---|---|---|
| "female-1" | Female 1 | Female narrator voice (Default) |
| "female-2" | Female 2 | Alternative female narrator voice |
| "male-1" | Male 1 | Male narrator voice |
| "male-2" | Male 2 | Alternative male narrator voice |
Background Music
Send the background_track field in your JSON body using one of the following keys.
| background_track key | Mood / Usage |
|---|---|
| "jazz" | Warm, neutral bed |
| "lofi" | Calm, study vibes |
| "dramatic" | Cinematic tension |
| "engaging" | Subtle corporate pulse |
| "hyper" | High-energy electronic |
| "inspirational" | Uplifting orchestral |
| "documentary" | Serious factual tone |
Voice Instructions
Describe how the voice should sound — accent, tone, or pronunciation style.
Pass instructions in the narration_instructions field to guide voice generation. The AI will adjust accent, tone, pace, and delivery accordingly.
{
"prompt": "Explain quantum computing basics",
"narration_instructions": "Speak in a warm British accent with a calm, professorial tone. Pause slightly between key concepts for emphasis.",
"narration_voice": "male-1"
}More examples
Video Instructions
Describe how the video should look — visuals, style, and scene direction.
Pass instructions in the visual_instructions field to guide the visual generation. The AI will adjust scene composition, imagery, and visual style accordingly.
{
"prompt": "Company quarterly results overview",
"visual_instructions": "Use clean corporate visuals with data charts and graphs. Include stock footage of modern office environments. Prefer blue and white color palette.",
"narration_voice": "female-1"
}More examples
Golpo Engine
Pick the video generation pipeline. golpo_canvas is the default; golpo_sketch produces whiteboard-style line-art animations.
| Value | Engine | Description |
|---|---|---|
| "golpo_canvas" | Golpo Canvas (Default) | Canvas-based video with rich style variants. Requires canvas_style_variant. |
| "golpo_sketch" | Golpo Sketch | Whiteboard line-art animation. Requires sketch_style_variant. |
canvas_style_variant to null with golpo_canvas(or sketch_style_variant to null with golpo_sketch) is rejected with HTTP 422.Canvas Style Variant
canvas_style_variant controls the visual style for golpo_video_engine: "golpo_canvas".
| Value | Label | Description |
|---|---|---|
| "chalkboard_bw" | Chalkboard (B/W) | Black & white chalkboard style |
| "chalkboard_color" | Chalkboard Color | Colorful neon chalkboard style (Default) |
| "whiteboard" | Whiteboard | Clean whiteboard illustrations |
| "modern_minimal" | Modern Minimal | Sleek, minimal modern aesthetic |
| "technical" | Technical | Technical diagram style |
| "sharpie" | Sharpie | Bold marker/sharpie drawn style |
| "playful" | Playful | Fun, colorful playful illustrations |
| "editorial" | Editorial | Magazine/editorial illustration style |
| "illustrations" | Illustrations | Vox-style editorial explainer with paper-textured infographic look |
{
"prompt": "How solar panels convert sunlight to electricity",
"golpo_video_engine": "golpo_canvas",
"canvas_style_variant": "modern_minimal",
"pen_animation_style": "stylus",
"scene_pacing": "normal",
"timing": "2"
}Sketch Style Variant
sketch_style_variant controls the look for golpo_video_engine: "golpo_sketch".
| Value | Label | Description |
|---|---|---|
| "classic" | Classic | Original Golpo Sketch — classic whiteboard line-art animation (Default) |
| "improved(beta)" | Improved | Improved line-art with cleaner strokes and a more polished look |
| "formal" | Formal | Advanced sketch generation with higher detail and refined aesthetics |
| "crayon" | Crayon | Storytelling crayon sketch look |
| "dry_erase" | Dry Erase | Whiteboard dry-erase aesthetic |
| "professional_clean" | Professional Clean | Clean, minimal professional sketch |
| "creative" | Creative | After Skool whiteboard-marker variant with bold colorful strokes |
| "infographics" | Infographics | Vox-style editorial explainer with paper-textured infographic look |
"normal" caps frames at 15s; "fast" caps frames at 10s.Pen Animation Style
pen_animation_style adds a drawing cursor effect to the animation. Only supported with the Golpo Canvas engine — setting it with golpo_video_engine: "golpo_sketch" is rejected with 422.
| Value | Description |
|---|---|
| null | No pen cursor (Default) |
| "stylus" | Thin stylus pen cursor |
| "marker" | Thick marker cursor |
| "pen" | Classic pen cursor |
Inserting Images in Script
How to place paired [START][IMAGE N] and [END][IMAGE N] markers inside custom_script so your uploaded custom_images land at the right moment in the narration.
When you supply your own script via custom_script and also upload custom_images, wrap a sentence in paired markers to control where each image appears. [IMAGE 1] refers to the first image in custom_images, [IMAGE 2] to the second, and so on (marker numbers start at 1, not 0). The image displays for the duration of the spoken text between [START][IMAGE N] and [END][IMAGE N].
Follow these rules to make sure your image inserts are never silently skipped:
- Use 1 for your first uploaded image, 2 for the second, and so on.
[IMAGE 1]→ first item incustom_images. If you write[IMAGE 3]but only uploaded 2 images, that image won’t appear. - Every
[START][IMAGE N]needs a matching[END][IMAGE N]with the same number. Missing or mismatched closing tags drop the marker. - Put whitespace around marker tags when they sit next to sentence punctuation. Always leave a space (or newline) between the preceding sentence's period and
[START], and between[END][IMAGE N]and the next sentence. Writestory. [START][IMAGE 2]and[END][IMAGE 1] Next sentence.— neverstory.[START][IMAGE 2]or[END][IMAGE 1]Next sentence.. Without these spaces the sentence splitter cannot find a clean break and the marker is dropped. - Wrap a complete, simple sentence of 8–15 plain words between the markers. Shorter than 5 words is fragile; longer than 20 holds the image on-screen too long.
- Avoid colons (
:), em-dashes (—), semicolons (;), and parentheses inside the marker span. - Keep commas inside the marker to at most one or two. Stacked lists like
"not X, not Y, not Z"confuse the matcher.
Example 1 — Good shape (use as a template):
{
"custom_script": "Travel changes how we see the world. [START][IMAGE 1] This is a quiet beach at sunset with golden waves rolling onto soft sand. [END][IMAGE 1] Coastal trips help us slow down and breathe deeply for a few days. [START][IMAGE 2] This is a mountain village tucked between tall green peaks and clouds. [END][IMAGE 2] Highland trips reward you with cool air and stunning scenic views.",
"custom_images": [
"https://example.com/beach.png",
"https://example.com/mountain.png"
],
"custom_images_description": [
"A quiet beach at sunset",
"A mountain village among green peaks"
]
}Each wrapped sentence is ~10–12 plain words, contains no colons or em-dashes, has a single space after each preceding period, and the marker numbers (1, 2) match the 2-item custom_images array.
You can also use other image control parameters alongside the markers: keep_original_images (boolean array — skip AI processing and place the image untouched) and disable_image_animation (boolean array — render as a static frame instead of an animated drawing).
Example 2 — Common mistakes and their fixes:
// ❌ Mistake A: no space BEFORE [START] — IMAGE 2 won't appear
{
"custom_script": "...each region tells a unique story.[START][IMAGE 2] Rajasthan glows proudly with royal forts and deserts[END][IMAGE 2]."
}
// ✅ Fix A: add a single space between "story." and "[START][IMAGE 2]"
{
"custom_script": "...each region tells a unique story. [START][IMAGE 2] Rajasthan glows proudly with royal forts and deserts[END][IMAGE 2]."
}
// ❌ Mistake B: no space AFTER [END] — IMAGE 1 won't appear
{
"custom_script": "[START][IMAGE 1] A coastal town glows at sunset by the harbor. [END][IMAGE 1]The next morning brings calm waters and a quiet beach."
}
// ✅ Fix B: add a single space between "[END][IMAGE 1]" and "The"
{
"custom_script": "[START][IMAGE 1] A coastal town glows at sunset by the harbor. [END][IMAGE 1] The next morning brings calm waters and a quiet beach."
}Inserting Videos in Script
How to place paired [START][VIDEO N]...[END][VIDEO N] markers inside custom_script so your uploaded custom_videos play for the right span of narration.
When you supply your own script via custom_script and also upload custom_videos, wrap the narration that should play over video N with a paired [START][VIDEO N] ... [END][VIDEO N] block — the same shape used for image markers. [VIDEO 1] refers to the first video in custom_videos, [VIDEO 2] to the second, and so on (marker numbers start at 1, not 0). The narration text between the [START] and [END] markers determines the on-screen duration of the user video — the engine cuts to your clip at the START marker and returns to AI-generated visuals at the END marker.
Follow these rules to make sure your video inserts are never silently skipped:
- Use 1 for your first uploaded video, 2 for the second, and so on.
[VIDEO 1]→ first item incustom_videos. If you write[VIDEO 3]but only uploaded 2 videos, that video won’t appear. - Every video needs a matching
[START]and[END]pair. Use the shape[START][VIDEO N] ... narration ... [END][VIDEO N]. Writing a bare[VIDEO N]without the wrappers causes the engine to start the video but never stop it — it will keep playing over all subsequent narration and block any later[VIDEO N]blocks from rendering. - Spelling and casing must be exact. Use uppercase
VIDEOwith a single space before the number — typos like[VEIDO 1]or[VDIEO 1]are silently dropped. - Always put whitespace around each marker. Write
Welcome. [START][VIDEO 1] Here is the footage. [END][VIDEO 1] Up next.— never glue markers to surrounding words. - Place markers at sentence boundaries, not mid-sentence. Put
[START][VIDEO N]right before the first word of the sentence the video should cover, and[END][VIDEO N]right after the closing punctuation of the last sentence in that block. - Match the narration length to the user video’s original duration. The engine treats the uploaded clip’s natural length as authoritative —
[END][VIDEO N]does not force a hard cut. If the clip is longer than the narration wrapped inside the block, the video keeps playing past[END]and the next narration line is delayed until the clip finishes, producing a visible silent gap. Either pre-trim the clip before uploading, or expand the narration inside the block to cover the clip’s full runtime. - Each
[VIDEO N]appears exactly once. One[START]and one[END]per video — do not reuse the same N later in the script. - Do not nest video blocks.
[START][VIDEO 1] ... [START][VIDEO 2] ... [END][VIDEO 1] [END][VIDEO 2]is invalid; each block must fully close before the next one opens.
[START][VIDEO N] and [END][VIDEO N]. If the clip is longer than the wrapped narration, the video keeps playing past [END] silently, and the next narration line is held back until the clip ends. To avoid this silent gap, either trim the clip to roughly the spoken duration of the wrapped sentences before uploading, or write enough narration inside the block to cover the clip’s full runtime.Example — Good shape (use as a template):
{
"custom_script": "Welcome to today's nature tour. [START][VIDEO 1] Here is a stunning view of the mountain ridge captured from the air. [END][VIDEO 1] Now let us head down to the coast. [START][VIDEO 2] These calming waves close out our journey. [END][VIDEO 2] Thanks for watching.",
"custom_videos": [
"https://example.com/mountain-clip.mp4",
"https://example.com/coastal-clip.mp4"
],
"custom_videos_description": [
"Aerial view of a mountain ridge",
"Coastal waves rolling onto a beach"
]
}Each [VIDEO N] appears twice — once with [START] at the beginning of its sentence and once with [END] at the end. Video 1 plays only over “Here is a stunning view… from the air.”, then the engine returns to AI-generated visuals for “Now let us head down to the coast.”, then video 2 plays only over “These calming waves close out our journey.” Marker numbers (1, 2) match the 2-item custom_videos array. To control whether the video plays with its original audio or AI narration, see use_ai_audio_at.
Language Support
44+ languages supported via the narration_language and onscreen_text_language parameters.
| Language | Accepted values | Note |
|---|---|---|
| English | english or en | Default when omitted |
| Hindi | hindi or hi | — |
| Spanish | spanish or es | — |
| French | french or fr | — |
| German | german or de | — |
| Italian | italian or it | — |
| Portuguese | portuguese or pt | — |
| Russian | russian or ru | — |
| Japanese | japanese or ja | — |
| Korean | korean or ko | — |
| Chinese / Mandarin | chinese, mandarin, or zh | Both map to zh |
| Arabic | arabic or ar | — |
| Dutch | dutch or nl | — |
| Polish | polish or pl | — |
| Turkish | turkish or tr | — |
| Swedish | swedish or sv | — |
| Danish | danish or da | — |
| Norwegian | norwegian or no | — |
| Finnish | finnish or fi | — |
| Greek | greek or el | — |
| Czech | czech or cs | — |
| Hungarian | hungarian or hu | — |
| Romanian | romanian or ro | — |
| Thai | thai or th | — |
| Vietnamese | vietnamese or vi | — |
| Indonesian | indonesian or id | — |
| Malay | malay or ms | — |
| Tamil | tamil or ta | — |
| Telugu | telugu or te | — |
| Bengali | bengali or bn | — |
| Marathi | marathi or mr | — |
| Gujarati | gujarati or gu | — |
| Kannada | kannada or kn | — |
| Malayalam | malayalam or ml | — |
| Punjabi | punjabi or pa | — |
| Urdu | urdu or ur | — |
HTTP Status Codes
Standard HTTP codes returned by all endpoints.
| Code | Meaning | Recovery |
|---|---|---|
| 200 | Successful request (GET, POST, PATCH, or DELETE) | Consume response payload |
| 400 | Bad request (invalid fields or file types) | Check request body and field values |
| 401 | Missing or invalid authentication | Verify the x-api-key header is set and valid |
| 403 | Plan does not allow requested action | Upgrade plan or contact support |
| 404 | Video / job not found | Verify identifiers belong to the account |
| 413 | Uploaded file exceeds 15 MB | Compress or split the file before retrying |
| 422 | Validation failure (bad payload) | Inspect detail field in response |
| 429 | Rate limit exceeded | Back off and retry with exponential delay |
| 500 | Unexpected server error | Retry later; contact support if persistent |
Error Response Format
All 4xx and 5xx responses return a JSON body with a detail field.
String detail
Most errors return detail as a single human-readable string describing what went wrong. Surface it directly in your UI or logs.
{
"detail": "'canvas_style_variant' is required when using 'golpo_canvas' engine."
}Array detail
When the request body fails validation, detail is an array of error objects — one per failing field. Each object includes the failing field path (loc) and a human-readable message (msg).
{
"detail": [
{
"type": "value_error",
"loc": ["body"],
"msg": "Value error, 'custom_videos_description' is required when 'custom_videos' is provided. Provide one description per video (2 expected)."
}
]
}API Only Tier
Usage-based pricing with volume discounts
About this plan
This plan is for using Golpo within your program or application. You will not be able to use the Golpo platform to generate videos manually.
This is a usage-based plan with a minimum cost of $200 to enter. Perfect for developers and businesses who need programmatic access to video generation.
Pay only for what you use — volume-based pricing that gets better as you scale.
Platform access (manual video creation via the dashboard) is not included in this plan. If you need both platform + API access, please consider buying an enterprise plan or business plan with an API add-on.
Pricing Rates
Credit Conversion
$1
USD
1 Credit
Golpo credit
| Resource | Cost |
|---|---|
| 1 min videoVideo generation | 2 Credits= $2.00 |
Volume discounts apply at higher usage tiers. Contact us for enterprise rates. | |
Minimum entry: $200 (200 credits = ~100 minutes of video)