Team Scheduling

Configure round-robin, collective, and pooled team events.

Overview

Team scheduling allows multiple hosts to share event types. Distribute meetings evenly, require all members, or let bookers choose their host.

Scheduling Types

TypeDescriptionUse Case
Round-RobinRotate between hostsSales demos, support calls
CollectiveAll hosts must attendPanel interviews, group reviews
ManagedBooker chooses hostClient preferences

Round-Robin Events

Automatically distribute bookings among team members.

Create Round-Robin Event

TypeScript:

const eventType = await client.calendar.eventTypes.create({
  title: 'Sales Demo',
  slug: 'demo',
  duration: 30,
  schedulingType: 'ROUND_ROBIN',
  hosts: [
    { userId: 'user_alice', isFixed: false },
    { userId: 'user_bob', isFixed: false },
    { userId: 'user_carol', isFixed: false },
  ],
  roundRobinConfig: {
    algorithm: 'LEAST_RECENT', // or 'AVAILABILITY_FIRST', 'EQUAL_DISTRIBUTION'
    weightByAvailability: true,
  },
});

Python:

event_type = client.calendar.event_types.create(
    title="Sales Demo",
    slug="demo",
    duration=30,
    scheduling_type="ROUND_ROBIN",
    hosts=[
        {"userId": "user_alice", "isFixed": False},
        {"userId": "user_bob", "isFixed": False},
        {"userId": "user_carol", "isFixed": False},
    ],
    round_robin_config={
        "algorithm": "LEAST_RECENT",
        "weightByAvailability": True,
    },
)

Distribution Algorithms

AlgorithmDescription
LEAST_RECENTAssign to host with oldest last booking
AVAILABILITY_FIRSTPrioritize hosts with most availability
EQUAL_DISTRIBUTIONBalance total bookings equally
PRIORITYFollow host priority order

Host Weights

Weight distribution for unequal loads:

const eventType = await client.calendar.eventTypes.create({
  title: 'Sales Demo',
  schedulingType: 'ROUND_ROBIN',
  hosts: [
    { userId: 'user_alice', weight: 3 },  // Gets 3x bookings
    { userId: 'user_bob', weight: 2 },    // Gets 2x bookings
    { userId: 'user_carol', weight: 1 },  // Gets 1x bookings
  ],
});

Fixed Hosts

Always include certain hosts:

const eventType = await client.calendar.eventTypes.create({
  title: 'Enterprise Demo',
  schedulingType: 'ROUND_ROBIN',
  hosts: [
    { userId: 'user_manager', isFixed: true },  // Always included
    { userId: 'user_alice', isFixed: false },   // Rotates
    { userId: 'user_bob', isFixed: false },     // Rotates
  ],
});

Collective Events

All specified hosts must be available and attend.

Create Collective Event

const eventType = await client.calendar.eventTypes.create({
  title: 'Panel Interview',
  slug: 'interview',
  duration: 60,
  schedulingType: 'COLLECTIVE',
  hosts: [
    { userId: 'user_hiring_manager' },
    { userId: 'user_tech_lead' },
    { userId: 'user_hr' },
  ],
  collectiveConfig: {
    requireAllHosts: true,
  },
});

Optional Attendees

Some hosts optional:

const eventType = await client.calendar.eventTypes.create({
  title: 'Design Review',
  schedulingType: 'COLLECTIVE',
  hosts: [
    { userId: 'user_lead', required: true },
    { userId: 'user_designer1', required: true },
    { userId: 'user_pm', required: false }, // Optional
  ],
  collectiveConfig: {
    minimumRequired: 2, // At least 2 must be available
  },
});

Managed Events (Booker Chooses)

Let the booker select their host.

Create Managed Event

const eventType = await client.calendar.eventTypes.create({
  title: 'Consultation',
  slug: 'consult',
  duration: 45,
  schedulingType: 'MANAGED',
  hosts: [
    {
      userId: 'user_alice',
      displayName: 'Alice Johnson',
      bio: 'Specializes in enterprise solutions',
      avatar: 'https://...',
    },
    {
      userId: 'user_bob',
      displayName: 'Bob Smith',
      bio: 'Expert in startups and SMBs',
      avatar: 'https://...',
    },
  ],
});

Get Host Availability

When booker selects a host:

// Get available hosts
const hosts = await client.calendar.eventTypes.getHosts(eventType.id);
 
// Get specific host availability
const availability = await client.calendar.availability.get({
  eventTypeId: eventType.id,
  hostId: 'user_alice',
  startDate: '2024-01-15',
  endDate: '2024-01-22',
});

Managing Team Members

Add Host

await client.calendar.eventTypes.addHost(eventType.id, {
  userId: 'user_new',
  weight: 1,
  isFixed: false,
});

Remove Host

await client.calendar.eventTypes.removeHost(eventType.id, 'user_leaving');

Update Host Settings

await client.calendar.eventTypes.updateHost(eventType.id, 'user_alice', {
  weight: 2,
  isFixed: true,
});

List Hosts

const hosts = await client.calendar.eventTypes.getHosts(eventType.id);
 
for (const host of hosts) {
  console.log(`${host.user.name}: ${host.weight}x weight`);
}

Host Availability

Individual Schedules

Each host can have their own schedule:

// Alice's schedule
const aliceSchedule = await client.calendar.schedules.create({
  userId: 'user_alice',
  name: 'Alice - Work Hours',
  availability: [
    { day: 'MONDAY', startTime: '09:00', endTime: '17:00' },
    // ...
  ],
});
 
// Bob's different schedule
const bobSchedule = await client.calendar.schedules.create({
  userId: 'user_bob',
  name: 'Bob - Work Hours',
  availability: [
    { day: 'MONDAY', startTime: '10:00', endTime: '18:00' },
    // ...
  ],
});

Combined Availability

For round-robin, availability is combined:

const availability = await client.calendar.availability.get({
  eventTypeId: eventType.id,
  startDate: '2024-01-15',
  endDate: '2024-01-22',
});
 
// Slots show when ANY host is available
for (const day of availability.days) {
  for (const slot of day.slots) {
    console.log(`${slot.startTime}: Available hosts: ${slot.availableHosts.join(', ')}`);
  }
}

Booking Assignment

Automatic Assignment

For round-robin, hosts are automatically assigned:

const booking = await client.calendar.bookings.create({
  eventTypeId: eventType.id,
  startTime: '2024-01-15T10:00:00-05:00',
  attendee: { name: 'John', email: 'john@example.com' },
  // Host automatically assigned based on algorithm
});
 
console.log('Assigned to:', booking.host.name);

Manual Assignment

Override automatic assignment:

const booking = await client.calendar.bookings.create({
  eventTypeId: eventType.id,
  startTime: '2024-01-15T10:00:00-05:00',
  attendee: { name: 'John', email: 'john@example.com' },
  hostId: 'user_alice', // Force specific host
});

Reassign Booking

await client.calendar.bookings.reassign(booking.uid, {
  newHostId: 'user_bob',
  reason: 'Original host out sick',
  notifyAttendee: true,
});

Team Analytics

Distribution Report

const report = await client.calendar.analytics.getTeamDistribution({
  eventTypeId: eventType.id,
  startDate: '2024-01-01',
  endDate: '2024-01-31',
});
 
for (const host of report.hosts) {
  console.log(`${host.name}:`);
  console.log(`  Bookings: ${host.totalBookings}`);
  console.log(`  Hours: ${host.totalHours}`);
  console.log(`  Completion rate: ${host.completionRate}%`);
}

Utilization

const utilization = await client.calendar.analytics.getUtilization({
  eventTypeId: eventType.id,
  startDate: '2024-01-01',
  endDate: '2024-01-31',
});
 
console.log('Team utilization:', utilization.overallRate);
for (const host of utilization.byHost) {
  console.log(`${host.name}: ${host.utilizationRate}% utilized`);
}

Out of Office

Handle host unavailability:

// Set out of office
await client.calendar.users.setOutOfOffice('user_alice', {
  startDate: '2024-02-01',
  endDate: '2024-02-05',
  reason: 'Vacation',
  reassignBookings: true, // Reassign existing bookings
  reassignTo: 'user_bob', // Or 'AUTO' for round-robin
});
 
// Clear out of office
await client.calendar.users.clearOutOfOffice('user_alice');

Notifications

Configure team notifications:

await client.calendar.eventTypes.update(eventType.id, {
  notifications: {
    hostNotifications: {
      newBooking: true,
      cancellation: true,
      reschedule: true,
      reminder: { enabled: true, minutesBefore: 30 },
    },
    teamNotifications: {
      // Notify all team members
      newBooking: false,
      cancellation: true, // Alert team to cancellations
    },
  },
});

Next Steps