CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-mux--mux-node

Official TypeScript library providing comprehensive client access to Mux's video infrastructure API including asset management, live streaming, analytics, and webhook handling

Overview
Eval results
Files

webhooks.mddocs/

Webhooks

Webhook signature verification and event parsing for secure handling of Mux platform events including video processing, live streaming, and system notifications.

Imports

import { Mux } from "@mux/mux-node";

// For webhook handling
const mux = new Mux({
  webhookSecret: process.env.MUX_WEBHOOK_SECRET
});

// Access webhook utilities
const webhooks = mux.webhooks;

Capabilities

Webhook Verification and Parsing

Verify webhook signatures and parse webhook events with automatic type detection and validation.

/**
 * Verify webhook signature and parse event payload
 * @param body - Raw webhook request body (string)
 * @param headers - HTTP headers from webhook request
 * @param secret - Webhook signing secret (optional, uses client config if not provided)
 * @returns Parsed and verified webhook event
 * @throws Error if signature verification fails
 */
unwrap(body: string, headers: HeadersLike, secret?: string): UnwrapWebhookEvent;

/**
 * Verify webhook signature without parsing event
 * @param body - Raw webhook request body (string)
 * @param headers - HTTP headers from webhook request
 * @param secret - Webhook signing secret (optional, uses client config if not provided)
 * @throws Error if signature verification fails
 */
verifySignature(body: string, headers: HeadersLike, secret?: string): void;

interface HeadersProtocol {
  get: (header: string) => string | null | undefined;
}

type HeadersLike = Record<string, string | string[] | undefined> | HeadersProtocol;

Usage Examples:

import express from 'express';

const app = express();

// Webhook endpoint with raw body parsing
app.post('/webhooks/mux', express.raw({ type: 'application/json' }), (req, res) => {
  try {
    // Verify and parse webhook event
    const event = mux.webhooks.unwrap(
      req.body.toString(),
      req.headers,
      process.env.MUX_WEBHOOK_SECRET
    );

    // Handle different event types
    switch (event.type) {
      case 'video.asset.ready':
        console.log('Asset ready:', event.data.id);
        break;
      case 'video.live_stream.active':
        console.log('Live stream active:', event.data.id);
        break;
      default:
        console.log('Unknown event type:', event.type);
    }

    res.status(200).send('OK');
  } catch (error) {
    console.error('Webhook verification failed:', error);
    res.status(400).send('Invalid signature');
  }
});

// Signature verification only
app.post('/webhooks/verify-only', express.raw({ type: 'application/json' }), (req, res) => {
  try {
    mux.webhooks.verifySignature(req.body.toString(), req.headers);

    // Signature is valid, process the raw body as needed
    const eventData = JSON.parse(req.body.toString());
    console.log('Valid webhook received:', eventData.type);

    res.status(200).send('OK');
  } catch (error) {
    res.status(400).send('Invalid signature');
  }
});

Webhook Event Types

Video Asset Events

Events related to video asset processing and lifecycle.

interface VideoAssetCreatedWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.created';
  data: Asset;
}

interface VideoAssetReadyWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.ready';
  data: Asset;
}

interface VideoAssetErroredWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.errored';
  data: Asset;
}

interface VideoAssetUpdatedWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.updated';
  data: Asset;
}

interface VideoAssetDeletedWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.deleted';
  data: Asset;
}

interface VideoAssetWarningWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.warning';
  data: Asset & {
    /** Warning message */
    warning?: string;
  };
}

interface VideoAssetNonStandardInputDetectedWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.non_standard_input_detected';
  data: Asset;
}

interface VideoAssetLiveStreamCompletedWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.live_stream_completed';
  data: Asset;
}

interface VideoAssetStaticRenditionsReadyWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.static_renditions.ready';
  data: Asset;
}

interface VideoAssetStaticRenditionsPreparingWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.static_renditions.preparing';
  data: Asset;
}

interface VideoAssetStaticRenditionsDeletedWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.static_renditions.deleted';
  data: Asset;
}

interface VideoAssetStaticRenditionsErroredWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.static_renditions.errored';
  data: Asset;
}

interface VideoAssetMasterReadyWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.master.ready';
  data: Asset;
}

interface VideoAssetMasterPreparingWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.master.preparing';
  data: Asset;
}

interface VideoAssetMasterErroredWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.master.errored';
  data: Asset;
}

interface VideoAssetMasterDeletedWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.master.deleted';
  data: Asset;
}

Live Stream Events

Events related to live streaming operations and status changes.

interface VideoLiveStreamCreatedWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.created';
  data: LiveStream;
}

interface VideoLiveStreamConnectedWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.connected';
  data: LiveStream;
}

interface VideoLiveStreamActiveWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.active';
  data: LiveStream;
}

interface VideoLiveStreamIdleWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.idle';
  data: LiveStream;
}

interface VideoLiveStreamDisconnectedWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.disconnected';
  data: LiveStream;
}

interface VideoLiveStreamUpdatedWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.updated';
  data: LiveStream;
}

interface VideoLiveStreamEnabledWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.enabled';
  data: LiveStream;
}

interface VideoLiveStreamDisabledWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.disabled';
  data: LiveStream;
}

interface VideoLiveStreamDeletedWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.deleted';
  data: LiveStream;
}

interface VideoLiveStreamWarningWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.warning';
  data: LiveStream & {
    /** Warning message */
    warning?: string;
  };
}

interface VideoLiveStreamRecordingWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.recording';
  data: LiveStream & { recording_start_time?: string };
}

Upload Events

Events related to direct upload operations and status.

interface VideoUploadCreatedWebhookEvent extends BaseWebhookEvent {
  type: 'video.upload.created';
  data: Upload;
}

interface VideoUploadCancelledWebhookEvent extends BaseWebhookEvent {
  type: 'video.upload.cancelled';
  data: Upload;
}

interface VideoUploadErroredWebhookEvent extends BaseWebhookEvent {
  type: 'video.upload.errored';
  data: Upload;
}

interface VideoUploadAssetCreatedWebhookEvent extends BaseWebhookEvent {
  type: 'video.upload.asset_created';
  data: Upload;
}

Static Rendition Events

Events for MP4 rendition generation and processing.

interface VideoAssetStaticRenditionCreatedWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.static_rendition.created';
  data: StaticRendition;
}

interface VideoAssetStaticRenditionReadyWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.static_rendition.ready';
  data: StaticRendition;
}

interface VideoAssetStaticRenditionErroredWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.static_rendition.errored';
  data: StaticRendition;
}

interface VideoAssetStaticRenditionDeletedWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.static_rendition.deleted';
  data: StaticRendition;
}

interface VideoAssetStaticRenditionSkippedWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.static_rendition.skipped';
  data: StaticRendition;
}

Track Events

Events for subtitle and audio track operations.

interface VideoAssetTrackCreatedWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.track.created';
  data: Track;
}

interface VideoAssetTrackReadyWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.track.ready';
  data: Track;
}

interface VideoAssetTrackErroredWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.track.errored';
  data: Track;
}

interface VideoAssetTrackDeletedWebhookEvent extends BaseWebhookEvent {
  type: 'video.asset.track.deleted';
  data: Track;
}

Simulcast Events

Events for simulcast target operations during live streaming.

interface VideoLiveStreamSimulcastTargetCreatedWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.simulcast_target.created';
  data: SimulcastTarget;
}

interface VideoLiveStreamSimulcastTargetIdleWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.simulcast_target.idle';
  data: SimulcastTarget;
}

interface VideoLiveStreamSimulcastTargetStartingWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.simulcast_target.starting';
  data: SimulcastTarget;
}

interface VideoLiveStreamSimulcastTargetBroadcastingWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.simulcast_target.broadcasting';
  data: SimulcastTarget;
}

interface VideoLiveStreamSimulcastTargetErroredWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.simulcast_target.errored';
  data: SimulcastTarget;
}

interface VideoLiveStreamSimulcastTargetDeletedWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.simulcast_target.deleted';
  data: SimulcastTarget;
}

interface VideoLiveStreamSimulcastTargetUpdatedWebhookEvent extends BaseWebhookEvent {
  type: 'video.live_stream.simulcast_target.updated';
  data: SimulcastTarget;
}

System Events

Events for system-level notifications and delivery monitoring.

interface VideoDeliveryHighTrafficWebhookEvent extends BaseWebhookEvent {
  type: 'video.delivery.high_traffic';
  data: {
    /** Unique identifier for the delivery report */
    id?: string;
    /** Array of asset delivery data */
    data?: Array<AssetDeliveryData>;
    /** Current threshold set for alerting */
    threshold?: number;
    /** Time range for the report as [start, end] timestamps */
    timeframe?: Array<number>;
  };
}

interface AssetDeliveryData {
  /** The duration of the asset in seconds */
  asset_duration: number;
  /** @deprecated Use asset_video_quality instead. The encoding tier that the asset was ingested at */
  asset_encoding_tier: 'smart' | 'baseline' | 'premium';
  /** Unique identifier for the asset */
  asset_id: string;
  /** The resolution tier that the asset was ingested at */
  asset_resolution_tier: 'audio-only' | '720p' | '1080p' | '1440p' | '2160p';
  /** The state of the asset */
  asset_state: 'ready' | 'errored' | 'deleted';
  /** Time at which the asset was created. Measured in seconds since the Unix epoch */
  created_at: number;
  /** Total number of delivered seconds during this time window */
  delivered_seconds: number;
  /** Seconds delivered broken into resolution tiers */
  delivered_seconds_by_resolution: DeliveredSecondsByResolution;
  /** The video quality that the asset was ingested at (replaces asset_encoding_tier) */
  asset_video_quality?: 'basic' | 'plus' | 'premium';
  /** If exists, time at which the asset was deleted. Measured in seconds since the Unix epoch */
  deleted_at?: number;
  /** Unique identifier for the live stream that created the asset */
  live_stream_id?: string;
  /** The passthrough value for the asset */
  passthrough?: string;
}

interface DeliveredSecondsByResolution {
  /** Delivered seconds within the 720p tier (up to 921,600 pixels total) */
  tier_720p?: number;
  /** Delivered seconds in 1080p tier (over 921,600 and <= 2,073,600 pixels) */
  tier_1080p?: number;
  /** Delivered seconds in 1440p tier (over 2,073,600 and <= 4,194,304 pixels) */
  tier_1440p?: number;
  /** Delivered seconds in 2160p tier (over 4,194,304 pixels) */
  tier_2160p?: number;
  /** Delivered seconds of audio only content */
  tier_audio_only?: number;
}

Base Event Structure

All webhook events extend the base webhook event interface:

interface BaseWebhookEvent {
  /** Unique identifier for the event */
  id: string;
  /** Event type identifier */
  type: string;
  /** Event creation timestamp */
  created_at: string;
  /** Event data payload */
  data: unknown;
  /** Attempts for sending out the webhook event */
  attempts: Array<WebhookAttempt>;
  /** Environment information */
  environment: WebhookEnvironment;
  /** Object metadata */
  object: BaseWebhookEvent.Object;
  /** @deprecated Request ID that triggered the event */
  request_id?: string | null;
  /** @deprecated Accessor information */
  accessor?: string | null;
  /** @deprecated Accessor source */
  accessor_source?: string | null;
}

namespace BaseWebhookEvent {
  interface Object {
    /** Object identifier */
    id: string;
    /** Object type */
    type: string;
  }
}

interface WebhookAttempt {
  /** Unique identifier for the webhook attempt */
  id?: string;
  /** URL address for the webhook attempt */
  address?: string;
  /** Unique identifier for the webhook */
  webhook_id?: number;
  /** Timestamp of the attempt */
  created_at?: string;
  /** Max attempts allowed */
  max_attempts?: number;
  /** HTTP response status code for the webhook attempt */
  response_status_code?: number;
  /** HTTP response headers for the webhook attempt */
  response_headers?: unknown;
  /** HTTP response body for the webhook attempt */
  response_body?: string | null;
}

interface WebhookEnvironment {
  /** Environment name: 'production' | 'development' */
  name: string;
  /** Environment identifier */
  id: string;
}

/** Core data types referenced in webhook events */
interface Asset {
  id: string;
  status: 'preparing' | 'ready' | 'errored';
  duration?: number;
  aspect_ratio?: string;
  created_at: string;
  playback_ids?: PlaybackID[];
  mp4_support?: string;
  master_access?: string;
  test?: boolean;
}

interface LiveStream {
  id: string;
  status: 'active' | 'idle';
  created_at: string;
  stream_key: string;
  playback_ids?: PlaybackID[];
  reconnect_window?: number;
  max_continuous_duration?: number;
  test?: boolean;
}

interface Upload {
  id: string;
  url: string;
  status: 'waiting' | 'asset_created' | 'errored' | 'cancelled';
  new_asset_settings?: Record<string, any>;
  asset_id?: string;
  error?: {
    type: string;
    message: string;
  };
  cors_origin?: string;
  test?: boolean;
}

interface StaticRendition {
  name: string;
  ext: string;
  height: number;
  width: number;
  bitrate: number;
  filesize?: number;
}

interface Track {
  id: string;
  type: 'video' | 'audio' | 'text';
  duration?: number;
  max_width?: number;
  max_height?: number;
  max_frame_rate?: number;
  text_type?: 'subtitles' | 'captions';
  language_code?: string;
  name?: string;
  closed_captions?: boolean;
  passthrough?: string;
}

interface SimulcastTarget {
  id: string;
  passthrough?: string;
  status?: string;
  stream_key?: string;
  url?: string;
}

type UnwrapWebhookEvent =
  | VideoAssetCreatedWebhookEvent
  | VideoAssetReadyWebhookEvent
  | VideoAssetErroredWebhookEvent
  | VideoAssetUpdatedWebhookEvent
  | VideoAssetDeletedWebhookEvent
  | VideoAssetLiveStreamCompletedWebhookEvent
  | VideoAssetStaticRenditionsReadyWebhookEvent
  | VideoAssetStaticRenditionsPreparingWebhookEvent
  | VideoAssetStaticRenditionsDeletedWebhookEvent
  | VideoAssetStaticRenditionsErroredWebhookEvent
  | VideoAssetMasterReadyWebhookEvent
  | VideoAssetMasterPreparingWebhookEvent
  | VideoAssetMasterDeletedWebhookEvent
  | VideoAssetMasterErroredWebhookEvent
  | VideoAssetTrackCreatedWebhookEvent
  | VideoAssetTrackReadyWebhookEvent
  | VideoAssetTrackErroredWebhookEvent
  | VideoAssetTrackDeletedWebhookEvent
  | VideoAssetStaticRenditionCreatedWebhookEvent
  | VideoAssetStaticRenditionReadyWebhookEvent
  | VideoAssetStaticRenditionErroredWebhookEvent
  | VideoAssetStaticRenditionDeletedWebhookEvent
  | VideoAssetStaticRenditionSkippedWebhookEvent
  | VideoAssetWarningWebhookEvent
  | VideoAssetNonStandardInputDetectedWebhookEvent
  | VideoUploadAssetCreatedWebhookEvent
  | VideoUploadCancelledWebhookEvent
  | VideoUploadCreatedWebhookEvent
  | VideoUploadErroredWebhookEvent
  | VideoLiveStreamCreatedWebhookEvent
  | VideoLiveStreamConnectedWebhookEvent
  | VideoLiveStreamRecordingWebhookEvent
  | VideoLiveStreamActiveWebhookEvent
  | VideoLiveStreamDisconnectedWebhookEvent
  | VideoLiveStreamIdleWebhookEvent
  | VideoLiveStreamUpdatedWebhookEvent
  | VideoLiveStreamEnabledWebhookEvent
  | VideoLiveStreamDisabledWebhookEvent
  | VideoLiveStreamDeletedWebhookEvent
  | VideoLiveStreamWarningWebhookEvent
  | VideoLiveStreamSimulcastTargetCreatedWebhookEvent
  | VideoLiveStreamSimulcastTargetIdleWebhookEvent
  | VideoLiveStreamSimulcastTargetStartingWebhookEvent
  | VideoLiveStreamSimulcastTargetBroadcastingWebhookEvent
  | VideoLiveStreamSimulcastTargetErroredWebhookEvent
  | VideoLiveStreamSimulcastTargetDeletedWebhookEvent
  | VideoLiveStreamSimulcastTargetUpdatedWebhookEvent
  | VideoDeliveryHighTrafficWebhookEvent;

Webhook Handler Patterns

Event Routing

function handleWebhookEvent(event: UnwrapWebhookEvent) {
  switch (event.type) {
    // Asset events
    case 'video.asset.ready':
      handleAssetReady(event.data);
      break;
    case 'video.asset.errored':
      handleAssetError(event.data);
      break;

    // Live stream events
    case 'video.live_stream.active':
      handleStreamActive(event.data);
      break;
    case 'video.live_stream.idle':
      handleStreamIdle(event.data);
      break;

    // Upload events
    case 'video.upload.asset_created':
      handleUploadComplete(event.data);
      break;

    default:
      console.log('Unhandled event type:', event.type);
  }
}

function handleAssetReady(asset: Asset) {
  console.log(`Asset ${asset.id} is ready for playback`);
  // Update database, notify users, etc.
}

function handleStreamActive(stream: LiveStream) {
  console.log(`Live stream ${stream.id} is now active`);
  // Update stream status, notify viewers, etc.
}

TypeScript Type Guards

function isAssetEvent(event: UnwrapWebhookEvent): event is VideoAssetReadyWebhookEvent {
  return event.type.startsWith('video.asset.');
}

function isLiveStreamEvent(event: UnwrapWebhookEvent): event is VideoLiveStreamActiveWebhookEvent {
  return event.type.startsWith('video.live_stream.');
}

// Usage with type safety
if (isAssetEvent(event)) {
  // TypeScript knows event.data is Asset
  console.log('Asset duration:', event.data.duration);
}

Security Best Practices

  • Verify Signatures: Always verify webhook signatures before processing events
  • Use HTTPS: Configure webhook URLs to use HTTPS only
  • Validate Payload: Validate the structure and content of webhook payloads
  • Handle Duplicates: Implement idempotency using event IDs to handle duplicate events
  • Error Handling: Return appropriate HTTP status codes (200 for success, 4xx/5xx for errors)
  • Secret Management: Store webhook secrets securely and rotate them regularly

Install with Tessl CLI

npx tessl i tessl/npm-mux--mux-node

docs

analytics-metrics.md

client-setup.md

data.md

delivery-usage.md

error-handling.md

index.md

jwt-signing.md

jwt.md

live-streaming.md

playback-control.md

system-operations.md

system.md

transcription-vocabularies.md

upload-utilities.md

video-assets.md

video-playback.md

video-uploads.md

video.md

web-inputs.md

webhooks.md

tile.json