Use CasesCaption/Reframe Video

Edit Video

This page explains how to use the Klap API to apply AI-powered edits to a video. You can add dynamic captions, reframe the content, add emojis and more, without extracting multiple clips.

Overview

Klap’s AI can enhance existing short videos by adding captions, reframing the content, and applying other visual improvements. This is ideal when you already have a well-cut video that just needs enhancements.

API Flow

1. Submit a Video for Editing

First, submit your video to be edited.

Endpoint Used: POST /tasks/video-to-video

const task = await postRequest("/tasks/video-to-video", {
  source_video_url: "https://example.com/video.mp4",
  language: "en",
  editing_options: {
    captions: true,
    reframe: true,
    emojis: true,
    intro_title: false
  },
  dimensions: {
    width: 1080,
    height: 1920
  }
});
 
console.log(`Task created: ${task.id}`);

This returns a Task object with the ID of your processing job. Your video will be analyzed and the specified edits will be applied.

2. Poll the Task Status

You’ll need to periodically check the status of your processing task until it completes.

Endpoint Used: GET /tasks/{task_id}

// Poll every 30 seconds until the task is complete
let currentTask;
do {
  currentTask = await getRequest(`/tasks/${task.id}`);
  console.log(`Task status: ${currentTask.status}`);
  
  if (currentTask.status === "processing") {
    await new Promise(resolve => setTimeout(resolve, 30000));
  }
} while (currentTask.status === "processing");
 
if (currentTask.status === "error") {
  throw new Error("Task processing failed");
}
 
// Once complete, get the project ID of the edited video
const projectID = currentTask.output_id;

When the task is complete and successful, it will give you an output_id representing the project ID of your edited video.

3. Preview the Edited Video (Optional)

You can preview the edited video before exporting it.

const previewUrl = `https://klap.app/player/${projectID}`;

This URL can be used to preview the edited video or embed it in your application.

4. Export the Edited Video

When you’re ready to export the final video, create an export task.

Endpoint Used: POST /projects/{project_id}/exports

const exportTask = await postRequest(
  `/projects/${projectID}/exports`,
  {
    watermark: {
      src_url: "https://example.com/logo.png",
      pos_x: 0.5,
      pos_y: 0.5,
      scale: 1
    }
  }
);
 
console.log(`Export started: ${exportTask.id}`);

This returns an Export object with details about your export job.

5. Poll the Export Status

Like with the initial processing, you need to poll until the export is complete.

Endpoint Used: GET /projects/{project_id}/exports/{export_id}

// Poll until export is complete
let currentExport;
do {
  currentExport = await getRequest(
    `/projects/${projectID}/exports/${exportTask.id}`
  );
  console.log(`Export status: ${currentExport.status}`);
  
  if (currentExport.status === "processing") {
    await new Promise(resolve => setTimeout(resolve, 15000));
  }
} while (currentExport.status === "processing");
 
if (currentExport.status === "error") {
  throw new Error("Export failed");
}

6. Access the Exported Video

When the export is complete, you’ll have a URL to the final video.

const videoUrl = currentExport.src_url;
console.log(`Export complete: ${videoUrl}`);

Complete Example

Here’s a full example of the process:

const API_URL = "https://api.klap.video/v2";
const API_KEY = "<your-api-key>";
const INPUT_VIDEO_URL = "<your-video-url>";
 
const postRequest = async (url, body = {}) => {
  const response = await fetch(`${API_URL}${url}`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${API_KEY}`,
    },
    body: JSON.stringify(body),
  });
 
  return response.ok ? response.json() : Promise.reject(await response.json());
};
 
const getRequest = async (url) => {
  const response = await fetch(`${API_URL}${url}`, {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });
  return response.json();
};
 
const pollStatus = async (url, checkKey, checkValue) => {
  let resJson;
 
  do {
    resJson = await getRequest(url);
    console.log(
      `[${new Date().toLocaleTimeString()}] Polling ${url} while ${checkKey} === ${checkValue}...`
    );
    await new Promise((r) => setTimeout(r, 30000));
  } while (resJson[checkKey] === checkValue);
  return resJson;
};
 
const editVideo = async (inputVideoUrl) => {
  // Step 1: Create the editing task
  let task = await postRequest("/tasks/video-to-video", {
    source_video_url: inputVideoUrl,
    language: "en",
    editing_options: {
      captions: true,
      reframe: true,
      emojis: true,
      intro_title: false
    },
    dimensions: {
      width: 1080,
      height: 1920
    }
  });
 
  console.log(`Task created: ${task.id}. Processing...`);
  
  // Step 2: Poll the task until it's complete
  task = await pollStatus(`/tasks/${task.id}`, "status", "processing");
  console.log(`Task processing done: ${task.id}.`);
  
  if (task.status === "error") {
    throw new Error("Task processing failed");
  }
 
  const projectId = task.output_id;
  console.log(`Edited video project ID: ${projectId}`);
  
  // Step 3: Export the video
  console.log(`Exporting project: ${projectId}...`);
  let exportRes = await postRequest(
    `/projects/${projectId}/exports`,
    {
      watermark: {
        src_url: "https://example.com/logo.png",
        pos_x: 0.5,
        pos_y: 0.5,
        scale: 1
      }
    }
  );
  console.log(`Export started: ${exportRes.id}.`);
  
  // Step 4: Poll the export until it's complete
  exportRes = await pollStatus(
    `/projects/${projectId}/exports/${exportRes.id}`,
    "status",
    "processing"
  );
  
  if (exportRes.status === "error") {
    throw new Error("Export failed");
  }
  
  return exportRes;
};
 
const main = async () => {
  try {
    const exportResult = await editVideo(INPUT_VIDEO_URL);
    console.log(`Export done: ${exportResult.src_url}`);
  } catch (error) {
    console.error("Error:", error.message);
  }
};
 
main();