Skip to content

timekit-io/js-sdk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Timekit JS SDK

Circle CI Code Coverage

Releases & changelog

Make API calls to Timekit with our easy-to-use JavaScript SDK. It supports all our endpoints as documented on https://reference.timekit.io/.

Visit timekit.io to learn more and don't hesitate to contact Lasse Boisen Andersen ([email protected] or create an Issue) for questions. PR's are more than welcome!

Features:

  • Supports API auth with both app keys and resource keys
  • Returns ES6/A+ style promises
  • Works in both node.js and in the browser (>=IE8 and evergreen)
  • Supports custom timestamp formats and timezones

Dependencies

The following libraries are bundled together with the SDK:

  • axios - a promise-based HTTP client for the browser (using XMLHttpRequests) and node.js (using http)
  • base64 - a robust base64 encoder/decoder, used for basic auth headers
  • humps - easy conversion from camelCase to snake_case and vice versa

Installation

The library is hosted on NPM, so you can simply go:  

npm install timekit-sdk --save

Module loading

The SDK is UMD (Universal Module Definition) compatible, which means that it can be loaded in various module formats across both browsers and server.

Note: Use plain or minified builds in /dist when using in browser. In node, /src/timekit.js will be used through npm (or reference it manually in your require)

ES6 module

import timekit from 'timekit-sdk'
console.log(timekit);

AMD (with e.g. require.js)

require(['timekit-sdk'], function(timekit) {
    console.log(timekit);
});

CommonJS2 (in e.g. node.js)

var timekit = require('timekit-sdk');
console.log(timekit);

As a global variable (in browsers)

<script src="timekit-sdk.js"></script>
<script>
    console.log(timekit);
</script>

See /examples for implementation examples.

Authentication

App key

Only for server-side integrations!

With app keys, your capabilities are scoped on an app-level which mean that you can access data (e.g. bookings) across all resources. It's essential that you only use this for server-side integrations as the key grants full access to your whole timekit app data.

timekit.configure({
  appKey: 'live_api_key_4cY2KWMggw95mAdx51eYUO2CyIWI2xup'
})

Your app key can be found in the Timekit admin panel (https://admin.timekit.io)

Resource keys

For client-side integrations!

Resource keys are scoped by the resource and the data that they have access to. The primary use-case is together with our booking.js widget that only acts as a single resource at a time.

Resource keys needs to be accompanied by the resource's email and the app attribute. Note that two types of keys exist: server-token and client-token, where only the latter should be used. Please refer to the API reference.

timekit.configure({
  app: 'back-to-the-future',
  resourceEmail: '[email protected]',
  resourceKey: '4cY2KWMggw95mAdx51eYUO2CyIWI2xup'
})

🚨 Important! Resource keys are being phased out as a supported authentication mechanism. We encourage you to use app keys for new Timekit integrations.

Usage (init)

The only required configuration is that you set the "app" key to your registered app slug on Timekit.

Here's all the available options:

// Overwrites default config with supplied object, possible keys with default values below
timekit.configure({
    apiBaseUrl:                 'https://api.timekit.io/',  // API endpoint (do not change)
    apiVersion:                 'v2',                       // version of API to call (do not change)
    inputTimestampFormat:       'Y-m-d h:ia',               // default timestamp format that you supply
    outputTimestampFormat:      'Y-m-d h:ia',               // default timestamp format that you want the API to return
    timezone:                   'Europe/Copenhagen',        // override user's timezone for custom formatted timestamps in another timezone
    convertResponseToCamelcase: false,                      // should keys in JSON response automatically be converted from snake_case to camelCase?
    convertRequestToSnakecase:  true,                       // should keys in JSON requests automatically be converted from camelCase to snake_case?
    autoFlattenResponse: true                               // if you keep this set to true, then responses with a "data" key will automatically be flattened to response.data (otherwise you need to access response.data.data). Pagination meta data can be found on response.metaData)
});

// Returns current config object
timekit.getConfig();

Usage (endpoints)

All the Timekit API endpoints are supported as methods. For endpoints taking parameters/data, the method argument should be an object with keys named as referenced in the docs - see: https://developers.timekit.io/reference/

If you supply keys as camelCased, they will automatically be converted to snake_case for you. Responses can also be converted to camelCase automatically if you set the config variable convertResponseToCamelcase to true.

Endpoints/methods:

// App endpoints
timekit.getApp()

// Resource endpoints
timekit.getResources()
timekit.getResource({ id })
timekit.createResource({ ... })
timekit.updateResource({ id, ... })
timekit.resetResourcePassword({ ... })
timekit.getResourceTimezone({ email })

// FindTime endpoints
timekit.findTime({ ... })
timekit.findTimeBulk({ ... })
timekit.findTimeTeam({ ... })

// Availability endpoints
timekit.fetchAvailability({ ... })
timekit.fetchUnAvailableSlots({ ... })
timekit.fetchAvailabilityDates({ ... })
timekit.fetchAvailabilityCounts({ ... })

// Booking endpoints
timekit.getBookings()
timekit.getBooking({ id })
timekit.createBooking({ ... })
timekit.createBookingsBulk({ ... })
timekit.updateBooking({ id, action, ... })
timekit.updateBookingsBulk({ ... })
timekit.deleteBooking({ id })
timekit.getGroupBookings()
timekit.getGroupBooking({ id })
timekit.rescheduleBooking({ id, ... })

// Account endpoints
timekit.getAccounts()
timekit.accountGoogleSignup({ callback }, shouldAutoRedirect)
timekit.accountGoogleSync()
timekit.accountMicrosoftSignup({ callback }, shouldAutoRedirect)
timekit.accountMicrosoftSync()

// Calendar endpoints
timekit.getCalendars()
timekit.getCalendar({ id })
timekit.createCalendar({ ... })
timekit.updateCalendar({ id, ... })
timekit.deleteCalendar({ id })

// Project endpoints
timekit.getProjects()
timekit.getProject({ id })
timekit.getHostedProject({ slug })
timekit.getEmbedProject({ id })
timekit.createProject({ ... })
timekit.updateProject({ id, ... })
timekit.deleteProject({ id })
timekit.getProjectResources({ id })
timekit.addProjectResource({ id, ... })
timekit.setProjectResources({ id, resources })
timekit.removeProjectResource({ id, resourceId })

// Event endpoints
timekit.getEvents({ ... })
timekit.getEvent({ id })
timekit.createEvent({ ... })
timekit.updateEvent({ id, ... })
timekit.deleteEvent({ id })

// Service endpoints
timekit.getServices({ ... })
timekit.getService({ id })
timekit.createService({ ... })
timekit.updateService({ id, ... })
timekit.deleteService({ id })

// Location endpoints
timekit.getLocations({ ... })
timekit.getLocation({ id })
timekit.createLocation({ ... })
timekit.updateLocation({ id, ... })
timekit.deleteLocation({ id })

// service location related endpoints
timekit.getServiceProjects(id)
timekit.getLocationProjects(id)
timekit.getLocationServiceProjects(locationUuid, serviceUuid)

// email template related endpoints
timekit.getEmailTemplates()
timekit.getEmailTemplate(slug)
timekit.updateEmailTemplate({ slug, ... })

// booking reservation
timekit.reserveBooking({ ... })
timekit.extendReservedBooking({ ... })

// Auth endpoints (Note: only used to fetch a resource key)
timekit.auth({ ... })

// Credential endpoints (Note: only used to manage resource keys)
timekit.getCredentials()
timekit.createCredential({ ... })
timekit.deleteCredential({ id })

Request example:

// Using promises
timekit.createBooking({
  resource_id: 'd187d6e0-d6cb-409a-ae60-45a8fd0ec879',
  graph: 'confirm_decline',
  start: '1955-11-12T21:30:00-07:00',
  end: '1955-11-12T22:15:00-07:00',
  what: 'Catch the lightning',
  where: 'Courthouse, Hill Valley, CA 95420, USA',
  description: 'The lightning strikes at 10:04 PM exactly! I need you to be there Doc!',
  customer: {
    name: 'Marty McFly',
    email: '[email protected]',
    phone: '(916) 555-4385',
    voip: 'McFly',
    timezone: 'America/Los_Angeles'
  }
}).then(function(response){
  console.log(response);
}).catch(function(response){
  console.log(response);
});

// Using async/await
const response = await timekit.createBooking({ ... })

Response example:

{
  // data is the response that was provided by the server
  data: {},
  // status is the HTTP status code from the server response
  status: 200,
  // statusText is the HTTP status message from the server response
  statusText: 'OK',
  // headers the headers that the server responded with
  headers: {},
  // config is the config that was provided to `axios` for the request
  config: {}
}

Usage (low-level API)

If you, for some reason, would like direct access to axios's request API, you can call the timekit.makeRequest() method directly. We'll still set the correct config headers, base url and includes, but otherwise it supports all the settings that axios does.

Example:

timekit.makeRequest({
  url: '/bookings',
  method: 'post',
  data: {
    key: 'value'
  },
  timeout: 1000
}).then(function(response){
  console.log(response);
}).catch(function(response){
  console.log(response);
});

Usage (carry)

If you want to inject specific params/query string or data into the next API request, you can use the carry method. It's handy for e.g. filtering result (search) or adding pagination (limit).

Example:

timekit
  .carry({
    params: {
      search: 'graph:confirm_decline',
      limit: 10
    }
  })
  .getBookings()
  .then(function(response) {
    // Response is filtered by the search query and limited to only 10 items
  });

Usage (dynamic includes)

The Timekit API have support for dynamically including related models (aka. expand objects). We supports this functionality by providing a chainable/fluent method called .include() that can be called right before a request.

The method takes unlimited string arguments, with each one being a model that you want included in the response. For nested data (e.g. events grouped by calendar), use the dot notation to dig into relations, like calender.events.

Example:

timekit
  .include('calendars.events', 'users')
  .getUserInfo()
  .then(function(response) {
    // Response contains JSON data with nested info on the user's calendars, events and meetings
  });

This is super powerful because it means that you can avoid unnecessary extra requests compared to fetching each resource sequentially.

Building from source

We use webpack for packaging the library as a module. To build the source files in /src to /dist, run:

# install dev dependencies
npm install
# build plain
webpack
# build minified
webpack --config webpack.config.min.js

Running tests

We use jasmine + karma for unit testing, which works together with webpack.

To run the test suite, simply do:

# install dev dependencies
npm install
# install karma as global
npm install -g karma
# start karma and run
karma start

Roadmap/todos

See Issues for feature requests, bugs etc.