---
title: "Customising calendar event templates"
url: "https://docs.pexipengage.com/en/administrators/calendar-event-templates"
description: "Change the title and content of the calendar events that Agents and customers receive for appointments and listings"
---

When an appointment is booked, Pexip Engage adds a calendar event to the calendars of the people involved. The event also appears in the **Add to calendar** links (Google Calendar, Outlook and iCal) that customers receive. As an Administrator, you can change the title and content of these events.

## Available templates

There are three calendar event templates. Each one has its own **Title** and **Content**.

| Context | Receiver | Used for |
| --- | --- | --- |
| Appointment | Employee | The event in the calendar of the Agents attending the appointment |
| Appointment | Customer | The event the customer and other participants add to their calendar |
| Listing | Employee | The event in an Agent’s calendar for a listing time slot |

You can’t create a separate template for each subject or meeting type. To show different content for, say, video and office meetings, use conditions inside the template (see [Showing content conditionally](#showing-content-conditionally)).

> You can’t change the location of the event. Pexip Engage sets it automatically: the office address for office meetings, the address the customer entered for meetings on location, and the video link for accepted video meetings. Phone meetings have no location.

## Editing a template

1.  Go to **Settings** > **Templates**.
    
2.  Select a template with the type **Calendar event template**.
    
3.  On the **Edit** tab, turn on **Customized**. Until you do, the default template is used and the fields can’t be edited.
    
4.  Change the **Title** and **Content**.
    
5.  Click **Save**.
    

Templates marked **Customized** in the list use your version. To go back to the default template, turn off **Customized** and click **Save**.

> Saving changes to a customized template makes it live immediately. Try out changes in a staging environment first.

## Previewing a template

Select the **Preview** tab to see the event filled with example data. You can switch between:

| Option | Description |
| --- | --- |
| Office, On location, Phone, Video | Icon buttons that show the event for each meeting type. Only the meeting types your organisation uses appear |
| View as primary participant / View as additional participant | Icon buttons that show the event as the main participant or an extra participant |
| Language list | Show the event in the selected language |

Hover over an icon button to see its name.

> Check the preview before saving. If a template has a mistake, such as a misspelled field name, that part stays empty in the event instead of showing an error.

## Template syntax

Templates use [Handlebars](https://handlebarsjs.com/guide/). You add appointment data to the template by placing a field name between curly braces:

```
{{{appointment.primaryCustomer.fullName}}} - {{{appointment.subject.name.value}}}
```

-   Use three braces, `{{{ }}}`, to show the value as it is. With two braces, `{{ }}`, characters such as `&` and `'` are encoded, which can look wrong in some calendars.
-   The content is plain text. Line breaks are kept, but HTML and formatting are not shown as formatting.
-   Text fields that can be translated, such as subject names and descriptions, end in `.value`: `{{{appointment.subject.name.value}}}`.

## Available fields

### In all templates

| Field | Description |
| --- | --- |
| enterprise.name | Your organisation’s name |
| enterprise.logoUrl | Link to your organisation’s logo |
| enterprise.termsAndConditionsUrl | Link to your terms and conditions |
| language | Language of the person receiving the event, such as en |
| timeZone | Time zone of the person receiving the event |
| receiver.fullName, receiver.firstName, receiver.lastName | Name of the person receiving the event |
| receiver.email, receiver.phoneNumber | Contact details of the person receiving the event |
| receiver.type | EMPLOYEE or CUSTOMER |

### Appointment

| Field | Description |
| --- | --- |
| appointment.start, appointment.end | Start and end time (use with the date helper) |
| appointment.duration | Duration in minutes, as a number such as 30 |
| appointment.meetingType | OFFICE, PHONE, VIDEO or ON_LOCATION |
| appointment.status | Status of the appointment |
| appointment.externalId | Your reference for the appointment |
| appointment.messageForCustomer | Message for the customer |
| appointment.internalNotes | Internal notes (only show these in the Employee template) |
| appointment.metadata | Extra data added to the appointment by an integration |
| appointment.subject.name.value | Subject name |
| appointment.subject.description.value | Subject description |
| appointment.subject.instructions.value | Subject instructions |
| appointment.subject.subjectGroup.name.value | Subject group name |
| appointment.office.name.value | Office name |
| appointment.office.email, appointment.office.phoneNumber | Office contact details |
| appointment.office.directions.value | Directions to the office |
| appointment.office.parkingInfo.value | Parking information |
| appointment.office.location.formattedAddress | Office address |
| appointment.location.formattedAddress | Address for meetings on location |
| appointment.leadSegment.code, appointment.leadSegment.description | Lead segment |

### Agent: `appointment.primaryEmployee`

| Field | Description |
| --- | --- |
| fullName, firstName, lastName | Name |
| email | Email address |
| communicationEmail | Email address used for communication |
| phoneNumber | Phone number |
| function.value | Job title |
| description.value | Profile description |
| profilePictureUrl | Link to the profile picture |
| staticVideoUrl | Personal video meeting link |
| externalId | Your reference for the Agent |
| language, timeZone | Language and time zone |

For example: `{{{appointment.primaryEmployee.function.value}}}`.

### Customer: `appointment.primaryCustomer`

| Field | Description |
| --- | --- |
| fullName, firstName, lastName | Name |
| email | Email address |
| phoneNumber | Phone number |
| company | Company |
| customerNumber | Customer number |
| notes | Notes about the customer |
| location.formattedAddress | Address |
| existing | Whether the customer is an existing customer |
| externalId | Your reference for the customer |
| language, timeZone | Language and time zone |

### Participants

| Field | Description |
| --- | --- |
| appointment.appointmentParticipants | List of everyone taking part in the appointment |
| appointment.secondaryAppointmentParticipants | List of additional participants |

Each participant in these lists has `participant.fullName`, `participant.email`, `participant.phoneNumber` and `role` (`PRIMARY` or `SECONDARY`).

### Links for the person receiving the event

| Field | Description |
| --- | --- |
| receiver.links.videoUrl | Link to join the video meeting |
| receiver.links.destinationVideoUrl | Direct link to the video meeting. Falls back to videoUrl. The default Employee template uses this link |
| receiver.links.videoTestUrl | Link to test audio and video before the meeting |
| receiver.links.pluginEditUrl | Link to reschedule the appointment |
| receiver.links.pluginCancelUrl | Link to cancel the appointment |
| receiver.links.pluginDeclineUrl | Link to decline the appointment |
| receiver.links.pluginInviteUrl | Link to invite other participants |
| receiver.links.googleCalendarUrl | Link to add the appointment to Google Calendar |
| receiver.links.office365CalendarUrl | Link to add the appointment to Outlook |
| receiver.links.icalUrl | Link to download the appointment as an iCal file |
| receiver.links.backofficeAppointmentDetailUrl | Link to the appointment in the backoffice (for Agents) |

These links are only available when the person receiving the event takes part in the appointment.

### Questionnaire answers: `appointment.answers`

Each answer has `question.label.value` (the question), `value` (the answer), `selectedAnswerOptions` (the chosen options, each with `label.value`) and `files` (uploaded files, each with `originalFileName`).

### Listing

| Field | Description |
| --- | --- |
| listingTimeSlot.start, listingTimeSlot.end | Start and end time of the time slot |
| listingTimeSlot.bookable | Whether the time slot can be booked |
| listingTimeSlot.isExclusiveForReceiver | Whether the time slot is only for this Agent |
| listingTimeSlot.listing.name.value | Listing name |
| listingTimeSlot.listing.description.value | Listing description |
| listingTimeSlot.listing.location.formattedAddress | Listing address |
| listingTimeSlot.listing.active | Whether the listing is active |

## Showing content conditionally

Use `{{#if}}` to show content only when a field has a value, and `{{else}}` for an alternative:

```
{{#if appointment.primaryCustomer.company}}  Company:  {{{appointment.primaryCustomer.company}}}{{/if}}
```

Use `{{#each}}` to repeat content for each item in a list. Inside the loop, `this` is the current item:

```
{{#if appointment.secondaryAppointmentParticipants.length}}  Additional participants:  {{#each appointment.secondaryAppointmentParticipants}}    -    {{{this.participant.fullName}}}    {{this.participant.email}}  {{/each}}{{/if}}
```

The following helpers are available:

| Helper | Example | Description |
| --- | --- | --- |
| if / else | {{#if appointment.internalNotes}}…{{else}}…{{/if}} | Show content when a value is present |
| unless | {{#unless @last}}, {{/unless}} | Show content when a value is missing |
| each | {{#each appointment.answers}}…{{/each}} | Repeat content for each item; @last is true for the last item |
| eq / neq | {{#if (eq appointment.meetingType "VIDEO")}}…{{/if}} | Check whether two values are equal or different |
| and / or | {{#if (or appointment.internalNotes appointment.metadata)}}…{{/if}} | Combine exactly two conditions |
| includes | {{#if (includes appointment.meetingType "OFFICE" "ON_LOCATION")}}…{{/if}} | Check whether a value is one of several options |
| date | {{date appointment.start "EEEE d MMMM yyyy, HH:mm"}} | Format a date in the receiver’s language and time zone, using date-fns format codes |
| concat | {{concat appointment.office.name.value " - " appointment.subject.name.value}} | Join text together |
| encodeUrl | https://example.com/{{encodeUrl appointment.office.name.value}} | Make text safe to use in a link. Characters such as &, ?, = and # are not encoded |
| year | {{year}} | The current year |
| translate | {{{translate 'appointment.employee.title'}}} | Show a standard text in the receiver’s language (see below) |
| mapObjectToTopLevelProperties | {{#each (mapObjectToTopLevelProperties appointment.metadata)}}{{this.key}}: {{this.value}}{{/each}} | List each item in the metadata |

## Translating template text

There is one template for all languages. Each event is shown in the language of the person receiving it.

The `translate` helper shows a standard text in the receiver’s language. The default templates use these texts:

| Key | English text |
| --- | --- |
| global.how | How |
| global.subject | Subject |
| global.description | Description |
| global.yes / global.no | yes / no |
| appointment.actions.view | View appointment |
| appointment.meetingTypes.office.title | A meeting at our office. |
| appointment.meetingTypes.onLocation.title | A meeting at a location you chose. |
| appointment.meetingTypes.phone.title | A phone meeting. |
| appointment.meetingTypes.video.title | A video meeting. |
| appointment.meetingTypes.video.joinMeeting | Join the meeting |
| appointment.customer.title | Customer details |
| appointment.employee.title | Your contact |
| appointment.internalNotes.title | Internal notes |
| appointment.metadata.title | Metadata |
| appointment.questionnaire.title | Questionnaire |
| appointment.secondaryParticipants.title | Additional participants |
| listing.title | Title |
| listing.description | Description |
| listing.locationDescription | Location description |
| listing.isListingActive | Is listing active? |
| listing.isExclusiveForYouAsEmployee | Is exclusive for you as contact? |
| listing.isTimeSlotBookable | Is time slot bookable? |

These texts are available in English, Dutch, French, German, Danish and Norwegian.

To use your own wording, you have two options:

-   **Write the text in the template.** To show different text per language, check the `language` field:
    
    ```
    {{#if (eq language "nl")}}Uw contactpersoon{{else if (eq language "fr")}}Votre contact{{else}}Your  contact{{/if}}
    ```
    
-   **Change the standard texts.** Contact support with the texts you want to use, and we’ll replace the standard texts for you.
    

## Example

This title shows the subject and the Agent’s name, and the content adds the date and a join link for video meetings:

**Title**

```
{{{appointment.subject.name.value}}} with {{{appointment.primaryEmployee.fullName}}}
```

**Content**

```
{{date appointment.start "EEEE d MMMM, HH:mm"}}
{{#if (eq appointment.meetingType "VIDEO")}}  {{{translate "appointment.meetingTypes.video.joinMeeting"}}}:  {{{receiver.links.videoUrl}}}{{/if}}
{{{translate "appointment.employee.title"}}}:{{{appointment.primaryEmployee.fullName}}}{{#if appointment.primaryEmployee.function}}{{{appointment.primaryEmployee.function.value}}}{{/if}}{{appointment.primaryEmployee.email}}
Need to change your appointment?{{{receiver.links.pluginEditUrl}}}
{{#if appointment.answers.length}}{{{translate "appointment.questionnaire.title"}}}:
  {{#each appointment.answers}}{{#if      (eq this.answerType "SUBJECT_QUESTIONNAIRE")    }}{{this.question.label.value}}      {{#if (includes this.question.inputType "SELECT" "MULTI_SELECT")}}{{#each          this.selectedAnswerOptions        }}{{this.label.value}}{{#unless @last}}, {{/unless}}{{/each}}{{else if        (includes this.question.inputType "FILE" "MULTI_FILE")      }}{{#each this.files}}{{this.originalFileName}}{{#unless @last}},          {{/unless}}{{/each}}{{else}}{{this.value}}{{/if}}
    {{/if}}{{/each}}{{/if}}
{{{translate "appointment.metadata.title"}}}:{{#each (mapObjectToTopLevelProperties appointment.metadata)}}{{this.key}}:  {{this.value}}{{/each}}
```