MeetingRouter

Migrating from v1 to v2 API

@meeting-baas/sdk - v1 API Reference / v1-migration-to-v2

Migrating from v1 to v2 API

This guide helps you migrate from Meeting BaaS v1 API to v2 API.

Why Migrate?

The v2 API offers several improvements:

  • Better error responses: Structured error codes and detailed information
  • Batch operations: Create and manage multiple bots at once
  • Improved webhook types: Comprehensive TypeScript types for all webhook events
  • Enhanced status tracking: More granular bot status updates
  • Consistent response format: API returns structured responses natively

Quick Migration

Step 1: Update Client Configuration

Simply change the api_version parameter:

// Before (v1)
const client = createBaasClient({
  api_key: "your-api-key"
});

// After (v2)
const client = createBaasClient({
  api_key: "your-api-key",
  api_version: "v2"
});

Step 2: Update Method Names

Some methods have been renamed in v2:

v1 Methodv2 MethodNotes
joinMeeting()createBot()More descriptive name
leaveMeeting()stopBot()Clearer intent
getMeetingData()getBot()Consistent naming
deleteBotData()deleteBotData()Unchanged

Step 3: Update Error Handling

v2 has structured error responses:

// v1 error handling
const result = await client.joinMeeting({ ... });

if (!result.success) {
  if (result.error instanceof ZodError) {
    // Validation error
  } else {
    // API error - parse message
    console.error(result.error.message);
  }
}

// v2 error handling
const result = await client.createBot({ ... });

if (!result.success) {
  // Structured error with code
  console.error(result.error);      // Human-readable message
  console.error(result.code);       // Machine-readable code
  console.error(result.statusCode); // HTTP status
  console.error(result.details);    // Additional details
}

Detailed Changes

Method Mapping

Bot Management

// v1: Join Meeting
const v1Result = await v1Client.joinMeeting({
  meeting_url: "https://meet.google.com/abc",
  bot_name: "Bot",
  reserved: true
});

// v2: Create Bot
const v2Result = await v2Client.createBot({
  meeting_url: "https://meet.google.com/abc",
  bot_name: "Bot"
  // 'reserved' parameter removed in v2
});
// v1: Leave Meeting
const v1Result = await v1Client.leaveMeeting({
  uuid: botId
});

// v2: Stop Bot
const v2Result = await v2Client.stopBot({
  bot_id: botId
});
// v1: Get Meeting Data
const v1Result = await v1Client.getMeetingData({
  bot_id: botId,
  include_transcripts: true
});

// v2: Get Bot
const v2Result = await v2Client.getBot({
  bot_id: botId
  // Transcripts are always included if available
});

Response Structure Changes

// v1 Response (SDK wraps API response)
type V1Response\<T\> =
  | { success: true; data: T; error?: never }
  | { success: false; error: ZodError | Error; data?: never }

// v2 Response (API returns structured response)
type V2Response\<T\> =
  | { success: true; data: T; error?: never }
  | {
      success: false;
      error: string;
      code: string;
      statusCode: number;
      details: unknown | null;
      data?: never
    }

New v2 Features

Batch Operations

v2 introduces batch operations not available in v1:

// Create multiple bots at once
const result = await v2Client.batchCreateBots({
  bots: [
    { meeting_url: "https://meet.google.com/abc", bot_name: "Bot 1" },
    { meeting_url: "https://zoom.us/j/123", bot_name: "Bot 2" },
    { meeting_url: "https://teams.microsoft.com/...", bot_name: "Bot 3" }
  ]
});

if (result.success) {
  console.log("Created:", result.data.length);

  // Check for partial failures
  if (result.errors && result.errors.length > 0) {
    console.log("Failed:", result.errors.length);
  }
}
// Stop multiple bots at once
const result = await v2Client.batchStopBots({
  bot_ids: ["bot-1", "bot-2", "bot-3"]
});
// Get multiple bots at once
const result = await v2Client.batchGetBots({
  bot_ids: ["bot-1", "bot-2", "bot-3"]
});

Enhanced Webhook Types

v2 provides comprehensive webhook types:

import type { V2 } from "@meeting-baas/sdk";

// Type-safe webhook handler
async function handleWebhook(payload: unknown) {
  // Type guard for bot.completed webhook
  if (isWebhook<V2.BotWebhookCompleted>(payload, "bot.completed")) {
    console.log("Bot completed:", payload.data.bot_id);
    console.log("Recording:", payload.data.mp4_url);
  }

  // Type guard for bot.failed webhook
  if (isWebhook<V2.BotWebhookFailed>(payload, "bot.failed")) {
    console.error("Bot failed:", payload.data.bot_id);
    console.error("Error:", payload.data.error_message);
  }
}

function isWebhook<T extends { event: string }>(
  payload: unknown,
  event: string
): payload is T {
  return (payload as any)?.event === event;
}

Migration Strategy

Gradual Migration

You can run both v1 and v2 clients simultaneously:

const v1Client = createBaasClient({
  api_key: process.env.API_KEY!,
  api_version: "v1"
});

const v2Client = createBaasClient({
  api_key: process.env.API_KEY!,
  api_version: "v2"
});

// Use v2 for new features
const createResult = await v2Client.createBot({ ... });

// Keep v1 for legacy code
const legacyResult = await v1Client.joinMeeting({ ... });

Feature Flag Pattern

const USE_V2_API = process.env.FEATURE_V2_API === "true";

const client = createBaasClient({
  api_key: process.env.API_KEY!,
  api_version: USE_V2_API ? "v2" : "v1"
});

// Abstraction layer
async function createMeetingBot(meetingUrl: string, botName: string) {
  if (USE_V2_API) {
    return await (client as V2Client).createBot({
      meeting_url: meetingUrl,
      bot_name: botName
    });
  } else {
    return await (client as V1Client).joinMeeting({
      meeting_url: meetingUrl,
      bot_name: botName,
      reserved: true
    });
  }
}

Breaking Changes

1. Parameter Changes

Some parameters have been removed or renamed:

// v1: 'reserved' parameter
await v1Client.joinMeeting({
  meeting_url: "...",
  bot_name: "Bot",
  reserved: true  // ❌ Not available in v2
});

// v2: No 'reserved' parameter
await v2Client.createBot({
  meeting_url: "...",
  bot_name: "Bot"
  // All bots are effectively "reserved" in v2
});

2. Response Data Structure

Response data structures may differ:

// v1 response
{
  success: true,
  data: {
    bot_id: "123",
    status_changes: [...],
    // ... other fields
  }
}

// v2 response
{
  success: true,
  data: {
    bot_id: "123",
    status: "joining",
    created_at: "2024-01-01T00:00:00Z",
    // ... different fields
  }
}

3. Error Handling

Error handling is fundamentally different:

// v1: Check error type
if (!result.success) {
  if (result.error instanceof ZodError) {
    // Validation error
  } else {
    // API error
  }
}

// v2: Use error code
if (!result.success) {
  switch (result.code) {
    case "INVALID_MEETING_URL":
      // Handle invalid URL
      break;
    case "RATE_LIMIT_EXCEEDED":
      // Handle rate limit
      break;
    default:
      // Handle other errors
  }
}

Testing Strategy

Parallel Testing

Test v2 alongside v1:

describe("Bot creation", () => {
  it("should work with v1 API", async () => {
    const result = await v1Client.joinMeeting({
      meeting_url: testUrl,
      bot_name: "Test Bot",
      reserved: true
    });

    expect(result.success).toBe(true);
  });

  it("should work with v2 API", async () => {
    const result = await v2Client.createBot({
      meeting_url: testUrl,
      bot_name: "Test Bot"
    });

    expect(result.success).toBe(true);
  });
});

Shadow Mode

Run v2 API calls without affecting production:

async function createBot(meetingUrl: string, botName: string) {
  // Production: v1
  const v1Result = await v1Client.joinMeeting({
    meeting_url: meetingUrl,
    bot_name: botName,
    reserved: true
  });

  // Shadow: v2 (for testing)
  v2Client.createBot({
    meeting_url: meetingUrl,
    bot_name: botName
  }).then(v2Result => {
    // Log for comparison
    console.log("v2 shadow result:", v2Result);
  }).catch(err => {
    console.error("v2 shadow error:", err);
  });

  return v1Result;
}

Checklist

  • Update client configuration to use v2
  • Replace joinMeeting() with createBot()
  • Replace leaveMeeting() with stopBot()
  • Replace getMeetingData() with getBot()
  • Update error handling to use structured errors
  • Remove reserved parameter from bot creation
  • Update webhook handlers to use v2 types
  • Test all bot operations with v2 API
  • Update monitoring/logging for v2 error codes
  • Update documentation for your team

Common Issues

Issue: TypeScript errors after migration

Solution: Ensure you're using the correct client type:

import { createBaasClient } from "@meeting-baas/sdk";

// TypeScript infers correct type based on api_version
const v2Client = createBaasClient({
  api_key: "key",
  api_version: "v2"
});

// Only v2 methods available
v2Client.createBot({ ... }); // ✅
v2Client.joinMeeting({ ... }); // ❌ Type error

Issue: Different error handling

Solution: Use adapter pattern:

function normalizeError(error: any) {
  if (error instanceof ZodError) {
    // v1 validation error
    return {
      code: "VALIDATION_ERROR",
      message: error.errors[0]?.message || "Validation failed"
    };
  }

  if (error.code && error.statusCode) {
    // v2 error
    return {
      code: error.code,
      message: error.error
    };
  }

  // v1 API error
  return {
    code: "UNKNOWN_ERROR",
    message: error.message
  };
}

On this page