Skip to main content
Learn how to reschedule and cancel bookings programmatically.

Get Booking Details

Before modifying a booking, retrieve its current state:
const response = await fetch(
  `https://api.meetergo.com/v4/appointment/${appointmentId}`,
  {
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'x-meetergo-api-user-id': userId
    }
  }
);

const booking = await response.json();

Rescheduling

Check Availability for Reschedule

When rescheduling, pass the existing appointment ID to exclude the current slot from conflict checking:
const response = await fetch(
  `https://api.meetergo.com/v4/booking-availability?` + new URLSearchParams({
    meetingTypeId: booking.meetingTypeId,
    start: '2024-01-20',
    end: '2024-01-27',
    existingAppointmentId: appointmentId  // Excludes current booking from conflicts
  }),
  {
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'x-meetergo-api-user-id': userId
    }
  }
);

const { availableSlots } = await response.json();

Reschedule via Booking Endpoint

Create a new booking and cancel the old one:
async function rescheduleBooking(oldBookingId, newStart) {
  // 1. Get old booking details
  const oldBooking = await getBooking(oldBookingId);

  // 2. Create new booking
  const newBooking = await fetch('https://api.meetergo.com/v4/booking', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json',
      'x-meetergo-api-user-id': userId
    },
    body: JSON.stringify({
      meetingTypeId: oldBooking.meetingTypeId,
      start: newStart,
      hostIds: oldBooking.hosts.map(h => h.id),
      attendee: {
        email: oldBooking.attendees[0].email,
        fullname: oldBooking.attendees[0].fullname,
        phone: oldBooking.attendees[0].phone
      },
      // Link to original booking for tracking
      rescheduledFromId: oldBookingId
    })
  });

  // 3. Cancel old booking
  await cancelBooking(oldBookingId, 'Rescheduled to new time');

  return newBooking.json();
}

Cancellation

Cancel a Booking

await fetch(`https://api.meetergo.com/v4/appointment/${appointmentId}`, {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-meetergo-api-user-id': userId
  }
});

Cancel with Reason

Include cancellation reason for tracking:
await fetch(`https://api.meetergo.com/v4/appointment/${appointmentId}`, {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-meetergo-api-user-id': userId
  },
  body: JSON.stringify({
    reason: 'Customer requested cancellation',
    notifyAttendees: true
  })
});

Handling via Webhooks

React to reschedule and cancellation events:
app.post('/webhooks/meetergo', async (req, res) => {
  res.status(200).send('OK');

  const { event, data } = req.body;

  switch (event) {
    case 'booking_rescheduled':
      await handleReschedule(data);
      break;
    case 'booking_cancelled':
      await handleCancellation(data);
      break;
  }
});

async function handleReschedule(data) {
  const { rescheduledAppointment, oldStartDate, oldEndDate } = data;

  console.log(`Booking rescheduled from ${oldStartDate} to ${rescheduledAppointment.start}`);

  // Update your systems
  await db.bookings.update({
    where: { meetergoId: rescheduledAppointment.id },
    data: {
      start: rescheduledAppointment.start,
      end: rescheduledAppointment.end,
      rescheduledAt: new Date(),
      previousStart: oldStartDate
    }
  });

  // Update calendar
  await updateCalendarEvent(rescheduledAppointment);

  // Notify internal systems
  await notifyTeam('booking_rescheduled', rescheduledAppointment);
}

async function handleCancellation(data) {
  const { id, cancel } = data;

  console.log(`Booking ${id} cancelled: ${cancel?.reason || 'No reason'}`);

  // Update your systems
  await db.bookings.update({
    where: { meetergoId: id },
    data: {
      status: 'cancelled',
      cancelledAt: cancel?.cancelledAt || new Date(),
      cancellationReason: cancel?.reason
    }
  });

  // Remove from calendar
  await deleteCalendarEvent(id);

  // Free up resources
  await releaseResources(id);
}

No-Shows

Mark attendees who didn’t show up:
await fetch(`https://api.meetergo.com/v4/attendee/${attendeeId}/no-show`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-meetergo-api-user-id': userId
  }
});
Track no-shows for analytics:
async function handleNoShow(appointmentId, attendeeId) {
  // Mark as no-show in meetergo
  await fetch(`https://api.meetergo.com/v4/attendee/${attendeeId}/no-show`, {
    method: 'POST',
    headers
  });

  // Track in your analytics
  await db.bookings.update({
    where: { meetergoId: appointmentId },
    data: {
      status: 'no_show',
      noShowAt: new Date()
    }
  });

  // Update CRM
  await updateCrmContact(attendeeId, {
    lastNoShow: new Date(),
    noShowCount: { increment: 1 }
  });
}

Update Booking Notes

Add or update notes on a booking:
await fetch(`https://api.meetergo.com/v4/appointment/${appointmentId}/notes`, {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-meetergo-api-user-id': userId
  },
  body: JSON.stringify({
    notes: 'Customer mentioned they need accessibility accommodations'
  })
});

Add/Remove Guests

Add Guest Emails

await fetch(`https://api.meetergo.com/v4/appointment/${appointmentId}/guests`, {
  method: 'PATCH',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'x-meetergo-api-user-id': userId
  },
  body: JSON.stringify({
    guestEmails: ['[email protected]', '[email protected]']
  })
});

Remove Guest

await fetch(
  `https://api.meetergo.com/v4/appointment/${appointmentId}/guest/${encodeURIComponent(guestEmail)}`,
  {
    method: 'DELETE',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'x-meetergo-api-user-id': userId
    }
  }
);

Common Patterns

Generate a reschedule link for attendees:
function generateRescheduleLink(booking) {
  const baseUrl = 'https://cal.meetergo.com';
  const params = new URLSearchParams({
    reschedule: booking.id,
    email: booking.attendees[0].email
  });

  return `${baseUrl}/${booking.companySlug}/${booking.meetingTypeSlug}?${params}`;
}

// Send to attendee
const rescheduleLink = generateRescheduleLink(booking);
await sendEmail(booking.attendees[0].email, {
  subject: 'Need to reschedule?',
  body: `Click here to pick a new time: ${rescheduleLink}`
});

Cancellation with Refund

async function cancelWithRefund(appointmentId, refundReason) {
  // 1. Get booking with payment info
  const booking = await getBooking(appointmentId);

  // 2. Process refund if paid
  if (booking.payment?.status === 'paid') {
    await processRefund(booking.payment.id, refundReason);
  }

  // 3. Cancel the booking
  await fetch(`https://api.meetergo.com/v4/appointment/${appointmentId}`, {
    method: 'DELETE',
    headers,
    body: JSON.stringify({
      reason: refundReason,
      notifyAttendees: true
    })
  });
}

Bulk Cancellation

Cancel multiple bookings (e.g., host unavailable):
async function cancelBookingsInRange(userId, startDate, endDate, reason) {
  // 1. Get all bookings in range
  const response = await fetch(
    `https://api.meetergo.com/v4/appointment/paginated?` + new URLSearchParams({
      page: 1,
      pageSize: 100,
      userId: userId,
      startDate: startDate,
      endDate: endDate
    }),
    { headers }
  );

  const { appointments } = await response.json();

  // 2. Cancel each booking
  const results = await Promise.allSettled(
    appointments.map(apt =>
      fetch(`https://api.meetergo.com/v4/appointment/${apt.id}`, {
        method: 'DELETE',
        headers,
        body: JSON.stringify({ reason, notifyAttendees: true })
      })
    )
  );

  const cancelled = results.filter(r => r.status === 'fulfilled').length;
  console.log(`Cancelled ${cancelled} of ${appointments.length} bookings`);

  return results;
}

Best Practices

Always notify attendees - Set notifyAttendees: true for cancellations
Track reasons - Store cancellation/reschedule reasons for analytics
Handle webhooks idempotently - Same event may be delivered multiple times
Use existingAppointmentId - When checking availability for reschedule
Cancellation is permanent - There’s no undo; create a new booking if needed

Next Steps