or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

audio

audio-processing.mdrealtime-transcription.mdspeech-to-speech.mdspeech-to-text.mdtext-to-speech.md
index.md
tile.json

studio.mddocs/content/

Studio Projects

Create and manage podcast projects with automatic conversion. The Studio API enables programmatic creation and management of audio projects for podcasts and long-form content.

Quick Reference

import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";

const client = new ElevenLabsClient({ apiKey: "your-api-key" });
// Access this API via: client.studio

Capabilities

Create Podcast

Create and automatically convert podcast project.

/**
 * @param request - Podcast script and configuration
 * @param requestOptions - Optional request configuration
 * @returns Created podcast project
 * @throws UnprocessableEntityError if request fails
 */
client.studio.createPodcast(
  request: BodyCreatePodcastV1StudioPodcastsPost,
  requestOptions?: RequestOptions
): HttpResponsePromise<PodcastProjectResponseModel>;

interface BodyCreatePodcastV1StudioPodcastsPost {
  /** Used for moderation. Your workspace must be allowlisted to use this feature. */
  safetyIdentifier?: string;
  /** The ID of the model to be used for this Studio project, you can query GET /v1/models to list all available models. (REQUIRED) */
  modelId: string;
  /** The type of podcast to generate. Can be 'conversation', an interaction between two voices, or 'bulletin', a monologue. (REQUIRED) */
  mode: BodyCreatePodcastV1StudioPodcastsPostMode;
  /** The source content for the Podcast. (REQUIRED) */
  source: BodyCreatePodcastV1StudioPodcastsPostSource;
  /** Output quality: 'standard' (128kbps 44.1kHz), 'high' (192kbps 44.1kHz), 'ultra' (192kbps 44.1kHz highest quality), 'ultra lossless' (705.6kbps 44.1kHz lossless) */
  qualityPreset?: "standard" | "high" | "ultra" | "ultra lossless";
  /** Duration scale: 'short' (<3min), 'default' (3-7min), 'long' (>7min) */
  durationScale?: "short" | "default" | "long";
  /** Language of the Studio project (ISO 639-1 two-letter code) */
  language?: string;
  /** Intro text that will always be added to the beginning of the podcast */
  intro?: string;
  /** Outro text that will always be added to the end of the podcast */
  outro?: string;
  /** Additional instructions prompt for the podcast generation used to adjust style and tone */
  instructionsPrompt?: string;
  /** Brief summary or highlights of the project's content (10-70 characters each) */
  highlights?: string[];
  /** Webhook URL called when the Studio project is converted */
  callbackUrl?: string;
  /** Text normalization mode: 'auto', 'on', 'off', 'apply_english' */
  applyTextNormalization?: "auto" | "on" | "off" | "apply_english";
}

/** Mode for podcast generation */
interface BodyCreatePodcastV1StudioPodcastsPostMode {
  /** Type of podcast: 'conversation' or 'bulletin' */
  type: "conversation" | "bulletin";
  /** Configuration for conversation mode (required if type is 'conversation') */
  conversation?: {
    hostVoiceId: string;
    guestVoiceId: string;
  };
  /** Configuration for bulletin mode (required if type is 'bulletin') */
  bulletin?: {
    voiceId: string;
  };
}

/** Source content for the podcast */
interface BodyCreatePodcastV1StudioPodcastsPostSource {
  /** Source type: 'text', 'url', or 'file' */
  type: "text" | "url" | "file";
  /** Text content (required if type is 'text') */
  text?: string;
  /** URL to extract content from (required if type is 'url') */
  url?: string;
  /** File to extract content from (required if type is 'file') */
  file?: File;
}

interface PodcastProjectResponseModel {
  /** Project ID */
  project_id: string;
  /** Project name */
  name: string;
  /** Project status */
  status: "creating" | "converting" | "completed" | "failed";
  /** Audio URL (when completed) */
  audio_url?: string;
  /** Error message (if failed) */
  error?: string;
}

Project Management

Manage Studio projects.

/**
 * List all Studio projects
 */
client.studio.projects.list(
  request?: ProjectsListRequest,
  requestOptions?: RequestOptions
): HttpResponsePromise<GetStudioProjectsResponseModel>;

/**
 * Get project details
 */
client.studio.projects.get(
  project_id: string,
  requestOptions?: RequestOptions
): HttpResponsePromise<StudioProjectResponseModel>;

/**
 * Update project
 */
client.studio.projects.update(
  project_id: string,
  request: UpdateStudioProjectRequest,
  requestOptions?: RequestOptions
): HttpResponsePromise<StudioProjectResponseModel>;

/**
 * Create project
 */
client.studio.projects.create(
  request: BodyCreateStudioProjectV1StudioProjectsPost,
  requestOptions?: RequestOptions
): HttpResponsePromise<AddProjectResponseModel>;

/**
 * Delete project
 */
client.studio.projects.delete(
  project_id: string,
  requestOptions?: RequestOptions
): HttpResponsePromise<void>;

/**
 * Convert project to audio
 */
client.studio.projects.convert(
  project_id: string,
  requestOptions?: RequestOptions
): HttpResponsePromise<ConvertProjectResponseModel>;

interface ProjectsListRequest {
  page_size?: number;
  next_page_token?: string;
  status?: "creating" | "converting" | "completed" | "failed";
}

interface StudioProjectResponseModel {
  project_id: string;
  name: string;
  status: string;
  created_at: number;
  updated_at: number;
  audio_url?: string;
  duration_seconds?: number;
  character_count?: number;
}

interface ConvertProjectResponseModel {
  /** Status of conversion request ('ok' if successful) */
  status: string;
}

Project Content Management

Update Studio project content from URL, document, or raw content.

/**
 * @param project_id - Project ID
 * @param request - Content update options
 * @param requestOptions - Optional request configuration
 * @returns Updated project
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.content.update(
  project_id: string,
  request: BodyUpdateStudioProjectContentV1StudioProjectsProjectIdContentPost,
  requestOptions?: RequestOptions
): HttpResponsePromise<EditProjectResponseModel>;

interface BodyUpdateStudioProjectContentV1StudioProjectsProjectIdContentPost {
  /** URL from which to extract content */
  from_url?: string;
  /** Document file (.epub, .pdf, .txt, etc.) */
  from_document?: File;
  /** Raw JSON content */
  from_content_json?: string;
  /** Whether to auto convert project to audio */
  auto_convert?: boolean;
}

interface EditProjectResponseModel {
  project: ProjectResponse;
}

Pronunciation Dictionaries

Manage pronunciation dictionaries for projects.

/**
 * @param project_id - Project ID
 * @param request - Dictionary locators
 * @param requestOptions - Optional request configuration
 * @returns Creation status
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.pronunciationDictionaries.create(
  project_id: string,
  request: BodyCreatePronunciationDictionariesV1StudioProjectsProjectIdPronunciationDictionariesPost,
  requestOptions?: RequestOptions
): HttpResponsePromise<CreatePronunciationDictionaryResponseModel>;

interface BodyCreatePronunciationDictionariesV1StudioProjectsProjectIdPronunciationDictionariesPost {
  /** List of pronunciation dictionary locators */
  pronunciation_dictionary_locators: PronunciationDictionaryVersionLocator[];
  /** Auto-mark affected text for reconversion */
  invalidate_affected_text?: boolean;
}

interface CreatePronunciationDictionaryResponseModel {
  /** Status of request ('ok' if successful) */
  status: string;
}

Chapter Management

Manage chapters within Studio projects.

List Chapters

/**
 * @param project_id - Project ID
 * @param requestOptions - Optional request configuration
 * @returns List of chapters
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.chapters.list(
  project_id: string,
  requestOptions?: RequestOptions
): HttpResponsePromise<GetChaptersResponse>;

interface GetChaptersResponse {
  chapters: ChapterResponse[];
}

Create Chapter

/**
 * @param project_id - Project ID
 * @param request - Chapter details
 * @param requestOptions - Optional request configuration
 * @returns Created chapter
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.chapters.create(
  project_id: string,
  request: BodyCreateChapterV1StudioProjectsProjectIdChaptersPost,
  requestOptions?: RequestOptions
): HttpResponsePromise<AddChapterResponseModel>;

interface BodyCreateChapterV1StudioProjectsProjectIdChaptersPost {
  /** Chapter name */
  name: string;
  /** Optional URL to extract content from */
  from_url?: string;
}

interface AddChapterResponseModel {
  chapter: ChapterWithContentResponseModel;
}

Get Chapter

/**
 * @param project_id - Project ID
 * @param chapter_id - Chapter ID
 * @param requestOptions - Optional request configuration
 * @returns Chapter details with content
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.chapters.get(
  project_id: string,
  chapter_id: string,
  requestOptions?: RequestOptions
): HttpResponsePromise<ChapterWithContentResponseModel>;

interface ChapterWithContentResponseModel {
  chapter_id: string;
  name: string;
  last_conversion_date_unix?: number;
  conversion_progress?: number;
  can_be_downloaded: boolean;
  state: string;
  has_video?: boolean;
  voice_ids?: string[];
  statistics?: ChapterStatisticsResponse;
  last_conversion_error?: string;
  content: ChapterContentResponseModel;
}

Update Chapter

/**
 * @param project_id - Project ID
 * @param chapter_id - Chapter ID
 * @param request - Chapter updates
 * @param requestOptions - Optional request configuration
 * @returns Updated chapter
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.chapters.update(
  project_id: string,
  chapter_id: string,
  request?: BodyUpdateChapterV1StudioProjectsProjectIdChaptersChapterIdPost,
  requestOptions?: RequestOptions
): HttpResponsePromise<EditChapterResponseModel>;

interface BodyUpdateChapterV1StudioProjectsProjectIdChaptersChapterIdPost {
  /** Chapter name */
  name?: string;
  /** Chapter content */
  content?: ChapterContentInputModel;
}

interface EditChapterResponseModel {
  chapter: ChapterWithContentResponseModel;
}

Delete Chapter

/**
 * @param project_id - Project ID
 * @param chapter_id - Chapter ID
 * @param requestOptions - Optional request configuration
 * @returns Deletion status
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.chapters.delete(
  project_id: string,
  chapter_id: string,
  requestOptions?: RequestOptions
): HttpResponsePromise<DeleteChapterResponseModel>;

interface DeleteChapterResponseModel {
  /** Status of deletion ('ok' if successful) */
  status: string;
}

Convert Chapter

/**
 * @param project_id - Project ID
 * @param chapter_id - Chapter ID
 * @param requestOptions - Optional request configuration
 * @returns Conversion status
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.chapters.convert(
  project_id: string,
  chapter_id: string,
  requestOptions?: RequestOptions
): HttpResponsePromise<ConvertChapterResponseModel>;

interface ConvertChapterResponseModel {
  /** Status of conversion ('ok' if successful) */
  status: string;
}

Chapter Snapshots

Manage chapter snapshots (generated after each conversion).

List Chapter Snapshots

/**
 * @param project_id - Project ID
 * @param chapter_id - Chapter ID
 * @param requestOptions - Optional request configuration
 * @returns List of chapter snapshots
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.chapters.snapshots.list(
  project_id: string,
  chapter_id: string,
  requestOptions?: RequestOptions
): HttpResponsePromise<ChapterSnapshotsResponse>;

interface ChapterSnapshotsResponse {
  snapshots: ChapterSnapshotResponse[];
}

Get Chapter Snapshot

/**
 * @param project_id - Project ID
 * @param chapter_id - Chapter ID
 * @param chapter_snapshot_id - Chapter snapshot ID
 * @param requestOptions - Optional request configuration
 * @returns Chapter snapshot details
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.chapters.snapshots.get(
  project_id: string,
  chapter_id: string,
  chapter_snapshot_id: string,
  requestOptions?: RequestOptions
): HttpResponsePromise<ChapterSnapshotExtendedResponseModel>;

interface ChapterSnapshotExtendedResponseModel {
  chapter_snapshot_id: string;
  project_id: string;
  chapter_id: string;
  created_at_unix: number;
  name: string;
  character_alignments: CharacterAlignmentModel[];
}

Stream Chapter Snapshot Audio

/**
 * @param project_id - Project ID
 * @param chapter_id - Chapter ID
 * @param chapter_snapshot_id - Chapter snapshot ID
 * @param request - Stream options
 * @param requestOptions - Optional request configuration
 * @returns Audio stream
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.chapters.snapshots.stream(
  project_id: string,
  chapter_id: string,
  chapter_snapshot_id: string,
  request?: BodyStreamChapterAudioV1StudioProjectsProjectIdChaptersChapterIdSnapshotsChapterSnapshotIdStreamPost,
  requestOptions?: RequestOptions
): HttpResponsePromise<ReadableStream<Uint8Array>>;

interface BodyStreamChapterAudioV1StudioProjectsProjectIdChaptersChapterIdSnapshotsChapterSnapshotIdStreamPost {
  /** Whether to convert audio to mpeg format */
  convert_to_mpeg?: boolean;
}

Project Snapshots

Manage project-level snapshots (generated after full project conversion).

List Project Snapshots

/**
 * @param project_id - Project ID
 * @param requestOptions - Optional request configuration
 * @returns List of project snapshots
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.snapshots.list(
  project_id: string,
  requestOptions?: RequestOptions
): HttpResponsePromise<ProjectSnapshotsResponse>;

interface ProjectSnapshotsResponse {
  snapshots: ProjectSnapshotResponse[];
}

Get Project Snapshot

/**
 * @param project_id - Project ID
 * @param project_snapshot_id - Project snapshot ID
 * @param requestOptions - Optional request configuration
 * @returns Project snapshot details
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.snapshots.get(
  project_id: string,
  project_snapshot_id: string,
  requestOptions?: RequestOptions
): HttpResponsePromise<ProjectSnapshotExtendedResponseModel>;

interface ProjectSnapshotExtendedResponseModel {
  project_snapshot_id: string;
  project_id: string;
  created_at_unix: number;
  name: string;
  character_alignments: CharacterAlignmentModel[];
  audio_duration_secs: number;
}

Stream Project Snapshot Audio

/**
 * @param project_id - Project ID
 * @param project_snapshot_id - Project snapshot ID
 * @param request - Stream options
 * @param requestOptions - Optional request configuration
 * @returns Audio stream
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.snapshots.stream(
  project_id: string,
  project_snapshot_id: string,
  request?: BodyStreamStudioProjectAudioV1StudioProjectsProjectIdSnapshotsProjectSnapshotIdStreamPost,
  requestOptions?: RequestOptions
): HttpResponsePromise<ReadableStream<Uint8Array>>;

interface BodyStreamStudioProjectAudioV1StudioProjectsProjectIdSnapshotsProjectSnapshotIdStreamPost {
  /** Whether to convert audio to mpeg format */
  convert_to_mpeg?: boolean;
}

Stream Project Snapshot Archive

/**
 * @param project_id - Project ID
 * @param project_snapshot_id - Project snapshot ID
 * @param requestOptions - Optional request configuration
 * @returns Compressed archive stream
 * @throws UnprocessableEntityError if request fails
 */
client.studio.projects.snapshots.streamArchive(
  project_id: string,
  project_snapshot_id: string,
  requestOptions?: RequestOptions
): HttpResponsePromise<ReadableStream<Uint8Array>>;

Project Response Types

Complete type definitions for Studio project responses.

/**
 * Complete project response with all metadata
 */
interface ProjectResponse {
  /** Project ID */
  projectId: string;
  /** Project name */
  name: string;
  /** Creation date (Unix timestamp) */
  createDateUnix: number;
  /** User ID who created the project */
  createdByUserId?: string;
  /** Default voice ID for titles */
  defaultTitleVoiceId: string;
  /** Default voice ID for paragraphs */
  defaultParagraphVoiceId: string;
  /** Default TTS model ID */
  defaultModelId: string;
  /** Last conversion date (Unix timestamp) */
  lastConversionDateUnix?: number;
  /** Whether project can be downloaded */
  canBeDownloaded: boolean;
  /** Project title */
  title?: string;
  /** Project author */
  author?: string;
  /** Project description */
  description?: string;
  /** List of genres */
  genres?: string[];
  /** Cover image URL */
  coverImageUrl?: string;
  /** Target audience */
  targetAudience?: ProjectResponseModelTargetAudience;
  /** Language (ISO 639-1 code) */
  language?: string;
  /** Content type (e.g., 'Novel', 'Short Story') */
  contentType?: string;
  /** Original publication date */
  originalPublicationDate?: string;
  /** Whether contains mature content */
  matureContent?: boolean;
  /** ISBN number */
  isbnNumber?: string;
  /** Volume normalization enabled */
  volumeNormalization: boolean;
  /** Project state */
  state: ProjectState;
  /** Access level */
  accessLevel: ProjectResponseModelAccessLevel;
  /** Fiction classification */
  fiction?: ProjectResponseModelFiction;
  /** Quality check enabled */
  qualityCheckOn: boolean;
  /** Quality check on bulk convert */
  qualityCheckOnWhenBulkConvert: boolean;
  /** Creation metadata */
  creationMeta?: ProjectCreationMetaResponseModel;
  /** Source type */
  sourceType?: ProjectResponseModelSourceType;
  /** Chapters enabled */
  chaptersEnabled?: boolean;
  /** Captions enabled */
  captionsEnabled?: boolean;
  /** Global caption styling */
  captionStyle?: CaptionStyleModel;
  /** Public share ID */
  publicShareId?: string;
  /** Aspect ratio */
  aspectRatio?: ProjectResponseModelAspectRatio;
}

/**
 * Project state enum
 */
enum ProjectState {
  CREATING = "creating",
  DEFAULT = "default",
  CONVERTING = "converting",
  IN_QUEUE = "in_queue",
}

/**
 * Project target audience
 */
enum ProjectResponseModelTargetAudience {
  CHILDREN = "children",
  YOUNG_ADULT = "young adult",
  ADULT = "adult",
  ALL_AGES = "all ages",
}

/**
 * Project access level
 */
enum ProjectResponseModelAccessLevel {
  PRIVATE = "private",
  PUBLIC = "public",
  WORKSPACE = "workspace",
}

/**
 * Project fiction classification
 */
enum ProjectResponseModelFiction {
  FICTION = "fiction",
  NON_FICTION = "non-fiction",
}

/**
 * Project source type
 */
enum ProjectResponseModelSourceType {
  URL = "url",
  FILE = "file",
  TEXT = "text",
}

/**
 * Project aspect ratio
 */
enum ProjectResponseModelAspectRatio {
  RATIO_16_9 = "16:9",
  RATIO_9_16 = "9:16",
  RATIO_1_1 = "1:1",
}

/**
 * Project creation metadata
 */
interface ProjectCreationMetaResponseModel {
  /** Creation progress (0-1) */
  creationProgress: number;
  /** Creation status */
  status: ProjectCreationMetaResponseModelStatus;
  /** Creation action type */
  type: ProjectCreationMetaResponseModelType;
}

/**
 * Project creation status
 */
enum ProjectCreationMetaResponseModelStatus {
  IN_PROGRESS = "in_progress",
  COMPLETED = "completed",
  FAILED = "failed",
}

/**
 * Project creation type
 */
enum ProjectCreationMetaResponseModelType {
  FROM_URL = "from_url",
  FROM_FILE = "from_file",
  FROM_TEXT = "from_text",
}

/**
 * Caption style configuration
 * Note: CaptionStyleTemplateModel, CaptionStyleSectionAnimationModel, CaptionStyleWordAnimationModel,
 * CaptionStyleCharacterAnimationModel, CaptionStyleHorizontalPlacementModel, and
 * CaptionStyleVerticalPlacementModel are available via the ElevenLabs namespace.
 */
interface CaptionStyleModel {
  /** Caption template */
  template?: CaptionStyleTemplateModel;
  /** Text font */
  textFont?: string;
  /** Text scale */
  textScale?: number;
  /** Text color */
  textColor?: string;
  /** Text alignment */
  textAlign?: CaptionStyleModelTextAlign;
  /** Text style */
  textStyle?: CaptionStyleModelTextStyle;
  /** Text weight */
  textWeight?: CaptionStyleModelTextWeight;
  /** Background enabled */
  backgroundEnabled?: boolean;
  /** Background color */
  backgroundColor?: string;
  /** Background opacity */
  backgroundOpacity?: number;
  /** Word highlights enabled */
  wordHighlightsEnabled?: boolean;
  /** Word highlights color */
  wordHighlightsColor?: string;
  /** Word highlights background */
  wordHighlightsBackgroundColor?: string;
  /** Word highlights opacity */
  wordHighlightsOpacity?: number;
  /** Section animation */
  sectionAnimation?: CaptionStyleSectionAnimationModel;
  /** Word animation */
  wordAnimation?: CaptionStyleWordAnimationModel;
  /** Character animation */
  characterAnimation?: CaptionStyleCharacterAnimationModel;
  /** Width percentage */
  widthPct?: number;
  /** Horizontal placement */
  horizontalPlacement?: CaptionStyleHorizontalPlacementModel;
  /** Vertical placement */
  verticalPlacement?: CaptionStyleVerticalPlacementModel;
  /** Auto break enabled */
  autoBreakEnabled?: boolean;
  /** Max lines per section */
  maxLinesPerSection?: number;
  /** Max words per line */
  maxWordsPerLine?: number;
}

/**
 * Caption style text alignment
 */
enum CaptionStyleModelTextAlign {
  LEFT = "left",
  CENTER = "center",
  RIGHT = "right",
}

/**
 * Caption style text style
 */
enum CaptionStyleModelTextStyle {
  NORMAL = "normal",
  ITALIC = "italic",
}

/**
 * Caption style text weight
 */
enum CaptionStyleModelTextWeight {
  NORMAL = "normal",
  BOLD = "bold",
}

/**
 * Chapter content response
 */
interface ChapterContentResponseModel {
  /** Array of content blocks */
  blocks: ChapterContentBlockResponseModel[];
}

/**
 * Chapter content block
 */
interface ChapterContentBlockResponseModel {
  /** Block ID */
  id: string;
  /** Block type */
  type: string;
  /** Block content nodes */
  nodes: ChapterContentNodeResponseModel[];
}

/**
 * Chapter content node
 */
interface ChapterContentNodeResponseModel {
  /** Node ID */
  id: string;
  /** Node type */
  type: string;
  /** Node text content */
  text?: string;
  /** Voice ID for this node */
  voiceId?: string;
  /** Whether node is excluded from conversion */
  excluded?: boolean;
}

/**
 * Chapter content input for updates
 */
interface ChapterContentInputModel {
  /** Array of content blocks */
  blocks: ChapterContentBlockInputModel[];
}

/**
 * Chapter content block input
 */
interface ChapterContentBlockInputModel {
  /** Block type */
  type: string;
  /** Block nodes */
  nodes: ChapterContentNodeInputModel[];
}

/**
 * Chapter content node input
 */
interface ChapterContentNodeInputModel {
  /** Node type */
  type: string;
  /** Node text */
  text?: string;
  /** Voice ID */
  voiceId?: string;
  /** Excluded from conversion */
  excluded?: boolean;
}

/**
 * Chapter response
 */
interface ChapterResponse {
  /** Chapter ID */
  chapter_id: string;
  /** Chapter name */
  name: string;
  /** Last conversion date */
  last_conversion_date_unix?: number;
  /** Conversion progress */
  conversion_progress?: number;
  /** Can be downloaded */
  can_be_downloaded: boolean;
  /** Chapter state */
  state: string;
  /** Has video */
  has_video?: boolean;
  /** Voice IDs used */
  voice_ids?: string[];
  /** Chapter statistics */
  statistics?: ChapterStatisticsResponse;
  /** Last conversion error */
  last_conversion_error?: string;
}

/**
 * Chapter statistics
 */
interface ChapterStatisticsResponse {
  /** Character count */
  character_count: number;
  /** Duration in seconds */
  duration_seconds: number;
}

/**
 * Chapter with full content
 */
interface ChapterWithContentResponseModel {
  /** Chapter ID */
  chapter_id: string;
  /** Chapter name */
  name: string;
  /** Last conversion date */
  last_conversion_date_unix?: number;
  /** Conversion progress */
  conversion_progress?: number;
  /** Can be downloaded */
  can_be_downloaded: boolean;
  /** Chapter state */
  state: string;
  /** Has video */
  has_video?: boolean;
  /** Voice IDs used */
  voice_ids?: string[];
  /** Chapter statistics */
  statistics?: ChapterStatisticsResponse;
  /** Last conversion error */
  last_conversion_error?: string;
  /** Chapter content */
  content: ChapterContentResponseModel;
}

/**
 * Chapter snapshot response
 */
interface ChapterSnapshotResponse {
  /** Snapshot ID */
  chapter_snapshot_id: string;
  /** Project ID */
  project_id: string;
  /** Chapter ID */
  chapter_id: string;
  /** Creation timestamp */
  created_at_unix: number;
  /** Snapshot name */
  name: string;
}

/**
 * Extended chapter snapshot with alignments
 */
interface ChapterSnapshotExtendedResponseModel {
  /** Snapshot ID */
  chapter_snapshot_id: string;
  /** Project ID */
  project_id: string;
  /** Chapter ID */
  chapter_id: string;
  /** Creation timestamp */
  created_at_unix: number;
  /** Snapshot name */
  name: string;
  /** Character alignments */
  character_alignments: CharacterAlignmentModel[];
}

/**
 * Project snapshot response
 */
interface ProjectSnapshotResponse {
  /** Snapshot ID */
  project_snapshot_id: string;
  /** Project ID */
  project_id: string;
  /** Creation timestamp */
  created_at_unix: number;
  /** Snapshot name */
  name: string;
}

/**
 * Extended project snapshot with alignments
 */
interface ProjectSnapshotExtendedResponseModel {
  /** Snapshot ID */
  project_snapshot_id: string;
  /** Project ID */
  project_id: string;
  /** Creation timestamp */
  created_at_unix: number;
  /** Snapshot name */
  name: string;
  /** Character alignments */
  character_alignments: CharacterAlignmentModel[];
  /** Audio duration in seconds */
  audio_duration_secs: number;
}

/**
 * Character alignment for audio synchronization
 */
interface CharacterAlignmentModel {
  /** Character index in text */
  character_index: number;
  /** Start time in seconds */
  start_time_secs: number;
  /** End time in seconds */
  end_time_secs: number;
}

Usage Examples

Create Simple Podcast (Bulletin Mode)

import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";

const client = new ElevenLabsClient({ apiKey: "your-api-key" });

// Create bulletin podcast (monologue)
const podcast = await client.studio.createPodcast({
  modelId: "eleven_multilingual_v2",
  mode: {
    type: "bulletin",
    bulletin: {
      voiceId: "narrator-voice-id",
    },
  },
  source: {
    type: "text",
    text: "Welcome to our podcast! Today we'll be discussing...",
  },
});

console.log("Podcast created:", podcast.project_id);
console.log("Status:", podcast.status);

Create Conversation Podcast

// Create conversation podcast (dialogue between two voices)
const podcast = await client.studio.createPodcast({
  modelId: "eleven_multilingual_v2",
  mode: {
    type: "conversation",
    conversation: {
      hostVoiceId: "host-voice-id",
      guestVoiceId: "guest-voice-id",
    },
  },
  source: {
    type: "text",
    text: `
      Welcome to Tech Talk, where we discuss the latest in technology.
      Today's topic is artificial intelligence and machine learning.
    `,
  },
  qualityPreset: "high",
  durationScale: "default",
});

Poll for Completion

// Wait for podcast to finish converting
async function waitForPodcast(projectId: string): Promise<string> {
  while (true) {
    const project = await client.studio.projects.get(projectId);

    console.log("Status:", project.status);

    if (project.status === "completed") {
      return project.audio_url!;
    } else if (project.status === "failed") {
      throw new Error(`Podcast failed: ${project.error}`);
    }

    // Wait before checking again
    await new Promise(resolve => setTimeout(resolve, 5000));
  }
}

const audioUrl = await waitForPodcast(podcast.project_id);
console.log("Podcast ready:", audioUrl);

List Projects

// Get all podcast projects
const projects = await client.studio.projects.list({
  pageSize: 50,
  status: "completed",
});

console.log("Completed Projects:");
for (const project of projects.projects) {
  console.log(`${project.name} (${project.project_id})`);
  console.log(`  Duration: ${project.duration_seconds}s`);
  console.log(`  Characters: ${project.character_count}`);
}

Update Project

// Update project name
await client.studio.projects.update(podcast.project_id, {
  name: "Episode 1: Introduction (Revised)",
});

Delete Project

// Delete podcast project
await client.studio.projects.delete(podcast.project_id);
console.log("Project deleted");

Download Podcast Audio

import { writeFile } from "fs/promises";

// Download completed podcast
const project = await client.studio.projects.get(podcast.project_id);

if (project.audio_url) {
  const response = await fetch(project.audio_url);
  const audioBuffer = await response.arrayBuffer();

  await writeFile("podcast.mp3", Buffer.from(audioBuffer));
  console.log("Podcast downloaded");
}

Batch Podcast Creation

// Create multiple podcast episodes
interface Episode {
  number: number;
  title: string;
  script: string;
}

const episodes: Episode[] = [
  {
    number: 1,
    title: "Introduction",
    script: "Welcome to episode 1...",
  },
  {
    number: 2,
    title: "Getting Started",
    script: "In episode 2, we'll cover...",
  },
  {
    number: 3,
    title: "Advanced Topics",
    script: "Episode 3 dives deep into...",
  },
];

async function createPodcastSeries(
  seriesName: string,
  episodes: Episode[],
  voiceId: string
): Promise<void> {
  for (const episode of episodes) {
    const podcast = await client.studio.createPodcast({
      modelId: "eleven_multilingual_v2",
      mode: {
        type: "bulletin",
        bulletin: {
          voiceId: voiceId,
        },
      },
      source: {
        type: "text",
        text: episode.script,
      },
    });

    console.log(`Created Episode ${episode.number}:`, podcast.project_id);

    // Wait for conversion
    const audioUrl = await waitForPodcast(podcast.project_id);
    console.log(`Episode ${episode.number} ready:`, audioUrl);
  }
}

await createPodcastSeries("Tech Talk Podcast", episodes, "narrator-voice-id");

Podcast from URL

// Create podcast from URL source
const podcast = await client.studio.createPodcast({
  modelId: "eleven_multilingual_v2",
  mode: {
    type: "bulletin",
    bulletin: {
      voiceId: "voice-id",
    },
  },
  source: {
    type: "url",
    url: "https://example.com/article.html",
  },
});

Monitor Project Status

// Monitor multiple projects
async function monitorProjects(): Promise<void> {
  const projects = await client.studio.projects.list({
    status: "converting",
  });

  console.log(`Monitoring ${projects.projects.length} converting projects`);

  for (const project of projects.projects) {
    console.log(`${project.name}: ${project.status}`);
  }
}

// Run periodically
setInterval(monitorProjects, 30000); // Every 30 seconds

Complete Workflow

// Complete podcast creation workflow
async function createAndDownloadPodcast(
  script: string,
  voiceId: string,
  outputPath: string
): Promise<void> {
  // 1. Create project
  console.log("Creating podcast...");
  const podcast = await client.studio.createPodcast({
    modelId: "eleven_multilingual_v2",
    mode: {
      type: "bulletin",
      bulletin: {
        voiceId: voiceId,
      },
    },
    source: {
      type: "text",
      text: script,
    },
  });

  // 2. Wait for completion
  console.log("Converting...");
  const audioUrl = await waitForPodcast(podcast.project_id);

  // 3. Download audio
  console.log("Downloading...");
  const response = await fetch(audioUrl);
  const audioBuffer = await response.arrayBuffer();
  await writeFile(outputPath, Buffer.from(audioBuffer));

  // 4. Get project details
  const project = await client.studio.projects.get(podcast.project_id);

  console.log("Podcast created successfully!");
  console.log(`Duration: ${project.duration_seconds}s`);
  console.log(`Characters: ${project.character_count}`);
  console.log(`Saved to: ${outputPath}`);
}

await createAndDownloadPodcast(
  "Welcome to my podcast...",
  "voice-id",
  "./podcast.mp3"
);

Error Handling

// Handle podcast creation errors
try {
  const podcast = await client.studio.createPodcast({
    modelId: "eleven_multilingual_v2",
    mode: {
      type: "bulletin",
      bulletin: {
        voiceId: "voice-id",
      },
    },
    source: {
      type: "text",
      text: "Test content",
    },
  });

  const audioUrl = await waitForPodcast(podcast.project_id);
  console.log("Success:", audioUrl);
} catch (error) {
  console.error("Podcast creation failed:", error);

  // Check if project was created
  const projects = await client.studio.projects.list();
  const failedProject = projects.projects.find(p => p.status === "failed");

  if (failedProject) {
    console.error("Failed project:", failedProject.error);
  }
}

Paginate Projects

// Get all projects with pagination
async function getAllProjects() {
  const allProjects = [];
  let nextToken: string | undefined;

  while (true) {
    const page = await client.studio.projects.list({
      pageSize: 100,
      next_page_token: nextToken,
    });

    allProjects.push(...page.projects);

    if (!page.has_more) break;
    nextToken = page.next_page_token;
  }

  return allProjects;
}

const all = await getAllProjects();
console.log(`Total projects: ${all.length}`);