New plugin

We are building a brand new plugin (currently in tech preview). Want to try it out? Click here.

Basic implementation

The Skedify plugin works by executing javascript on the page. Upon initialization, it instantiates a SkedifyPluginInstance inside every block-level element that has a skedify-plugin class set on it. To communicate with the Skedify API, every SkedifyPluginInstance needs a client-id or an access token. These can be set by configuring a html attribute: skedify:oauth.client or skedify:oauth.token.

<head>
  ...
  <link type="text/css" rel="stylesheet" href="https://plugin.skedify.io/senso/SkedifyPlugin.css" />
</head>
<div
  class="skedify-plugin"
  id="skedify-plugin-wrapper"
  skedify:language="nl-BE"
  skedify:customer.timezone="Europe/Brussels"
  skedify:oauth.client="MS4yGE5riR3jnvYBRHjebJMJSO99BxDaO04BnpNA"
>
  <script src="https://plugin.skedify.io/senso/skedify-plugin.js" defer></script>
</div>
After window.Skedify.Plugin has been resolved, it's possible to manually re-initiate the plugin by calling:
const pluginElement = document.querySelector("#skedify-plugin-wrapper");
window.Skedify.Plugin(pluginElement);

Configuration

The plugin can be configured to behave in a certain way or have some values prefilled. You can do this by adding extra attributes.

oauth.client
The client-ID of the plugin. This ID is provided to you by your Skedify contact.
oauth.token
The bearer token used by the plugin. This token represents the contact.
oauth.resource_code
A resource_code of an existing appointment. This will allow you to complete or change an appointment. This parameter is mostly used by redirects from external sources (e.g. e-mails) and should usually not be provided manually.
session
This parameter is used for tracking events inside the plugin.
session.status
Used to enable/disable tracking of events in the plugin for insights about conversion. Possible values are:
  • default (enabled)
  • disabled
session.id
Pass your own custom session ID.
session.source_tags
Pass source tags seperated with a semi-colon.
customer
This parameter is used for prefilling the customer
customer.timezone
Default timezone to be used for the customer, this overwrites the guess that is being done as to what timezone the customer should be in.
customer.first_name
This prefills the first name in the contact information of the customer.
customer.last_name
This prefills the last name in the contact information of the customer.
customer.email
This prefills the email in the contact information of the customer.
customer.phone_number
This prefills the phone number in the contact information of the customer.
customer.customer_number
This prefills the customer number in the contact information of the customer.
appointment.subject_id
A (Skedify-internal) subject-ID. This allows a subject to be preselected. This option is ignored when oauth.resource_code is provided. This parameter can not be used together with the external_subject_id parameter.
external_subject_id
A subject-ID. This allows a subject to be preselected. This option is ignored when oauth.resource_code is provided. This parameter can not be used together with the appointment.subject_id parameter.
appointment.listing_id
Only available when your enterprise is using Skedify’s listings functionality. A Listing ID. This allows to filter subjects on a Listing. This option is ignored when oauth.resource_code is provided. This parameter can not be used together with the external_listing_id parameter.
external_listing_id
Only available when your enterprise is using Skedify’s listings functionality. A Listing ID. This allows to filter subjects on a Listing. This option is ignored when oauth.resource_code is provided. This parameter can not be used together with the appointment.subject_id parameter.
lead_segment_code
A Lead Segment Code. This allows a subject to be preselected matching the lead segment code.
appointment.office_id
A (Skedify-internal) office-/office-ID. This allows an office to be preselected. This option is ignored when oauth.resource_code is provided. This parameter can not be used together with the external_office_id parameter.
external_office_id
An office-/office-ID. This allows an office to be preselected. This option is ignored when oauth.resource_code is provided. This parameter can not be used together with the appointment.office_id parameter.
hints.intent
The suspected intent of the customer. Possible values are schedule, reschedule, invite, edit, cancel. This parameter is mostly used by redirects from external sources (e.g. e-mails) and should usually not be provided manually.
hints.contacts
A space-separated list of (Skedify-internal) contact-IDs. This makes the plugin favor choice options that are associated with at least one of the provided contacts.
hints.external_employee_ids
A space-separated list of (external) employee-IDs. This makes the plugin favor choice options that are associated with at least one of the provided external IDs.
language
An RFC 5646-compatible language tag. This will cause the plugin to be displayed in the specified language, unless the language is unavailable. In that case, a best-effort fallback will be performed with increasingly more generic variants of the specified language or finally 'en' if no variants of the specified language are available.
meeting_types
Possible values are office, phone, video, on_location.
application.scroll
Used to change the scrolling behaviour inside the plugin. Currently only possible to disable the initial scrolling when the plugin loads. Possible values: disable_initial_scroll_on_schedule, default.
application.timezone_selection
Used to enable timezone selection when the meeting type is video or phone. Possible values: enable_timezone_selection, disable_timezone_selection. The default is disable_timezone_selection.
application.timezone_selection
Used to enable timezone selection when the meeting type is video or phone. Possible values: enable_timezone_selection, disable_timezone_selection. The default is disable_timezone_selection.
location
This parameter is used for prefilling the location search step, so that offices are already scoped to this location. When location is passed, both geolocation & formatted_address are required.
location.formatted_address
The textual representation of the location.
location.geolocation
Latitude & longitude in the following format lat;lng
location.city
Textual representation of the city.
location.country
Textual representation of the country code (for example: BE).
location.postal_code
Textual representation of the postal code.
location.state
Textual representation of the state.
location.street_1
Textual representation of the street name & number.
search.country
The country that should be used for searching locations. Should be a two letter ISO 3166-1 country code. You can repeat that parameter up to 5 times to provide more countries.
flow
A sequence of characters that indicates the order of steps to be shown. The following characters are supported:
  • S: Subject. The step that allows the customer to pick a subject.
  • O: Office. The step that allows the customer to pick an office.
  • E: Employee. The step that allows the customer to pick an employee.
  • T: Timetable. The step that allows the customer to suggest one or more time slots for their appointment.
  • Q: Questions. The step that allows the customer to answer any addition questions specific to the chosen subject.
  • C: Customer. The step that allows the customer to provide his/her contact information.
  • ': [start]. Indicate the first step that should be shown is the first one following this character.
  • #: [locked]. Indicate that the step is locked and can not be edited. This means that a value must be provided.

Currently, the following constraints must always be met:
  • The following characters must always be present: T, Q, C.
  • No other characters than those listed above may be used.
  • When S is not present, it is mandatory that an external mechanism will provide the appointment.subject_id or external_subject_id configuration option instead.
  • When O is not present, it is mandatory that an external mechanism will provide the appointment.office_id or external_office_id configuration option instead.
  • If S or O are present, they can never occur at a position after T.
  • If S is present, it can never occur at a position after Q.
  • If the start character ( ') is present, it can never occur at a position after T. If the start character is ommitted, it will be assumed that the first character also specifies the first step to be shown.
By default the value 'SOTQC will be assumed. This will be the case if no value was provided or if the provided value fails these constraints.
<div
  class="skedify-plugin"
  id="skedify-plugin-wrapper"
  skedify:appointment.office_id="<office-id here>"
  skedify:appointment.subject_id="<subject-id here>"
  skedify:flow="S'TQC"
  skedify:language="nl-BE"
  skedify:customer.timezone="Europe/Brussels"
  skedify:oauth.client="MS4yGE5riR3jnvYBRHjebJMJSO99BxDaO04BnpNA"
>
  <script src="https://plugin.skedify.io/senso/skedify-plugin.js" defer></script>
  <!-- Insert a fallback for when the plugin fails here, for example: -->
  <!--
    <p class="enterprise-fallback">
    U kunt momenteel geen afspraak maken via deze module. Probeer binnen enkele minuten opnieuw of neem contact op via
    <a href="mailto:contact@example.com">e-mail</a> of telefonisch op
    <a href="tel:0032800000000">0800 00 00 00</a>.
  </p>
  -->

  <!-- <a href="skedify.me" style="color:transparent;font-size:1pt;letter-spacing:-3.5pt;cursor:default;">
    scheduling software</a> -->
</div>

Passing parameters via URL

A subset of parameters can also be passed via the hash-part of the URL.
rco
Maps to parameter oauth.resource_code (see above).
sub
Maps to parameter appointment.subject_id (see above).
esb
Maps to parameter external_subject_id (see above).
lis
Maps to parameter appointment.listing_id (see above).
eli
Maps to parameter appointment.external_listing_id (see above).
lsc
Maps to parameter lead_segment_code (see above).
off
Maps to parameter appointment.office_id (see above).
eof
Maps to parameter external_office_id (see above).
act
Maps to parameter hints.intent (see above).
con
An array of contact-IDs. This parameter has the same effect as hints.contacts (see above).
eco
An array of external employee-IDs. This parameter has the same effect as hints.external_employee_ids (see above).
sco
Maps to parameter search.country (see above).
flo
Maps to parameter flow (see above).
mty
Maps to parameter meeting_types (see above).
scr
Maps to parameter application.scroll (see above).
ets
Maps to parameter application.timezone_selection (see above).
lng
Maps to parameter language (see above).
session
Maps to parameter session (see above).
cas
Maps to parameter session.status (see above).
sid
Maps to parameter session.id (see above).
sst
Maps to parameter session.source_tags (see above).
customer
Maps to parameter customer (see above).
ctz
Maps to parameter customer.timezone (see above).
cfn
Maps to parameter customer.first_name (see above).
cln
Maps to parameter customer.last_name (see above).
cem
Maps to parameter customer.email (see above).
cpn
Maps to parameter customer.phone_number (see above).
ccn
Maps to parameter customer.customer_number (see above).
location
Maps to parameter location (see above).
lfa
Maps to parameter location.formatted_address (see above).
lgl
Maps to parameter location.geolocation (see above).
lci
Maps to parameter location.city (see above).
lco
Maps to parameter location.country (see above).
lpc
Maps to parameter location.postal_code (see above).
lsa
Maps to parameter location.state (see above).
lst
Maps to parameter location.street_1 (see above).

To prevent naming collisions with parameters of the containing website, Skedify chose to encode these parameters. To provide parameters, insert 'skedify' + encoded_params into the hash part of the URL, making sure the first character following that is not an alpha-numeric character. An implementation for encoding the parameters is made available by Skedify and as a package on NPM.

/* eslint-disable */
const skedify_params_to_encode = {
  sub: "subject_id_1",
  flo: "'SOTQC",
};

const encoded_params = Skedify.encodeURIParameters(skedify_params_to_encode);
// skedify_params_to_encode ~= Skedify.decodeURIParameters(encoded_params);

document.location.replace(
  "http://example.com/page-containing-plugin" + "#skedify" + encoded_params
);
// URL should now be 'http://example.com/page-containing-plugin#skedifyeyJzdWIiOiJzdWJqZWN0X2lkXzEiLCJmbG8iOiInU0xUUUMifQg'

JavaScript API

The Skedify plugin also offers a Javascript API. Upon initialisation, it registers one global object in the window scope: Skedify.Plugin. This object implements the following SkedifyPlugin interface.

[interface] Skedify.Plugin: {
  /**
   * EVENT TYPES
   */
  [constant] EVENT_INIT,                                                // This event is triggered when the Skedify.Plugin global is registered.
  [constant] EVENT_CREATION,                                            // This event is triggered when an instance of Skedify.Plugin was created.
  [constant] EVENT_MISCONFIGURED,                                       // This event is triggered when an URL- or DOM-style initialisation was not properly configured.
  [constant] EVENT_ERROR,                                               // This event is triggered when a fatal error occurred within a plugin instance.
  [constant] EVENT_APPOINTMENT_CREATED,                                 // This event is triggered when an appointment request was made.
  [constant] EVENT_APPOINTMENT_EDITED,                                  // This event is triggered when an appointment was edited.
  [constant] EVENT_APPOINTMENT_CANCELLED,                               // This event is triggered when an appointment was cancelled.

  /**
   * EVENT SUBTYPES
   */
  // Misconfigured sub types
  [constant] MISCONFIGURED_SUBJECT_ID,                                  // Subtype of `EVENT_MISCONFIGURED`. Set if the cause of a misconfiguration was an invalid subject_id.
  [constant] MISCONFIGURED_OFFICE_ID,                                 // Subtype of `EVENT_MISCONFIGURED`. Set if the cause of a misconfiguration was an invalid office_id.
  [constant] MISCONFIGURED_RESOURCE_CODE,                               // Subtype of `EVENT_MISCONFIGURED`. Set if the cause of a misconfiguration was an invalid resource_code.
  [constant] MISCONFIGURED_CLIENT_ID,                                   // Subtype of `EVENT_MISCONFIGURED`. Set if the cause of a misconfiguration was an invalid client_id.
  [constant] MISCONFIGURED_INTENT_WITHOUT_RESOURCE_CODE,                // Subtype of `EVENT_MISCONFIGURED`. Set if a requested intent is only allowed for appointment contexts, but no resource_code was provided.

  // Error sub types
  [constant] ERROR_API_DOWN,                                            // Subtype of `EVENT_ERROR`. Set if the API unexpectedly cannot respond to a request that is necessary for the plugin to function correctly.

  /**
   * Intents
   */
  [constant] INTENT_SCHEDULE,                                           // Can be provided to hint.intent to indicate intent to schedule an appointment
  [constant] INTENT_RESCHEDULE,                                         // Can be provided to hint.intent to indicate intent to reschedule an appointment
  [constant] INTENT_INVITE,                                             // Can be provided to hint.intent to indicate intent to invite a customer to schedule an appointment
  [constant] INTENT_EDIT,                                               // Can be provided to hint.intent to indicate intent to edit an appointment
  [constant] INTENT_CANCEL,                                             // Can be provided to hint.intent to indicate intent to cancel an appointment

  getInstance(index /* 0-based */: int): SkedifyPluginInstance,         // Get one of the instances
  count: int,                                                           // The current amount of instances

  version: string,                                                      // Semver version number

  [alias] dispose,                                                      // Alias to getInstance(0).dispose
  [alias] addEventListener,                                             // Alias to getInstance(0).addEventListener
  [alias] customer,                                                     // Alias to getInstance(0).customer
  [alias] appointment,                                                  // Alias to getInstance(0).appointment
  [alias] hints                                                         // Alias to getInstance(0).hints
}

Skedify.Plugin(DOMElement, { ...options })                              // Factory function to create a plugin instance.
  // DOMElement: Is the element in which the plugin will be rendered
  //             (Can contain any of the supported option attributes).
  // Options:    Can be any of the supported options.

  // E.g.:
  //   Skedify.Plugin(document.createElement('div'), {
  //     oauth: {
  //       client: 'your-id-here',
  //     },
  //   });

[interface] SkedifyPluginInstance: {
  dispose(),                                                            // Destroy the instance
  addEventListener(                                                     // Add an event listener
    /* [optional] */
    Skedify.Plugin.EVENT_*,
    /* [Callback] */
    function(event) {

    }
  ),
  [read-only] intention : string,                                       // The current intention
  customer: {                                                           // Provide known information about the customer
    [read-write] company : string,
    [read-write] customer_number : string,
    [read-write] email : string,
    [read-write] external_id : string,
    [read-write] first_name : string,
    [read-write] is_existing : boolean,
    [read-write] language : string,
    [read-write] last_name : string,
    [read-write] phone_number : string,
    [read-write] timezone : string,
  },
  appointment: {                                                        // Reads known information about the appointment
    [read-only] id: string,
    [read-only] location: {                                             // Reads information about the location of the appointment
      [read-only] id: string,
    },
    [read-only] meeting_type: string,                                   // Reads information about the meeting type of the appointment
    subject: {                                                          // Reads information about the subject of the appointment
      [read-only] id: string,
      [read-only] category_id: string,
    },
    meta: {                                                             // Store meta-information about the appointment (for your own use)
      // Keys and values must be JSON-serializeable
      get(key, defaultValue),                                           // Retrieve the value associated with the key, or retrieve the defaultValue if no value was present
      set(key, value),                                                  // Associate the value with the key
      remove(key),                                                      // Remove a key and its associated value
    }
  },
}

Other javascript on the page can be informed by the availability of the Skedify.Plugin global by listening on document for a SkedifyPluginEvent event using the native event handler functionality. Similarly, you can detect a plugin instance being created and hook specific event callbacks on that.

(function () {
  function initBindingWithSkedify(instance) {
    // You can listen for specific events
    instance.addEventListener(window.Skedify.Plugin.EVENT_APPOINTMENT_CREATED, function (event) {
      console.log("An appointment (request) was made.");
    });

    // You can listen for all events
    instance.addEventListener(function (event) {
      // any event for the instance will be caught
      // determine the type based on `event.detail.type`
      if (event.detail.type === window.Skedify.Plugin.EVENT_MISCONFIGURED) {
        console.log("The configuration provided to the instance was invalid");

        if (event.detail.subtype === window.Skedify.Plugin.MISCONFIGURED_SUBJECT_ID) {
          console.log("  the provided subject_id was invalid");
        } else if (event.detail.subtype === window.Skedify.Plugin.MISCONFIGURED_OFFICE_ID) {
          console.log("  the provided office_id was invalid");
        } else if (event.detail.subtype === window.Skedify.Plugin.MISCONFIGURED_RESOURCE_CODE) {
          console.log("  the provided resource_code was invalid");
        }
      } else if (event.detail.type === window.Skedify.Plugin.EVENT_ERROR) {
        console.log("The Skedify API is down, or an unexpected runtime exception occurred");
      }
    });
  }

  if (window.Skedify && window.Skedify.Plugin) {
    // If Skedify.Plugin is already available, use that instance.
    initBindingWithSkedify(window.Skedify.Plugin.getInstance(0));
  } else {
    // If the Skedify.Plugin is loaded async, we have to wait for an instance.
    document.addEventListener("SkedifyPluginEvent", function (event) {
      // every event will have a `event.detail.type` attribute, so different events can be distinguished.
      if (event.detail.type === window.Skedify.Plugin.EVENT_CREATION) {
        initBindingWithSkedify(event.detail.instance);
      }
    });
  }
})();