2026-11-02 · 4 min read

Captions for LinkedIn Video with an API

LinkedIn is one of the few major feeds where video still autoplays without sound by default, so a talking head clip with no captions can lose its message in the first seconds. If your clips already exist, burning captions in before upload is a small change that can make the difference between a scroll past and a watch.

This walkthrough submits a finished clip to the caption.sh API and polls until the captioned render is ready. It assumes you already have a video file hosted somewhere reachable, such as an S3 URL or your own CDN.

Submit the clip

One POST starts the render. Pass the video URL and any style options. The response is a job id, not the video, because rendering is asynchronous.

const API = "https://api.caption.sh/v1";
const headers = {
  Authorization: `Bearer ${process.env.CAPTION_API_KEY}`,
  "Content-Type": "application/json",
};

async function captionClip(sourceUrl) {
  const res = await fetch(`${API}/videos`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      source_url: sourceUrl,
      options: { font: "inter" },
    }),
  });
  if (res.status === 402) throw new Error("out of credits");
  if (!res.ok) throw new Error(`submit failed: ${res.status}`);
  const { job_id } = await res.json();

  for (let i = 0; i < 120; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const job = await (
      await fetch(`${API}/jobs/${job_id}`, { headers })
    ).json();
    if (job.status === "error") throw new Error("render failed");
    if (job.status === "done") return job_id;
  }
  throw new Error("render timed out");
}

What to know before you batch

  • Submissions are rate limited per API key. A 429 response means wait a moment and retry, it does not mean the job failed.
  • Rendering is prepaid at $0.10 per minute of video. A 402 response means the balance is empty, so top up before retrying.
  • Every render needs a bounded poll loop with three exits: done, error, and your own timeout. Do not poll forever.
  • The API documents no webhook surface, so polling is the intended way to learn a job finished.

Once the job status is done, download the rendered mp4 and upload it to LinkedIn natively. Native uploads keep the burned captions intact because they are part of the video frames, not a separate track the platform could drop.

Back to all articles