Back to How to
How to

How to Handle Completed and Failed Video Jobs With Webhooks

Set up a signed ngram webhook receiver, verify the raw request, route video.completed and video.failed separately, and deduplicate retries without losing a new edit.

How to Handle Completed and Failed Video Jobs With Webhooks
3 min read•Updated at November 2, 2026
Written and edited by
Rishikesh Ranjan
Rishikesh Ranjan
all thing growth @ ngram.com

A create request returns HTTP 202. Your application knows the job exists, but it still cannot tell a customer that their file is ready. Let the job finish asynchronously. Give the receiver a durable record of the original request, the expected account and the destination.

Choose how the event reaches you

For one job, include webhook_url and webhook_secret in the create request. For all matching jobs on one ngram account, POST to /api/v1/webhooks/subscriptions with event_type and target_url. Register separate subscriptions for video.completed and video.failed. Save each subscription’s secret at creation; it is not returned on a later read. Use a public HTTPS receiver for production.

POST /api/v1/webhooks/subscriptions
Authorization: Bearer <server-side API key>
Content-Type: application/json

{
  "event_type": "video.completed",
  "target_url": "https://events.example.com/ngram/completed"
}

Create the failure subscription with event_type set to video.failed. A separate receiver path for each subscription makes it straightforward to select the matching signing secret before reading the body.

Start from the API getting-started guide to authenticate and check account access. Key creation is self-service. Creating a video with an API key requires Basic or a higher paid plan and sufficient credits.

Verify the signature before parsing the JSON

Keep the exact bytes delivered to the endpoint. Read X-Ngram-Timestamp and X-Ngram-Signature. Using the secret assigned to this callback or subscription, compute HMAC-SHA256 over the timestamp, a period and the raw bytes. Reject invalid signatures and timestamps more than five minutes from the server clock. The helper below assumes a Node request handler has already captured the raw body as a Buffer.

import { createHmac, timingSafeEqual } from "node:crypto";

function validWebhook(rawBody, headers, secret) {
  const timestamp = headers["x-ngram-timestamp"];
  const signature = headers["x-ngram-signature"];
  if (typeof timestamp !== "string" || !/^\d+$/.test(timestamp)) return false;
  if (typeof signature !== "string" || !/^sha256=[0-9a-f]{64}$/.test(signature)) return false;
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const expected = createHmac("sha256", secret)
    .update(timestamp + ".").update(rawBody).digest();
  const received = Buffer.from(signature.slice(7), "hex");
  return timingSafeEqual(expected, received);
}

Only after verification should the handler parse event, video_id and any version_id. Resolve the destination from your own job-to-record mapping, not from a free-form URL supplied by a customer. The webhook integration describes callback and subscription scopes.

Route a completed result to the correct record

In the completed example, video_id is vid_release_brief and the receiver gets a version_id, a result URL and duration_ms of 13200. An endpoint returning 204 has acknowledged receipt. Record delivery to the customer only after your application has checked the intended destination.

A preview-only job can complete without result.url. Its job-specific callback receives the event; account-wide subscriptions do not receive that preview completion. Read live_preview on GET /api/v1/videos/{id}, or export the approved version if the recipient needs an MP4.

Send failure to the owner, not the customer’s file slot

The failure example has video_id vid_source_review, error_code generation_failed and the message “Could not finish the video.” Keep the failure and its job ID with the source record. Notify the operator who can inspect the cause. Do not create a file placeholder that looks like a successful video.

Acknowledge durable receipt and make retries safe

Persist the event or enqueue it durably, with a unique processing key, before answering 2xx. Keep that acknowledgement within ten seconds. A timeout or non-2xx response can lead to retries after 1, 2, 5, 15 and 30 minutes, for up to six attempts in total. HTTP 410 tells a persistent subscription that the receiver is gone and removes the subscription.

For a versioned completion, key the delivery on video_id and version_id. The same pair should not notify twice. A new edit can complete under the same video_id with a new version_id; process it as a new delivery when appropriate. Use a separate failure key and read current status when an older completion has no version_id. The public API integration covers the job and export reads you can use to reconcile a result.

Related articles

How to Use ChatGPT to Plan a Product Demo and Create Its Explainer
How to8 min read

How to Use ChatGPT to Plan a Product Demo and Create Its Explainer

Use ChatGPT and ngram to explain a product concept on video. Review a real RAG example, check the quoted settings and choose when a demo needs actual screen footage.

ngramHow To
Rishikesh Ranjan
Rishikesh Ranjan
Growth Lead
Nov 2, 2026
How to Explain a Code Change to Customers Without Showing the Diff
How to3 min read

How to Explain a Code Change to Customers Without Showing the Diff

Translate a pull request into a customer-facing explanation. Use the shipped action, a visible before-and-after result and a written availability check instead of exposing the diff.

How Tongram
Rishikesh Ranjan
Rishikesh Ranjan
Growth Lead
Nov 2, 2026
How to Brief a Teammate Who Picks Up a Complex Ticket Mid-Sprint
How to3 min read

How to Brief a Teammate Who Picks Up a Complex Ticket Mid-Sprint

Prepare a mid-sprint ticket handoff that separates the problem, confirmed evidence, open questions and first reproducible check. Use a short video only for something the next owner needs to see.

How Tongram
Rishikesh Ranjan
Rishikesh Ranjan
Growth Lead
Nov 2, 2026
How to Deliver a Customer’s Video as Soon as It’s Ready
How to3 min read

How to Deliver a Customer’s Video as Soon as It’s Ready

Design an asynchronous video handoff that matches a finished job to the intended customer, checks the correct version and avoids duplicate notifications.

How Tongram
Rishikesh Ranjan
Rishikesh Ranjan
Growth Lead
Nov 2, 2026
How to Preview and Export a Video With the ngram MCP Server
How to3 min read

How to Preview and Export a Video With the ngram MCP Server

Create a video with the full ngram MCP profile, review its live preview, request a change and explicitly export the current version when you need an MP4.

How Tongram
Rishikesh Ranjan
Rishikesh Ranjan
Growth Lead
Nov 2, 2026
Should You Post Your Video as a Reply on X or Start a New Thread?
How to3 min read

Should You Post Your Video as a Reply on X or Start a New Thread?

Decide whether a video belongs in an existing X conversation or in a new post from your account. Compare a real explainer reply with a standalone announcement brief.

How Tongram
Rishikesh Ranjan
Rishikesh Ranjan
Growth Lead
Nov 2, 2026

Ready to create your first video?

Turn your source material into a video. Shape the brief, review the plan and make it yours.