One Click Videos · Developers
JavaScript and TypeScript
Create and poll a video using server-side fetch. No third-party package is required.
Before running
Use Node.js 22 or later, set JEMSU_API_KEY securely and run node create-video.mjs. Do not include this code in a client-side bundle. The first POST uses account credits.
// Server-side Node.js 22+. Save as create-video.mjs.
import { writeFile } from "node:fs/promises";
const key = process.env.JEMSU_API_KEY;
if (!key) throw new Error("Set JEMSU_API_KEY in your server environment.");
const base = "https://app.jemsu.ai/api/v1";
const headers = { Authorization: `Bearer ${key}`, "Content-Type": "application/json" };
const brief = {
video_idea: "A paper boat drifts across a sunlit pond. Calm, cinematic, no dialogue.",
video_length_sec: 10, speech: "no", music: "no", aspectratio: "9:16"
};
const res = await fetch(`${base}/videos`, {
method: "POST", headers, body: JSON.stringify(brief), signal: AbortSignal.timeout(120000)
});
const created = await res.json();
if (!res.ok || !created.jobId) throw new Error(JSON.stringify(created));
// Persist before polling. A new POST creates a new billable video.
await writeFile("jemsu-job.json", JSON.stringify(created, null, 2));
console.log("Job:", created.jobId, "Reserved credits:", created.creditsReserved);
for (let attempt = 0; attempt < 60; attempt++) {
await new Promise(resolve => setTimeout(resolve, 15000));
const status = await fetch(`${base}/videos/${encodeURIComponent(created.jobId)}`, {
headers, signal: AbortSignal.timeout(30000)
});
if (status.status === 429 || status.status >= 500) continue;
const job = await status.json();
if (!status.ok) throw new Error(JSON.stringify(job));
if (job.status === "failed") throw new Error(JSON.stringify(job.error));
if (job.status === "completed") {
if (!job.videoUrl) throw new Error("Completed without a result URL; contact support with the job ID.");
console.log("Video:", job.videoUrl);
process.exit(0);
}
}
throw new Error("Polling limit reached. Resume GET status using jemsu-job.json; do not submit another POST.");
Resume after interruption
Read jemsu-job.json and call GET /videos/{jobId}. Do not rerun the entire script unless you intend to create another video. A fetch timeout stops local waiting; it does not cancel a server job.
Using TypeScript
The request body is a JSON object; generate typed models from the OpenAPI contract if useful. Keep runtime response and error checks even when using generated types.