updateAppointment
This interface updates an existing appointment in the connected CRM. It is called when a user edits an appointment from within App Connect's appointment panel.
Input parameters
| Parameter | Description |
|---|---|
user |
An object describing the Chrome extension user associated with the action that triggered this interface. |
authHeader |
The HTTP Authorization header to be transmitted with the API request to the target CRM. |
appointmentId |
The CRM ID of the appointment to update. |
patchBody |
An object containing the fields to update. See Patch body schema. |
Patch body schema
| Property | Type | Description |
|---|---|---|
title |
string | New title for the appointment. |
summary |
string | New notes or body text. |
startTimeUtc |
string | Updated ISO-8601 UTC start time. |
durationMinutes |
number | Updated duration in minutes. |
contacts |
array | (Optional) Replacement list of attendee IDs or contact objects. When provided, existing attendees not in this list are removed. |
Return value(s)
An object with the following property:
| Parameter | Description |
|---|---|
appointment |
The full updated appointment object. |
If the appointment cannot be found or updated, return:
| Parameter | Description |
|---|---|
successful |
false |
returnMessage |
An object with message, messageType, and ttl. |
Example
return {
appointment: {
id: "12345",
thirdPartyAppointmentId: "12345",
title: "Updated intake call",
description: "Rescheduled",
startTimeUtc: "2024-03-16T10:00:00.000Z",
durationMinutes: 30,
status: "scheduled",
contactId: "",
attendees: []
}
};
Reference
const createRes = await axios.post(
`https://${user.hostname}/api/v4/calendar_entries.json`,
body,
{ headers: { 'Authorization': authHeader }, params: { fields: 'id,summary,description,start_at,end_at,attendees,external_properties,calendar_owner_id' } }
);
const calendarEntry = createRes?.data?.data ?? null;
const appointment = normalizeCalendarEntryToAppointment(calendarEntry);
return { appointmentId: appointment.id, appointment };
}
async function updateAppointment({ user, authHeader, appointmentId, patchBody }) {
const existing = await getCalendarEntryById({ user, authHeader, appointmentId });
if (!existing) {
return {
successful: false,
returnMessage: {
message: 'Appointment not found in Clio.',
messageType: 'warning',
ttl: 5000
}
};
}
const existingAttendees = existing?.attendees ?? [];
const startAt = patchBody?.startTimeUtc ?? patchBody?.startTime ?? null;
const durationMinutes = Number(patchBody?.durationMinutes ?? 0);
const endAt = startAt ? moment.utc(startAt).add(durationMinutes, 'minutes').toISOString() : null;
const toAttendee = (id) => {
const n = typeof id === 'number' ? id : Number(id);
if (!Number.isFinite(n)) return null;
return { id: n, type: 'Contact' };
};
const hasAttendeeUpdate = Array.isArray(patchBody?.contacts);
const attendees = (() => {
if (!hasAttendeeUpdate) return [];
const desiredAttendeeSource = patchBody.contacts;
const desiredAttendeeRefs = Array.isArray(desiredAttendeeSource) && desiredAttendeeSource.length
? desiredAttendeeSource
.map(c => {
if (c && typeof c === 'object') {
return toAttendee(c.id);
}
return toAttendee(c);
})
.filter(Boolean)
: [];
const desiredAttendeeIdSet = new Set(desiredAttendeeRefs.map(a => `${a.id}`));
const existingAttendeeRefs = (existingAttendees ?? [])
.map(a => {
if (a?.id == null) return null;
const n = typeof a.id === 'number' ? a.id : Number(a.id);
return { id: n, type: 'Contact' };
})
.filter(Boolean);
// Only remove (destroy) those existing attendees that are NOT in the desired list.
const removedAttendeeRefs = existingAttendeeRefs
.filter(a => !desiredAttendeeIdSet.has(`${a.id}`))
.map(a => ({ id: a.id, type: 'Contact', _destroy: true }));
const mergedAttendeeRefs = [...removedAttendeeRefs, ...desiredAttendeeRefs];
const seenKeys = new Set();
return mergedAttendeeRefs.filter(a => {
const key = `${a.id}:${a.type ?? 'Contact'}:${a._destroy ? '1' : '0'}`;
if (seenKeys.has(key)) return false;
seenKeys.add(key);
return true;
});
})();
const updateBody = {
data: {
summary: patchBody?.title ?? '',
description: patchBody?.summary ?? '',
start_at: startAt,