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 Method | v2 Method | Notes |
|---|---|---|
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()withcreateBot() - Replace
leaveMeeting()withstopBot() - Replace
getMeetingData()withgetBot() - Update error handling to use structured errors
- Remove
reservedparameter 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 errorIssue: 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
};
}