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. |
The HTTP client sends these fields inside a patch wrapper:
{
"patch": {
"title": "Updated meeting",
"summary": "Discuss next steps",
"startTimeUtc": "2026-10-26T12:00:00.000Z",
"durationMinutes": 60,
"contacts": [{ "id": "2288275906", "type": "contact" }]
}
}
Send startTimeUtc and durationMinutes together when changing the time. Omit
both for edits that only change other fields. The server continues to accept the
deprecated startTime input for older clients; current clients send startTimeUtc.
participantName, attendees, attendeeIds, contactId, and contactType are
display/response fields, not appointment patch fields. Use contacts for attendee
changes. Send a changed status through the separate status, confirm, or cancel
endpoint, rather than including status in the patch.
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
if (!hasCustomRange) {
return { appointments };
}
const rangeStart = moment.utc(range.startDate).startOf('day');
const rangeEnd = moment.utc(range.endDate).endOf('day');
if (!rangeStart.isValid() || !rangeEnd.isValid()) {
return { appointments };
}
return {
appointments: appointments.filter(appointment => {
if (!appointment.startTimeUtc) return false;
const appointmentStart = moment.utc(appointment.startTimeUtc);
return appointmentStart.isValid()
&& appointmentStart.valueOf() >= rangeStart.valueOf()
&& appointmentStart.valueOf() <= rangeEnd.valueOf();
})
};
}
async function createAppointment({ user, authHeader, payload }) {
const calendarId = await getWriteableUserCalendarId({ user, authHeader });
if (calendarId == null) {
return {
successful: false,
returnMessage: {
message: 'No writeable calendar found in Clio.',
messageType: 'warning',
ttl: 5000
}
};
}
const startAt = payload?.startTimeUtc ?? payload?.startTime ?? null;
const durationMinutes = Number(payload?.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 attendees = (() => {
if (Array.isArray(payload?.contacts) && payload.contacts.length) {
return payload.contacts
.map(c => (c && typeof c === 'object' ? toAttendee(c.id) : toAttendee(c)))
.filter(Boolean);
}
return [];
})();
const data = {
calendar_owner: { id: calendarId },
summary: payload?.title ?? payload?.summary ?? 'Appointment',
description: payload?.summary ?? '',
start_at: startAt,
end_at: endAt,
send_email_notification: false,
...(attendees.length ? { attendees } : {})
};
const body = { data };
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 hasPatchField = (field) => Object.prototype.hasOwnProperty.call(patchBody ?? {}, field);
const hasSupportedMutation = ['title', 'summary', 'startTimeUtc', 'startTime', 'contacts']
.some(hasPatchField);
if (hasPatchField('status') && !hasSupportedMutation) {
return {
successful: false,
returnMessage: {
message: 'Clio does not support appointment status changes.',